取模运算与除法运算区别
除法和取余(模运算)在数学中是密切相关的运算。在整数除法中,比如5除以3,结果是1余2。这里的1是商,2是余数。
在C++等编程语言中,除法运算符(/)用来求商,模运算符(%)用来求余数。
所以,5 / 3 的结果是 1,5 % 3 的结果是 2。
取模重要用途:循环索引
在C++中,取余(或称为取模)操作有很多用途。大多数用途,是用于环形数组之中,通过取模%运算循环遍历数组!
由于取模运算的特性, i初始值=0,那么i%nums.size()
这个式子就是0--nums.size()-1
循环取值。
- 当i初始值=0时,i%a的范围就是[0,a-1]!
因为 “求模” 运算的定义是 “求余数”。例如,当 7 除以 3,结果是 2 余 1,所以 7%3 的结果是 1。余数总是会小于除数的,所以 i%a 的结果将始终在 0 到 a-1 的范围内。
当 i 小于 a 时,i%a 的结果就是 i 自己;当 i 等于 a 时,i%a 的结果就是 0;当 i 大于 a 时,i%a 的结果就是 i-a 的值,直到这个值小于 a 为止。
循环索引示例
本题是环形数组,需要遍历两遍原来的nums数组,才能得到环形数组每个元素的下一个最大元素。
遍历两遍的逻辑:
st.push(0);
for(int i=1;i<nums.size()*2;i++){
if(nums[i%nums.size()]<=nums[st.top()]){
st.push(i%nums.size());
}
else{
while(nums[i%nums.size()]>nums[st.top()]&&!st.empty()){
result[st.top()]=nums[i%nums.size()];
st.pop();
}
st.push(nums[i%nums.size()]);
}
}
完整版:(环形数组推荐写法)
- 重点在只用O(n)的时间复杂度和空间复杂度,完成遍历两遍数组
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
stack<int>st;
vector<int>result(nums.size(),-1);
st.push(0);
for(int i=1;i<nums.size()*2;i++){
if(nums[i%nums.size()]<=nums[st.top()]){
st.push(i%nums.size());
}
else{
while(!st.empty()&&nums[i%nums.size()]>nums[st.top()]){
result[st.top()]=nums[i%nums.size()];
st.pop();
}
st.push(i%nums.size());
}
}
return result;
}
};
判断奇偶性
可以通过将一个数对2取余,来判断它是奇数还是偶数。如果余数为0,则说明该数是偶数;如果余数为1,则说明该数是奇数。例如:
int num = 10;
if(num % 2 == 0) {
std::cout << "Even";
} else {
std::cout << "Odd";
}
获取个位数/消除最后一位
"/10"操作会将数字的最后一位(个位数)去掉。
int num = 1234;
std::cout << num / 10; // 输出 123
如果要获取一个数的个位数,可以使用"%10"操作,"%10"操作会得到数字的个位数。
int num = 1234;
std::cout << num % 10; // 输出 4
限制数值范围
有时,我们需要一个数值在某个范围内变动,例如在[0, n)之间,这时可以用取模运算。例如,生成一个小于n的随机数:
int n = 10;
int randNum = rand() % n; // randNum 将会是一个在 [0, n) 之间的整数
这种类型的应用例如 leetcode59.螺旋矩阵 题目链接
题目代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
//初始化二维n*n大小,初值全部是0的数组
vector<vector<int>> ans(n, vector<int>(n,0));
int t = 0; // 初始方向
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; // 四个x,y更改的方向
for (int i = 0, j = 0, k = 1; k <= n * n; ++k) {
//空的二维数组赋值
ans[i][j] = k;
//记录下个点的预估位置
int x = i + dx[t], y = j + dy[t];
// 判断下个点预估位置是否合理,不合理就通过t操作方向数组下标,从而修改方向
if (x < 0 || x >= n || y < 0 || y >= n || ans[x][y] != 0)
//t操作方向数组下标
t = (t + 1) % 4;
//x方向修改
i += dx[t];
//y方向修改
j += dy[t];
}
return ans;
}
};
本题博客整理:螺旋矩阵解法整理与技巧说明
求逆元
在一些算法,比如RSA加密算法中,会需要用到模逆元,这就需要用到模运算。例如,求a模p的逆元,需要满足 (a*a_inv) % p = 1。