leetcode
leetcode 1851 ~ 1900
链表最大孪生和

链表最大孪生和

难度:

标签:

题目描述

在一个大小为 n 且 n 为 偶数 的链表中,对于 0 <= i <= (n / 2) - 1 的 i ,第 i 个节点(下标从 0 开始)的孪生节点为第 (n-1-i) 个节点 。

  • 比方说,n = 4 那么节点 0 是节点 3 的孪生节点,节点 1 是节点 2 的孪生节点。这是长度为 n = 4 的链表中所有的孪生节点。

孪生和 定义为一个节点和它孪生节点两者值之和。

给你一个长度为偶数的链表的头节点 head ,请你返回链表的 最大孪生和 。

 

示例 1:

输入:head = [5,4,2,1]
输出:6
解释:
节点 0 和节点 1 分别是节点 3 和 2 的孪生节点。孪生和都为 6 。
链表中没有其他孪生节点。
所以,链表的最大孪生和是 6 。

示例 2:

输入:head = [4,2,2,3]
输出:7
解释:
链表中的孪生节点为:
- 节点 0 是节点 3 的孪生节点,孪生和为 4 + 3 = 7 。
- 节点 1 是节点 2 的孪生节点,孪生和为 2 + 2 = 4 。
所以,最大孪生和为 max(7, 4) = 7 。

示例 3:

输入:head = [1,100000]
输出:100001
解释:
链表中只有一对孪生节点,孪生和为 1 + 100000 = 100001 。

 

提示:

  • 链表的节点数目是 [2, 105] 中的 偶数 。
  • 1 <= Node.val <= 105

代码结果

运行时间: 808 ms, 内存: 46.4 MB


/*
 * 题目思路:
 * 1. 使用流收集链表节点值到列表。
 * 2. 计算并找出最大的孪生和。
 */

import java.util.*;
import java.util.stream.Collectors;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class Solution {
    public int pairSum(ListNode head) {
        // 使用流收集链表节点值
        List<Integer> list = new ArrayList<>();
        ListNode current = head;
        while (current != null) {
            list.add(current.val);
            current = current.next;
        }
        int n = list.size();
        // 计算最大孪生和
        return IntStream.range(0, n / 2)
                .map(i -> list.get(i) + list.get(n - 1 - i))
                .max()
                .orElse(0);
    }
}

解释

方法:

此题解通过使用快慢指针来找到链表的中点,然后将链表一分为二。接着,反转链表的后半部分,以便使得前半部分和反转后的后半部分的节点可以直接相加得到孪生和。通过遍历这两个部分的链表,计算所有可能的孪生和,并记录其中的最大值。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么选择使用快慢指针来找到链表的中点?有没有其他方法可以找到链表的中点?
快慢指针方法是一种高效且简洁的方式来找到链表的中点。通过设置两个指针,一个每次移动一步(慢指针),另一个每次移动两步(快指针),当快指针到达链表的末尾时,慢指针正好在链表的中点。这种方法的优点是只需遍历链表一次,空间复杂度为 O(1)。除此之外,另一种方法是先遍历整个链表以确定链表的长度,然后再次遍历到链表长度的一半位置来找到中点,但这种方法需要遍历链表两次。
🦆
在反转链表的后半部分时,有没有考虑到链表的节点数目只有两个的情况?这样的情况下代码的行为是怎样的?
代码中已经考虑了链表节点数目只有两个的情况。当链表只有两个节点时,快慢指针会使得慢指针停在第一个节点上,将链表分割为一个节点和另一个节点。反转后半部分(只有一个节点的链表)时,反转操作实际上不会改变链表,因为单节点链表反转后仍是自己。因此,这种情况下代码依然可以正确计算出孪生和为这两个节点的值之和。
🦆
反转链表后,原链表的结构改变了。是否有方法在不改变原链表结构的情况下解决这个问题?
可以在不改变原链表结构的情况下解决这个问题。一种方法是使用栈。首先,遍历链表的前半部分并将其值推入栈中。然后遍历后半部分的链表,并在每次迭代中从栈中弹出一个元素,将其与当前节点的值相加以计算孪生和。这种方法的空间复杂度较高,为 O(n/2),但可以保持原链表的结构不变。
🦆
在计算孪生和的过程中,你使用了两个指针p1和p2分别遍历前半部分和反转后的后半部分。这种方法是否保证了所有情况下都能正确计算出孪生和,尤其是在链表长度很大的情况下?
这种方法可以保证在所有情况下都正确计算出孪生和,包括当链表长度很大时。通过反转后半部分的链表,确保了两个指针 p1 和 p2 在遍历时,对应的节点是孪生节点。每次迭代中,两个指针都会向前移动一步,直到其中一个或两个都到达各自的终点。这确保了每一对孪生节点都被准确地计算了孪生和一次,因此这种方法在链表长度大时依然有效。

相关问题