↓快轉到主要內容
  1. LeetCode/

LeetCode 1040: Moving Stones Until Consecutive II

·1 分鐘· ·
LeetCode Medium Sliding-Window Math Sorting Array
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2026-01-18

  • 提交紀錄:Accepted(一次通過)

解題思路
#

先排序。每次只能移動端點石頭,而且移完它不能還是端點。

最多步數
#

最後石頭會連在一起,所以理想上每一步只填一個空位。第一步必須移動最左或最右的那顆:

  • 移最左邊的:stones[0] 和 stones[1] 之間的空位就再也用不到了。
  • 移最右邊的:同理,浪費 stones[-1] 和 stones[-2] 之間的空位。

之後每一步都可以只往內填一格。所以最多步數 = 總空位 − min(左邊空隙, 右邊空隙),總空位是 (stones[-1] - stones[0] + 1) - n。

最少步數
#

最後石頭佔一段長度 n 的連續位置。用滑動視窗找哪一段長度 n 的區間裡已經有最多石頭,其他的都要搬進來,n - count 步。

特例:如果視窗裡有 n - 1 顆石頭而且已經連續(剛好佔滿長度 n - 1),剩下一顆在遠處,例如 [1, 2, 3, 4, 10]。直接把 10 搬到 5 是不行的(搬過去還是端點),要 2 步:先搬 1 到 6,再搬 10 到 5。

我的解法
#

class Solution:
    def numMovesStonesII(self, stones: List[int]) -> List[int]:
        stones.sort()
        n = len(stones)

        total_gap = (stones[-1] - stones[0] + 1) - n
        max_moves = total_gap - min(stones[1] - stones[0] - 1, stones[-1] - stones[-2] - 1)

        min_moves = n
        left = 0
        for right in range(n):
            while stones[right] - stones[left] + 1 > n:
                left += 1                          # 視窗寬度不超過 n
            count = right - left + 1
            if count == n - 1 and stones[right] - stones[left] + 1 == n - 1:
                min_moves = min(min_moves, 2)      # n - 1 顆已連續,剩一顆在遠處
            else:
                min_moves = min(min_moves, n - count)
        return [min_moves, max_moves]

複雜度
#

時間 O(n log n),空間 O(1)(不算排序)。

要特別避免的錯誤
#

  • 最多步數沒扣掉第一步浪費的空隙。
  • 最少步數漏掉「n - 1 顆已連續」的特例。

面試口說整理
#

最多步數:第一步一定要移最左或最右的石頭,它旁邊的空隙就浪費了,之後每步只填一格,所以是總空位減掉比較小的那個邊緣空隙。最少步數:用長度 n 的滑動視窗找已經有最多石頭的區間,剩下的都要搬進來;但如果 n - 1 顆已經連續、剩一顆在遠處,要特判成 2 步。時間 O(n log n)。

相關文章

LeetCode 1838: Frequency of the Most Frequent Element
·1 分鐘
LeetCode Medium Sliding-Window Sorting Greedy Prefix-Sum Binary-Search Array
LeetCode 1838 解題筆記:排序後,把視窗裡的數都加到 nums[right] 的花費是 nums[right] × 長度 − 視窗總和;花費 > k 就縮左邊
LeetCode 2271: Maximum White Tiles Covered by a Carpet
·1 分鐘
LeetCode Medium Sliding-Window Greedy Sorting Prefix-Sum Binary-Search Array
LeetCode 2271 解題筆記:地毯的左端放在某段白磚的起點一定不會更差;排序後用雙指針,完整蓋住的段累加,最後一段只算部分
LeetCode 3634: Minimum Removals to Balance Array
·1 分鐘
LeetCode Medium Sliding-Window Sorting Binary-Search Array
LeetCode 3634 解題筆記:排序後留下來的一定是連續一段;對每個最小值 nums[left],用只往右走的指針找能留到哪裡,刪掉兩邊剩下的
LeetCode 3413: Maximum Coins From K Consecutive Bags
·2 分鐘
LeetCode Medium Sliding-Window Greedy Sorting Prefix-Sum Binary-Search Array
LeetCode 3413 解題筆記:最佳的 k 個袋子,一定有一端對齊某段的端點;分別算「左端對齊段的起點」和「右端對齊段的終點」(鏡像後重用同一個函式)
LeetCode 2779: Maximum Beauty of an Array After Applying Operation
·1 分鐘
LeetCode Medium Sliding-Window Sorting Binary-Search Array
LeetCode 2779 解題筆記:每個數可以變成 [x - k, x + k] 裡的任何值,一群數能變成同一個值 ⇔ 最大 - 最小 <= 2k;排序後找最長的這種視窗
LeetCode 3649: Number of Perfect Pairs
·1 分鐘
LeetCode Medium Two-Pointers Math Sorting Array
LeetCode 3649 解題筆記:把條件化簡成「較大的絕對值 <= 2 × 較小的絕對值」,排序絕對值後用雙指針計數