刷爆力扣之检查数组对是否可以被 k 整除

简介: 刷爆力扣之检查数组对是否可以被 k 整除

刷爆力扣之检查数组对是否可以被 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 取模后可以简化配对过程,但是并没有联想到两种配对情况 😭😭😭 (破题关键点)


所以博主的这道题也是在阅读完官方解析后,解出来并加以记录的


相关文章
|
5天前
|
算法
【数组相关面试题】LeetCode试题
【数组相关面试题】LeetCode试题
|
5天前
|
存储
力扣面试经典题之数组/字符串
力扣面试经典题之数组/字符串
27 0
|
5天前
|
人工智能 BI
力扣561 数组拆分
力扣561 数组拆分
|
5天前
【Leetcode】两数之和,给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
【Leetcode】两数之和,给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
|
5天前
|
算法
leetcode代码记录(寻找两个正序数组的中位数
leetcode代码记录(寻找两个正序数组的中位数
13 2
|
5天前
|
索引
leetcode代码记录(最长重复子数组
leetcode代码记录(最长重复子数组
12 0
|
5天前
leetcode代码记录(两个数组的交集
leetcode代码记录(两个数组的交集
9 1
|
5天前
leetcode代码记录(最大子数组和
leetcode代码记录(最大子数组和
11 2
|
5天前
|
存储 算法
Leetcode 30天高效刷数据结构和算法 Day1 两数之和 —— 无序数组
给定一个无序整数数组和目标值,找出数组中和为目标值的两个数的下标。要求不重复且可按任意顺序返回。示例:输入nums = [2,7,11,15], target = 9,输出[0,1]。暴力解法时间复杂度O(n²),优化解法利用哈希表实现,时间复杂度O(n)。
22 0
|
5天前
|
索引
Leetcode 给定一个数组,给定一个数字。返回数组中可以相加得到指定数字的两个索引
Leetcode 给定一个数组,给定一个数字。返回数组中可以相加得到指定数字的两个索引