[Leetcode解題] 2009. Minimum Number of Operations to Make Array Continuous - 使用 Binary Search 算法
9 March 2024
hard
binary-search
bs
題目
2009. Minimum Number of Operations to Make Array Continuous 給定一個整數陣列 nums。在一次操作中,你可以將 nums 中的任何元素替換為任何整數。 如果滿足以下兩個條件,則 nums 被認為是連續的:
nums 中的所有元素都是唯一的。 nums 中的最大元素與最小元素之間的差等於 nums.length - 1。 例如,nums = [4, 2, 5, 3] 是連續的,但 nums = [1, 22, 22, 24, 24] 不是連續的。
返回使 nums 變得連續所需的最小操作次數。
解題思路
我們的目標是使得陣列連續,也就是要求最大元素與最小元素之間的差為 nums.length - 1,同時保持所有元素唯一。因此,我們可以通過以下步驟來解決這個問題:
- 將 nums 進行排序,這樣最大元素與最小元素就位於陣列的兩端了。
- 對於每個可能的連續子陣列,找到最大元素的索引。這可以通過Binary Search來實現。
- 子陣列中需要替換的重複元素的數量。這可以通過一個輔助陣列(PreSum的概念)來計算重複元素的個數。
- 對於每個連續子陣列,計算需要替換的操作次數,並保留最小值。
Python 實作
class Solution:
def minOperations(self, nums: List[int]) -> int:
n = len(nums)
nums.sort()
minOps = float('inf')
duplicate = [0] * n
d = 0
for i in range(1, n):
if nums[i] == nums[i - 1]:
d += 1
duplicate[i] = d
for i in range(n):
interval_max = nums[i] + n - 1
interval_max_idx = bisect_right(nums, interval_max) - 1
duplicate_num = duplicate[interval_max_idx] - duplicate[i]
minOps = min(minOps, duplicate_num + n - (interval_max_idx - i + 1))
return minOps
C++ 實作
class Solution {
public:
int minOperations(vector<int>& nums) {
int n = nums.size();
vector<int> duplicate(n, 0);
int minOps = INT_MAX;
sort(nums.begin(), nums.end());
int d = 0;
for(int i=1; i<n; i++){
if(nums[i] == nums[i-1]) ++d;
duplicate[i] = d;
}
for(int i=0; i<n; i++){
int interval_max = nums[i]+n-1;
int interval_max_idx = upper_bound(nums.begin(), nums.end(), interval_max) - nums.begin() -1;
int duplicate_num = duplicate[interval_max_idx]- duplicate[i];
minOps = min(minOps, duplicate_num + n - (interval_max_idx-i+1));
}
return minOps;
}
};
時間複雜度
排序的時間複雜度為 $O(n log n)$,其中 $n$ 是陣列的長度,對於每個連續子陣列,進行Binary Search的時間複雜度為 $O(log n)$。總體時間複雜度為 $O(n log n)$。