LeetCode 1497. 检查数组对是否可以被 k 整除
好的!我们来详细分析 LeetCode 1497. 检查数组对是否可以被 k 整除 这道题的解法和思路。
题目: https://leetcode.cn/problems/check-if-array-pairs-are-divisible-by-k/description/
题目分析
问题描述:
给定一个整数数组 arr
和一个整数 k
,判断数组中的元素是否可以分成若干对,使得每对元素的和都能被 k
整除。
示例:
输入:arr = [1, 2, 3, 4, 5, 10, 6, 7, 8, 9]
, k = 5
输出:true
解释:可以分成如下五对:(1, 9)
, (2, 8)
, (3, 7)
, (4, 6)
, (5, 10)
,每对的和都是 10,能被 5 整除。
核心思路
- 余数分解:将每个元素
num
对k
取余,得到余数r = num % k
。 - 互补余数:对于每个余数
r
,其互补余数为(k - r) % k
。 - 哈希表统计:使用哈希表统计每个余数的出现次数,检查余数
r
和互补余数(k - r) % k
的次数是否匹配。
解法步骤
- 预处理余数:遍历数组,计算每个元素的余数
r
,并将余数r
的计数加 1。 - 检查余数对:
- 余数 0:出现次数必须为偶数,否则无法配对。
- 其他余数:余数
r
的次数必须等于互补余数(k - r) % k
的次数。
代码实现
class Solution {
public:bool canArrange(vector<int>& arr, int k) {vector<int> remainderCount(k, 0);// 统计每个余数的出现次数for (int num : arr) {int r = (num % k + k) % k; // 处理负数余数,确保结果在 [0, k-1] 范围内remainderCount[r]++;}// 检查余数0的次数是否为偶数if (remainderCount[0] % 2 != 0) {return false;}// 检查其他余数 i 和 k-i 的次数是否匹配for (int i = 1; i <= k/2; i++) {if (i == k - i) { // 当 k 为偶数且 i 是 k/2 时if (remainderCount[i] % 2 != 0) {return false;}} else {if (remainderCount[i] != remainderCount[k - i]) {return false;}}}return true;}
};
详细解释
-
余数预处理:
- 使用
(num % k + k) % k
确保负数余数正确转换为正数(例如,-3 % 5
转换为2
)。
- 使用
-
余数 0 的处理:
- 余数为 0 的元素必须两两配对,因此其出现次数必须为偶数。
-
互补余数的处理:
- 对于每个余数
i
(1 ≤ i ≤ k/2),其互补余数为k - i
。 - 当
k
为偶数且i = k/2
时,余数i
必须自身配对,因此其出现次数必须为偶数。
- 对于每个余数
示例验证
输入:arr = [1, 2, 3, 4]
, k = 5
步骤如下:
-
计算余数:
1 % 5 = 1
,2 % 5 = 2
,3 % 5 = 3
,4 % 5 = 4
。- 余数计数:
remainderCount = [0, 1, 1, 1, 1]
。
-
检查余数对:
- 余数 0:次数为 0,符合条件。
- 余数 1 和 4:次数均为 1,匹配。
- 余数 2 和 3:次数均为 1,匹配。
输出:true
(可以配对为 (1, 4)
和 (2, 3)
)。
复杂度分析
- 时间复杂度:O(n + k),其中 n 是数组长度,k 是给定的除数。
- 空间复杂度:O(k),主要用于存储余数的计数。
总结
通过余数分解和互补余数的配对检查,我们可以高效地判断数组是否能被分成若干对,使得每对的和都能被 k 整除。这种方法利用了模运算的性质,将问题转化为余数的匹配问题,时间复杂度为线性级。
这行代码检查的是当 k
为偶数且 i
恰好是 k/2
时,余数为 i
的元素数量必须是偶数。这是因为当 i = k/2
时,其互补余数仍然是 i
自身,因此这些元素必须两两配对。
补充:详细解释条件判断
- 代码:
if (i == k - i) // 当 k 为偶数且 i 是 k/2 时
当 k
为偶数时,存在一个特殊的余数 i = k/2
(例如,当 k=4
时,i=2
)。此时:
-
余数
i
的互补性:
余数i
的互补余数是(k - i) % k
。当i = k/2
时,k - i = k/2
,因此互补余数仍然是i
。- 示例:若
k=4
,余数2
的互补余数是4-2=2
。
- 示例:若
-
配对规则:
余数为i
的元素只能与同样余数为i
的元素配对。因此,余数为i
的元素数量必须是偶数,否则无法完全配对。- 示例:若余数
2
出现了 3 次(奇数),则必然有一个元素无法配对,导致无法满足条件。
- 示例:若余数
代码逻辑验证
在代码中,当 i == k - i
时(即 i
是 k/2
),检查 remainderCount[i]
是否为偶数:
if (i == k - i) { // 当 k 为偶数且 i 是 k/2 时if (remainderCount[i] % 2 != 0) { // 若余数为 i 的元素数量为奇数return false; // 无法两两配对,返回 false}
}
示例验证
假设 k=4
,数组为 [2, 2, 2, 6]
,余数统计为:
- 余数
2
出现了 3 次(元素 2, 2, 6)。 - 互补余数检查时,
i=2
的互补余数仍为2
,但3 % 2 != 0
,因此无法配对,返回false
。
总结
当 k
为偶数时,余数 k/2
的元素必须两两配对,因此其数量必须为偶数。这是代码中检查 remainderCount[i] % 2 != 0
的核心原因。