给出一个单向链表,第i 个node 和 第(n-1-i)个node称为twin.
0 <= i <= n/2 - 1
求所有twin的最大和。
链表长度为偶数。
思路:
链表长度为偶数,就省了不少步骤,不用再考虑奇数时中间那个node单独计算了。
直觉上来看,应该是先走到链表的中间位置,然后从中间到两边两两值求和,取最大的。
后半部分往结尾走还比较简单,那如何从中间往head处走呢?
或许会想到用一个数组保存链表所有的值,然后用数组下标访问元素。
那么就需要先遍历一遍链表,再额外需要一个长度为n的数组,这里不用这种方法。
再说如何让指针从中间往head处走。
因为是单向链表,没有回头指针,肯定是行不通的。
但是,可以把前半部分逆序。
逆序了,就可以正常地从head走到中间。
怎么确定只逆序前半部分,何时停止?
以前都是用快慢指针来确定链表一半的位置,这里不需要慢指针,只需要快指针,
只要快指针到了终点,就停止逆序过程。
来模拟一下这个过程,用Example1的数据。
先不考虑只逆序一半,先看看如何实现逆序排列。
申请一个新指针newHead, 方便操作。
newHead -> 5 -> 4 -> 2 -> 1
用head指针指向当前node, post指针指向下一node,
那么这时候head指向5,post指向4,
把post换到newHead后面,就变成
newHead -> 4 -> 5 -> 2 -> 1
这时post还是指向4,head指向5,把post指向head.next, 也就是2,
再把post换到newHead后面,变成
newHead -> 2 -> 4 -> 5 -> 1
head还是指向5,再把post指向head.next, 也就是1
把post换到newHead后面,变成
newHead -> 1 -> 2 -> 4 -> 5
这样就实现了逆序排列,只需要在快指针变成null时停止,就实现了只对前半部分逆序。
你说中间交换指针会不会影响快指针的位置?
不会,因为交换4到newHead后面时,快指针已经走到2了,交换的位置追不上快指针的位置。
快指针变成null时,链表变成
newHead -> 4 -> 5 -> 2 -> 1
这时head指向5,post指向4,
现在把post指向head.next, 也就是2,
把head移动到newHead.next, 也就是开头的4,
现在每次head和post都向后移动一步,直到post为null,
找到head.val + post.val的最大值即可。
public int pairSum(ListNode head) {
ListNode newHead = new ListNode();
newHead.next = head;
ListNode fast = head;
ListNode post = head.next;
int res = 0;
//链表前半部分逆序排列
while(fast != null && fast.next != null) {
fast = fast.next.next;
if(fast == null) break;
//swap post node to newHead.next
head.next = post.next;
post.next = newHead.next;
newHead.next = post;
post = head.next;
}
head = newHead.next;
while(post != null) {
res = Math.max(res, post.val + head.val);
head = head.next;
post = post.next;
}
return res;
}