刷爆力扣之检查数组对是否可以被 k 整除
HELLO,各位看官大大好啊,我是阿呆 🙈🙈🙈
今天开始阿呆将会记录下力扣刷题过程,收录在专栏算法中 😜😜😜
该专栏按照不同类别标签进行刷题,每个标签又分为 Easy、Medium、Hard 三个等级 🥳🥳🥳
本部分所有题目均来自于LeetCode 网,并于每道题目下标明具体力扣网原题链接 🏃🏃🏃
OK,兄弟们,废话不多直接上题,冲冲冲 🌞🌞🌞
一 🏠 题目描述
1497. 检查数组对是否可以被 k 整除
给你一个整数数组 arr 和一个整数 k ,其中数组长度是偶数,值为 n
现在需要把数组恰好分成 n / 2 对,以使每对数字的和都能够被 k 整除
如果存在这样的分法,请返回 True ;否则,返回 False
示例 1:
输入:arr = [1,2,3,4,5,10,6,7,8,9], k =5输出:true 解释:划分后的数字对为 (1,9),(2,8),(3,7),(4,6) 以及 (5,10)
示例 2:
输入:arr = [1,2,3,4,5,6], k =7输出:true 解释:划分后的数字对为 (1,6),(2,5) 以及 (3,4)
示例 3:
输入:arr = [1,2,3,4,5,6], k =10输出:false 解释:无法在将数组中的数字分为三对的同时满足每对数字和能够被 10 整除的条件
提示:
arr.length == n 1 <= n <=105n 为偶数 -109 <= arr[i] <=1091 <= k <=10
二 🏠破题思路
2.1 🚀 关键信息
解决问题第一步,当然先提取题目字面上的关键信息 😎😎😎
把数组恰好分成 n / 2 对 = 即把数组中的元素两两一对进行分组
每对数字和能被 k 整除 = 每组的元素之 sum 对 k 取模结果都为 0 (sum % k = 0)
提取完题目中的关键信息后,直接进入第二阶段,思路整理 😃😃😃
2.2 🚀 思路整理
如果两个数之和能被 k 整除,那这两个数对 k 取模的结果之和也能被 k 整除,这是这道算法题的核心点
那么对于任意的一个数,对 k 取模后记为 Xk,分为以下两种情况
1、若 Xk1 = 0,需找到另一个满足 Xk2 = 0 的数进行配对
2、若 Xk1 > 0,需找到另一个满足 Xk1 + Xk2 = k 的数进行配对
于是可以很容易联想到使用哈希表记录取模结果。对于哈希表的 KEY 表示一个数的余数,VAL 表示这个余数出现的次数。统计完成后,将所有条目进行配对,确保如下两条
1、哈希映射中键 0 对应的值为偶数,对应如上第一种情况
2、哈希映射中键 t (t>0) 和键 k - t 对应的值相等,对应如上第二种情况
小细节
在 C++ 中,将负数 x 对一个正数 k 进行取模操作,得到的结果小于等于 0,即在 [−k+1,0] 范围内 。我们可以通过:xk = (x % k + k) % k ,得到在 [0, k-1] 的范围内的余数 👀👀👀
由于哈希映射中的键的范围为 [0, k-1],因此我们可以使用一个长度为 k 的数组代替哈希表,降低编码难度
整理完解题思路后,直接进入第三阶段,代码实现 😃😃😃
三 🏠 代码详解
3.1 🚀 代码实现
按照我们刚才的破题思路,直接代码走起来 👇👇👇👇
bool canArrange(std::vector<int>& arr, int k) { std::vector<int> mod(k); //定义取模数组代替哈希表 ,对应小细节 ② for (int num: arr) { //遍历输入数组 arr ++mod[(num % k + k) % k]; //对输入数组元素进行取模操作,并对其进行计数 } for (int i =1; i + i < k; ++i) { //遍历取模数组 if (mod[i] != mod[k - i]) return false; //若不满足第二种配对情况直接 return } return mod[0] % 2==0; //校验是否满足第一种配对情况 }
++mod[(num % k + k) % k]; //对输入数组元素进行取模操作,并对其进行计数
3.2 🚀 细节解析
看完 👀👀👀 全注释版的代码实现后,相信看官大大对整体逻辑已经是大写的 OK 了 😃😃😃
那么我们挖掘上述实现的晦涩细节 😖😖😖 进行解析,直接开干,走起来 👇👇👇👇
++mod[(num % k + k) % k]; //对输入数组元素进行取模操作,并对其进行计数
首先是 (num % k + k) % k ,它对应着小细节 ①,我们这里举出一个例子解释, 例 x = - 1, k = 5
注:以下 y,z 范围为 ( - k,k ),参考 2.2 思路整理
如果满足 (x + y) % k = 0,易得 y = 1
那么 1 对应的正整数满足表达式(1 + z ) % = 0 ,易得 z = 4
因此我们可以得对于数字 y = 1 , x = - 1 和 z = 4 对于(x + y) % k = 0 表达式完全等效
其次是 ++mod[N],这实际就是利用了数组下标作为哈希表的 KEY ,索引值作为哈希表 VAL 在计数而言
i + i < k //遍历取模数组
遍历取模数组的循环条件是否可以写成 i < k ?
当然可以,但是实际上这仅需遍历一半足矣,因为是在拿元素值进行配对比较嘛,这样的效率高 😜😜😜
遍历取模数组的循环条件是否可以写成 i < k / 2 ?
不可以,因为 i 为整型 i + i < k 和 i < k / 2 并不等效,例如 i = 1,k = 3 ,前者表表达式结果为 TRUE ,后者表达式结果为 FALSE 😖😖😖
四 🏠 心路历程
为方便各位看官大大了解博主真实刷题过程,我把当时状态纯纯真实还原,记录在心路历程这一小节,不感兴趣的小伙伴可以直接跳过哈
博主在第一阶段提取 🚀 关键信息并没有问题,在第二阶段 🚀 思路整理中只想到了对任意元素,对 k 取模后可以简化配对过程,但是并没有联想到两种配对情况 😭😭😭 (破题关键点)
所以博主的这道题也是在阅读完官方解析后,解出来并加以记录的