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

LeetCode 4099: Minimum Operations to Sort With Locked Indices

·2 分鐘· ·
LeetCode Medium Array Merge-Sort Greedy
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2026-11-02

  • 提交紀錄:Accepted ×2

解題思路
#

兩部分分開算:

1. 交換次數:只能交換相鄰元素時,排好序最少要的交換次數就是逆序數,只要需要的位置都解鎖了就做得到。逆序數用 merge sort 算(Merge Sort),O(n log n)。

2. 一定要解鎖的位置:位置 i 上鎖時,任何元素都不能跨過它。nums[i] 的值大於 i + 1 代表它要往右移到 nums[i] - 1,路上 i 到 nums[i] - 1 這段都必須解鎖。所以掃一遍,維護目前最遠要解鎖到哪裡 reach,上鎖而且在 reach 範圍內的位置就要解鎖。

往左移的元素不用另外處理:位置 i 上的值如果小於 i + 1,前 i + 1 個位置裡一定有某個值大於 i,它要往右跨過 i,已經被算到了。

必須解鎖的數量超過 k 就回傳 -1;否則答案是解鎖數加逆序數。

我的嘗試
#

兩次都一次通過。第一版的 merge sort 是包含右端點的寫法,另外複製陣列;第二版改成半開區間、直接在 nums 上排序,和 LC 493 用的模板一樣。

正確解法
#

class Solution:
    def minOperations(self, nums: List[int], locked: List[int], k: int) -> int:
        unlocks = 0
        reach = -1
        for i, num in enumerate(nums):
            if num > i + 1:
                reach = max(reach, num - 1)
            if locked[i] and i <= reach:
                unlocks += 1
        if unlocks > k:
            return -1

        temp = [0] * len(nums)

        def sort_count(lo, hi):
            if hi - lo <= 1:
                return 0
            mid = (lo + hi) // 2
            count = sort_count(lo, mid) + sort_count(mid, hi)
            i, j, t = lo, mid, lo
            while i < mid or j < hi:
                if j >= hi or (i < mid and nums[i] <= nums[j]):
                    temp[t] = nums[i]
                    i += 1
                else:
                    temp[t] = nums[j]
                    count += mid - i
                    j += 1
                t += 1
            nums[lo:hi] = temp[lo:hi]
            return count

        return unlocks + sort_count(0, len(nums))

複雜度
#

時間 O(n log n),空間 O(n)。n 只到 2000,O(n^2) 直接數逆序數也會過,但題目要求 O(n log n)。

要特別避免的錯誤
#

  • 解鎖數要先算,因為 merge sort 會把 nums 排好序。
  • 位置 i 自己的值要往右移時,i 本身也要解鎖(範圍包含 i)。
  • 交換和解鎖都算操作次數,兩個要相加。

面試口說整理
#

相鄰交換的最少次數是逆序數,我用 merge sort 在 O(n log n) 算。另外,有元素要跨過的上鎖位置一定要解鎖:掃一遍,值大於 i + 1 的元素要往右移到 num - 1,維護最遠要解鎖到哪,在範圍內的上鎖位置都要解。往左移的元素一定伴隨某個往右跨的元素,所以不用另外算。解鎖數超過 k 回傳 -1,否則答案是解鎖數加逆序數。

相關文章

LeetCode 1989: Maximum Number of People That Can Be Caught in Tag
·1 分鐘
LeetCode Medium Two-Pointers Greedy Array
LeetCode 1989 解題筆記:鬼從左到右,每個鬼抓範圍內最左邊、還沒被抓的人;用一個只往右走的指針指向下一個候選人
LeetCode 948: Bag of Tokens
·1 分鐘
LeetCode Medium Two-Pointers Greedy Sorting Array
LeetCode 948 解題筆記:排序後,用最小的 token 換分數、用最大的 token 換能量;只有分數 > 0 才能換能量,換不了就停
LeetCode 3413: Maximum Coins From K Consecutive Bags
·2 分鐘
LeetCode Medium Sliding-Window Greedy Sorting Prefix-Sum Binary-Search Array
LeetCode 3413 解題筆記:最佳的 k 個袋子,一定有一端對齊某段的端點;分別算「左端對齊段的起點」和「右端對齊段的終點」(鏡像後重用同一個函式)
LeetCode 3796: Find Maximum Value in a Constrained Sequence
·1 分鐘
LeetCode Medium Greedy Array
LeetCode 3796 解題筆記:每個位置的上界是自己的限制、左邊上界 + 差值、右邊上界 + 差值三者取最小;左右各掃一次
LeetCode 3638: Maximum Balanced Shipments
·1 分鐘
LeetCode Medium Dynamic-Programming Greedy Monotonic-Stack Array
LeetCode 3638 解題筆記:貪心,一段一旦出現比這段最大值小的數就馬上切;因為切之前的那段是非遞減的,最大值就是前一個數
LeetCode 3627: Maximum Median Sum of Subsequences of Size 3
·1 分鐘
LeetCode Medium Math Greedy Sorting Game-Theory Array
LeetCode 3627 解題筆記:排序後每次拿最大的兩個和最小的一個,中位數是第二大的;答案是從尾端往前每隔一個取,共 n / 3 個