LeetCode刷题总结(九)29 - 31 -- 二进制倍增,位运算,滑动窗口

这篇博客总结了LeetCode的三道算法题,包括29题的二进制倍增法求两数相除,30题使用滑动窗口寻找所有单词子串,以及31题的下一个排列问题。文中详细讲解了如何利用位运算和负数计算优化解题,以及滑动窗口在解决特定问题时的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)LeetCode29:两数相除

暴力做法是循环 x -= y,x为被除数,y为除数,减到 x 小于 y 为止,每减一次计数变量 ++,最后输出计数变量。
然而以上这种做法显然是会超时的!!!
高级解法是二进制移位倍增,其实这也是计算机实现除法的本质。二进制倍增的意思就是暴力的做法让y一个一个地增太慢了,每次应该大一点地向x逼近,那么怎么确定这个大呢
我们可以,以y为基数,并定义一个数组,在小于x的情况,y倍增一倍后存入该数组,循环,直到该数大于x。这时我们每次在向x逼近的时候就可以从上面那个数组中最大的数向x逼近,逼近成功(逼近的数小于x),那么商就加上 2的该数在数组中索引的次方(为什么是2?因为y在倍增准备的时候是一次增加一倍的)即可。

第一种代码实现:使用long long

但现在lc已经规定假设只有int这一数据类型,所以这一解法是不成立的,但二进制的基本思路还是不变的。

实现的时候有两个难点

1、 怎么产生倍增数组
在这里插入图片描述
在这里插入图片描述
2、不用乘法,商怎么加上 2的索引次方(这里使用了位运算,1 << i 的意义就是将1在二进制上向左移位 i 格,新移出的部分都会0,比如:1 << 3,实际上在二进制中就是0001 —> 1000,变为了2^3。从上面的例子可以看出对1做左移位,向左移动几位后其值就正好是2的 几次方
在这里插入图片描述
若想进一步了解“位运算”,可以参考文章:
c++位运算中最常用的两种操作

】这里由于可能会出现溢出,即如果i==31时,2^31就已经超出了int的数据范围了,所以在1后面加上了 ll (long long)防止溢出。这是c++11中的新特性,将ll或LL加在某个数字的后面,可以将其提升为long long类型,也可以防止在后面的计算中溢出!!!

代码示例:

class Solution {
   
public:
    int divide(int x, int y) {
   
       typedef long long LL; // type + def : 由于long long写起来比较长,所以可以重新定义一下。定义的时候你可以读作:type long long def LL,这样更好记忆,long long要放在前面,LL 要放在后面
       vector<LL> exp; // 用于存二进制倍增数组
       bool is_minus = false;
       if(x < 0 && y > 0 || x > 0 && y < 0) is_minus = true;

       LL a = labs((LL)x), b = labs((LL)y); // x可能是-2^31,除以一个正数可能就溢出了(但现在题目规定了不能用long long,假设只有int存)

       // 现在开始生成二进制倍增的前提,在小于a的前提下,每次都倍增一次
       // 到时候减的时候,从大向小减
       for(LL i = b; i <= a; i = i + i) exp.push_back(i); // 注意存入方式是push_back,注意是可以取到等于a的,最好的情况就是和a相等,这样就能够整除了

       LL res = 0;
       for(int i = exp.size() - 1; i >= 0; i --) {
    // 从大往小去减
           while(a >= exp[i]) {
    // 这里while的时间复杂度为O(1),因为只会执行一次,其实这里用if也行,只是while更好理解
               a -= exp[i];
               // 下面是关键代码:如何获取exp[i]对应多少商?
               res += 1ll << i; // 为什么加上2的i次方,因为假设上面条件成立,那么x时减去了2个i次方的y成立,商则是要加上2的i次方
               // 2的i次方注意会溢出,不过这里防止溢出的方式还是很难理解
           }
       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值