Description

在一個長度為偶數 n 的鏈結串列中,第 i 個節點的 twin 是第 n-1-i 個節點。twin sum 是一對 twin 節點值的和。回傳最大的 twin sum。

Example:

Input: head = [5,4,2,1] Output: 6(5+1=6, 4+2=6)

Intuition#

核心思路:找到中點後反轉前半段(或後半段),然後同步遍歷計算 twin sum 的最大值。

  • Twin 的配對方式是首尾對稱(第 0 個配第 n-1 個)
  • 可以用 Stack 儲存前半段,遍歷後半段時逐一配對
  • 最佳做法:快慢指針找中點 + 反轉前半段,O(1) 空間

Approaches#

1: Stack#

  • 概念: 用快慢指針找到中點,將前半段壓入 Stack,再遍歷後半段同時彈出 Stack 計算配對和
  • 時間複雜度: O(n)
  • 空間複雜度: O(n/2) = O(n)
class Solution {
    fun pairSum(head: ListNode?): Int {
        val stack = ArrayDeque<Int>()
        var slow = head
        var fast = head
        while (fast?.next != null) {
            stack.addLast(slow!!.`val`)
            slow = slow.next
            fast = fast.next?.next
        }
        var maxSum = 0
        var curr = slow
        while (curr != null) {
            maxSum = maxOf(maxSum, curr.`val` + stack.removeLast())
            curr = curr.next
        }
        return maxSum
    }
}

⭐2: Reverse First Half#

  • 概念: 快慢指針找中點的同時反轉前半段,然後從中點和反轉後的前半段頭同步遍歷
  • 時間複雜度: O(n)
  • 空間複雜度: O(1)
class Solution {
    fun pairSum(head: ListNode?): Int {
        var slow = head
        var fast = head
        var prev: ListNode? = null

        // 快慢指針找中點,同時反轉前半段
        while (fast?.next != null) {
            fast = fast.next?.next
            val next = slow?.next
            slow?.next = prev
            prev = slow
            slow = next
        }

        // prev 是反轉後的前半段頭,slow 是後半段頭
        var maxSum = 0
        var left = prev
        var right = slow
        while (left != null && right != null) {
            maxSum = maxOf(maxSum, left.`val` + right.`val`)
            left = left.next
            right = right.next
        }
        return maxSum
    }
}

🔑 Takeaways#

  • Pattern: 鏈結串列的對稱配對問題,核心是找中點 + 反轉其中一半
  • 關鍵技巧: 可以在快慢指針移動的同時反轉前半段,一次遍歷完成兩件事