【每日一练】1/2/23(需填坑)

刷题原则

  1. 尽可能自己实现一遍代码,跑通示例
  2. 无论是否AC,看一看大神解法
  3. 看完大神解法后,无提示情况下重现一遍,找到遗漏的关键点
  4. 做笔记,当时理解上的困难点尽可能说明

剑指 Offer II 001. 整数除法

题目描述【简单】

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'、除号 '/' 以及求余符号 '%' ;

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2 ;

假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31−1]。本题中,如果除法结果溢出,则返回 2^31−1 。

输入:-2^31 <= a, b <= 2^31 - 1;  b != 0

示例:

输入:a = 15, b = 2         输出:7         解释:15/2 = truncate(7.5) = 7

输入:a = 7, b = -3          ​​​​​​输出:-2        解释:7/-3 = truncate(-2.33333..) = -2

输入:a = 0, b = 1           输出:0

输入:a = 1, b = 1           输出:1

代码:

根据错误反馈,不断改正,得到的:

class Solution {
public:
    int divide(int a, int b) {
        int count = 0, flag = 0;
        if (a==0) return 0; // 需单独考虑,否则count--
        // 除法结果溢出?

        if ((a>0&&b<0)||(a<0&&b>0)) flag = 1;
        // 需考虑a、b为负数的情况
        a = abs(a); b = abs(b); // a=7, b=-3, c=-2
        while (a>0) {
            a -= b;
            count++;
        }
        
        if (a) count--; // 刚好减到0就不用减1了
        if (flag) count = 0-count;
        return count;
    }
};

因为不知道怎么判断溢出,去看了官方解答LeetCode

// 考虑被除数为最小值的情况
// [−2^31, 2^31−1]
// 若除法结果溢出,则返回2^31−1
// INT_MIN==−2^31,INT_MAX==2^31−1

if (a == INT_MIN) {
    if (b == 1) {
        return INT_MIN;
    }
    if (b == -1) {
        return INT_MAX;
    }
}
// 考虑除数为最小值的情况
if (b == INT_MIN) {
    return a == INT_MIN ? 1 : 0;
}

但是依然有测试错误:

通过测试用例:910 / 992

输入:-2147483648 2        输出:1        预期结果:-1073741824

即使这里不出现错误,应该也会有超时的问题吧。

对于正负的讨论

如果我们将被除数和除数都变为正数,那么可能会导致溢出。

例如当被除数为−2^31时,它的相反数2^31产生了溢出。

因此,我们考虑将被除数和除数都变为负数,就不会有溢出的问题了,在编码时只需要考虑1种情况。

算法思路:二分查找

在考虑【快速乘】时,A + B可能会产生溢出,因此我们必须将判断改为 A < C - B是否成立。

class Solution {
public:
    int divide(int a, int b) {
        // 考虑a, b溢出
        
        // 转化为负数

        // 快速乘
        auto quickAdd = [](int y, int z, int x) {
            // x 和 y 是负数,z 是正数
            // 需要判断 z * y >= x 是否成立
            int result = 0, add = y;
            while (z) {
                if (z & 1) {
                    // 需要保证 result + add >= x
                    if (result < x - add) {
                        return false;
                    }
                    result += add;
                }
                if (z != 1) {
                    // 需要保证 add + add >= x
                    if (add < x - add) {
                        return false;
                    }
                    add += add;
                }
                // 不能使用除法
                z >>= 1;
            }
            return true;
        };
        
        int left = 1, right = INT_MAX, ans = 0;
        while (left <= right) {
            // 注意溢出,并且不能使用除法
            int mid = left + ((right - left) >> 1);
            bool check = quickAdd(b, mid, a);
            if (check) {
                ans = mid;
                // 注意溢出
                if (mid == INT_MAX) {
                    break;
                }
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }

        return rev ? -ans : ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/xoh6Oh/solution/zheng-shu-chu-fa-by-leetcode-solution-3572/
来源:力扣(LeetCode)

理解中……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值