CPP取余/取模运算用途整理

取模运算与除法运算区别

除法和取余(模运算)在数学中是密切相关的运算。在整数除法中,比如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 为止。

循环索引示例

leetcode503.下一个最大元素Ⅱ

本题是环形数组,需要遍历两遍原来的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。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值