leetcode 2130. Maximum Twin Sum of a Linked List(链表的最大孪生和)-LMLPHP
给出一个单向链表,第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;
}

leetcode 2130. Maximum Twin Sum of a Linked List(链表的最大孪生和)-LMLPHP

05-17 21:06