快轉到主要內容
  1. LeetCode/

LeetCode 1049: Last Stone Weight II

·2 分鐘· ·
LeetCode Medium Dynamic-Programming Knapsack Subset-Sum
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2026-08-19 來源:Day 45 learning note

學習脈絡
#

這篇是從 learning note 裡該 LeetCode 題目的段落重新整理出來的版本。我保留當天筆記中的修正點、比較點、容易犯錯的地方,並移除同一天其他非 LeetCode 主題,避免文章內容混題。

筆記中提到的相關提醒
#

  • explain LC 1049 as a partition problem, not a simulation problem

當天筆記摘錄
#

Problem 2 - LC 1049 Last Stone Weight II
#

  • Pattern: 0/1 subset partition with best-half approximation.

Why This Fits
#

If the stones are partitioned into two groups with sums:

A and B

then the final remaining weight is:

|A - B|

So the real goal is:

find a reachable subset sum as close as possible to total / 2

Core State / Invariant
#

dp[s] = whether some subset of processed stones can make sum s

Base Case
#

dp[0] = true

Reason:

choosing no stones makes sum 0

Transition
#

For each stone, iterate backward:

dp[s] |= dp[s - stone]

Final Answer
#

Find the largest reachable:

s <= total // 2

Then return:

total - 2 * s

Complexity
#

Time: O(len(stones) * target)
Space: O(target)

Common Mistakes
#

  • treating smash operations as simulation instead of partitioning
  • using forward iteration and reusing one stone
  • thinking maximize-value DP is required
  • forgetting the final scan for best reachable half

Strong Spoken Explanation
#

I reframe the smash process as partitioning stones into two groups. If the group sums are A and B, the final leftover is |A - B|, so I want the two sums as close as possible. That means I only need subset sums up to total // 2. I use boolean 0/1 DP where dp[s] tells me whether sum s is reachable from the processed stones. After filling the table, I scan downward from total // 2 for the largest reachable s and return total - 2 * s.

正確解法
#

上面的筆記保留了推理脈絡和當天需要修正的點。下面是我會提交的版本。

from typing import List

class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        total = sum(stones)
        target = total // 2
        dp = [False] * (target + 1)
        dp[0] = True

        for stone in stones:
            for s in range(target, stone - 1, -1):
                dp[s] = dp[s] or dp[s - stone]

        for s in range(target, -1, -1):
            if dp[s]:
                return total - 2 * s
        return 0

複雜度
#

Time O(n * total_sum), Space O(total_sum).

要特別避免的錯誤
#

  • Iterating forward accidentally reuses the same stone more than once.
  • Optimizing for exact half only; the best answer may be below half.

面試口說整理
#

先講清楚 state definition,再說 transition 為什麼維持這個 state。只要這題有 loop direction、狀態壓縮、或題型相似但 answer shape 不同的地方,就要主動講出來,因為那通常就是這類題最容易出錯的點。

相關文章

LeetCode 474: Ones and Zeroes
·3 分鐘
LeetCode Medium Dynamic-Programming Knapsack
LeetCode 474 解題筆記,依照原始 learning note 重新整理
LeetCode 931: Minimum Falling Path Sum
·3 分鐘
LeetCode Medium Dynamic-Programming Grid-Dp
LeetCode 931 解題筆記,依照原始 learning note 重新整理
LeetCode 1449: Form Largest Integer With Digits That Add Up To Target
·3 分鐘
LeetCode Hard Dynamic-Programming Knapsack
LeetCode 1449 解題筆記,依照原始 learning note 重新整理
LeetCode 879: Profitable Schemes
·3 分鐘
LeetCode Hard Dynamic-Programming Knapsack
LeetCode 879 解題筆記,依照原始 learning note 重新整理
LeetCode 97: Interleaving String
·3 分鐘
LeetCode Medium Dynamic-Programming String
LeetCode 97 解題筆記,依照原始 learning note 重新整理
LeetCode 1143: Longest Common Subsequence
·3 分鐘
LeetCode Medium Dynamic-Programming String
LeetCode 1143 解題筆記,依照原始 learning note 重新整理