# 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 的練習。 - 配對問題模式:這類尋找配對元素的問題很常見,掌握這種模式有助於快速識別和解決類似問題。 - 模擬操作與實際操作:有時候不需要實際修改數據結構(如移除元素),而是可通過模擬操作(如減少計數)來達到同樣的效果,這通常更高效。