# LeetCode 日記 #010: 1679. Max Number of K-Sum Pairs|HashTable|Counter|Greedy
> You are given an integer array nums and an integer k.
>
> In one operation, you can pick two numbers from the array whose sum equals k and remove them from the array.
>
> Return the maximum number of operations you can perform on the array.
- **Example 1:**
Input: nums = [1,2,3,4], k = 5
Output: 2
- **Example 2:**
Input: nums = [3,1,3,4,3], k = 6
Output: 1
## 思路
題目說的是要找出陣列中,兩值的和會等於 k 的元素,最後計算出有幾對並返回。
1. 重點在於**查找方式**,因為可以用迭代方式判斷是否包含 k - num 的數字,所以關鍵在於快速查找 (k - num)。
>而提到快速查找通常最先想到會是 HashTable -> O(1)
2. 第二個重點是不能重複計算元素,被計算過的就要被移除,但首先陣列不能移除元素,而列表移除會改變長度,所以應該要用 counter 來計算 (?)
> 用 HashTable 作為 counter,先計算每個值出現的次數,每當有組合達成條件就扣除出現的次數,直到沒有辦法達成條件為止。
3. 計算組合次數,每當有一個組合達成條件時,除了扣除 counter 裡的次數,也要累計組合的次數。
4. 需要注意的 Edge Case 是當兩個元素的值相同時,需要確保在 counter 裡的次數是至少等於 2。
## Code
時間跟空間複雜度都是 O(n),時間的增長量主要在迭代次數,空間是每次迭代要存入的 complement 變數。
```java
class Solution {
public int maxOperations(int[] nums, int k) {
Map<Integer, Integer> map = getCountMap(nums);
int count = 0;
for (int num : nums) {
if (map.getOrDefault(num, 0) > 0) {
int complement = k - num;
if (isMatch(map, num, complement)) {
map.put(num, map.get(num) - 1);
map.put(complement, map.get(complement) - 1);
count++;
}
}
}
return count;
}
private boolean isMatch(Map<Integer, Integer> map, int num, int complement) {
return num != complement && map.getOrDefault(complement, 0) > 0 ||
num == complement && map.getOrDefault(complement, 0) > 1;
}
private Map<Integer, Integer> getCountMap(int[] nums) {
return Arrays.stream(nums)
.boxed()
.collect(Collectors.toMap(
num -> num,
num -> 1,
(existing, replacement) -> existing + 1
));
}
}
```
## Takeaway
- 用 Map 作為 Counter 計算值出現的次數。重複的 key 會合併,用 getOrDefault 來計算的方法很巧妙。
- 用 HashTable 查找的複雜度是 O(1)。
- Stream 的練習。
- 配對問題模式:這類尋找配對元素的問題很常見,掌握這種模式有助於快速識別和解決類似問題。
- 模擬操作與實際操作:有時候不需要實際修改數據結構(如移除元素),而是可通過模擬操作(如減少計數)來達到同樣的效果,這通常更高效。