📘 題目敘述
給定一個整數陣列 nums 與一個整數 k。
你每次可以選擇 兩個數(必須是不同索引),且它們的總和剛好等於 k,然後把這兩個數從陣列中移除。
請回傳你最多可以做幾次這樣的操作(也就是最多能移除幾組「和為 k」的配對)。
條件限制
1 <= nums.length <= 10^51 <= nums[i] <= 10^91 <= k <= 10^9
🧠 解題思路
我的做法是:
- 先排序
nums(讓大小有順序) - 用兩個指標:
l指向最左邊(最小值)r指向最右邊(最大值)
- 每次看
nums[l] + nums[r]跟k的關係來決定怎麼移動指標:
- 如果剛好等於
k:找到一組配對,count++,然後l++、r-- - 如果大於
k:代表右邊太大,r-- - 如果小於
k:代表左邊太小,l++
另外我在一開始多做了一步:
- 因為
nums[i]都是正數,如果nums[r] > k,那它不可能跟任何正數加出k - 所以可以先把
r往左移到nums[r] <= k的位置,減少後續判斷範圍
所有變數
nums:輸入陣列(我會先排序)k:目標和l:左指標(從小的開始)r:右指標(從大的開始)count:目前找到的合法配對數量(答案)
🪜 主要流程步驟
1. 排序
- 排序後才能用「左右夾逼」快速判斷目前和是太大還太小
2. 先把不可能用到的右端排除(我的小優化)
- 當
nums[r] > k時: - 因為所有數都是正數,所以
nums[l] + nums[r] >= nums[r] > k - 代表
nums[r]不可能出現在任何合法配對中 - 所以我先做:
- 一直
r--直到nums[r] <= k(或r到最左邊)
3. 兩指標掃描找配對
只要 l < r,就重複:
- 情況一:
nums[l] + nums[r] == k- 找到一組配對,可以「移除」兩個數
count++,並且兩邊都往內縮:l++、r--
- 情況二:
nums[l] + nums[r] > k- 和太大,代表右邊數字太大
r--嘗試用更小的右邊數字
- 情況三:
nums[l] + nums[r] < k- 和太小,代表左邊數字太小
l++嘗試用更大的左邊數字
最後 count 就是最多可以取到的配對數量。
💻 程式碼實作
class Solution {
public:
int maxOperations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int l = 0, r = nums.size() - 1;
int count = 0;
while (nums[r] > k && r > 0) {
r--;
}
while (l < r) {
if (nums[l] + nums[r] == k) {
count++;
l++;
r--;
} else if (nums[l] + nums[r] > k) {
r--;
} else {
l++;
}
}
return count;
}
};