剑指 Offer ll 001 整数除法

向右看齐 2024-03-27 09:22 134阅读 0赞

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

注意:

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231−1]。本题中,如果除法结果溢出,则返回 231 − 1

示例 1:

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

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

输入:a = 0, b = 1
输出:0
示例 4:

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

相关知识点:

1.位运算:

同位与^:同则0,异则1;例 0^0 = 0 1^0 = 1 false^false=false false^true=true

2.int的最大值

int是四个字节,即32个bit位,其中第一用来存储正负号,其他31位用来存储数据。但在正数上0被归为了正数,所以正数最大值是2^31-1,负数最小值就是2^31

方法一:减法代替除法

假设是a = 15, b = 2,则15-2=13,13-2=11……..3-2=1最终再无法减(a<=b)就结束。

1.其中考虑符号的情况

  • 全为正:符号没影响,直接进行计算
  • 一正一负:这时候要考虑符号情况,但计算过程可以依照全为正数的来计算,因此保留符号,然后对数字进行绝对值后再按照全为正的计算。

    • 正常的判断逻辑
    • 通过用位运算来进行性能的优化
  • 全为负:符号没影响,直接进行计算

2.同时也要考虑边界问题

因为int是四个字节,是32个bit位,但最大值和最小值不同;32位最大值:2^31-1=2147483647
32位最小值:-2^31 =-2147483648

因此将所有数字都取绝对值进行优化,因为正数和负数的操作都一样,但正数的最大值的绝对值比负数的最小值的绝对值小,所以都转化做负数来操作一定不越界

  1. class Solution {
  2. public int divide(int a, int b) {
  3. //32位最大值:2^31-1=2147483647
  4. //32位最小值:-2^31 =-2147483648
  5. //当a取-2147483648,b取-1时,2147483648>2147483647就会出现数组越界的情况
  6. //但2147483647变为负数就不会
  7. if(a==Interger.MIN_VALUE&&b == -1)
  8. return Interger.MAX_VALUE;
  9. //优化前
  10. //if((a>0&&b<0)||(a<0&&b>0)){
  11. // sign=-1;
  12. //}
  13. //优化后,采用位运算
  14. int sign = (a>0)^(b>0)?-1:1;
  15. //优化前
  16. //a = Math.abs(a);
  17. //b = Math.abs(b);
  18. //优化后
  19. //因为正数和负数的操作都一样,但正数的最大值的绝对值比负数的最小值的绝对值小
  20. //所以转化做负数来操作一定不越界
  21. if(a>0) a=-a;
  22. if(b>0) b=-b;
  23. int res = 0;
  24. //都改成负号之后要注意这里的条件符号要变
  25. while(a<=b){
  26. a -= b;
  27. res++;
  28. }
  29. return sign=1?res:-res;
  30. }
  31. }

方法二:优化,降低时间复杂度每次尝试减去除数的倍数

a = 22,b = 3

22-3*2 k=1
22- 3*2*2= 10 k=2

22-3*2*2*2< 0 k=4
a = 10,b = 3

10-3*2= 4 k=1

10-3*2*2< 0 k=2
a= 4,b = 3 k=1

4-3*2<0
a= 1,b= 3

a-b*2^k ==0 ==>k

  1. class Solution {
  2. public int divide(int a, int b) {
  3. //32位最大值:2^31-1=2147483647
  4. //32位最小值:-2^31 =-2147483648
  5. //当a取-2147483648,b取-1时,2147483648>2147483647就会出现数组越界的情况
  6. //但2147483647变为负数就不会
  7. if(a==Interger.MIN_VALUE&&b == -1)
  8. return Interger.MAX_VALUE;
  9. //优化前
  10. //if((a>0&&b<0)||(a<0&&b>0)){
  11. // sign=-1;
  12. //}
  13. //优化后,采用位运算
  14. int sign = (a>0)^(b>0)?-1:1;
  15. //优化前
  16. //a = Math.abs(a);
  17. //b = Math.abs(b);
  18. //优化后
  19. //因为正数和负数的操作都一样,但正数的最大值的绝对值比负数的最小值的绝对值小
  20. //所以转化做负数来操作一定不越界
  21. if(a>0) a=-a;
  22. if(b>0) b=-b;
  23. int res = 0;
  24. //都改成负号之后要注意这里的条件符号要变
  25. while(a<=b){
  26. int value = b;
  27. int k = 1;
  28. // 0xc0000000 是十进制 -2^30 的十六进制的表示
  29. // 判断 value >= 0xc0000000 的原因:保证 value + value 不会溢出
  30. // 可以这样判断的原因是:0xc0000000 是最小值 -2^31 的一半,
  31. // 而 a 的值不可能比 -2^31 还要小,所以 value 不可能比 0xc0000000 小
  32. // -2^31 / 2 = -2^30
  33. while (value >= 0xc0000000 && a <= value + value) {
  34. value += value;
  35. // 代码优化:如果 k 已经大于最大值的一半的话,那么直接返回最小值
  36. // 因为这个时候 k += k 的话肯定会大于等于 2147483648 ,这个超过了题目给的范围
  37. if (k > Integer.MAX_VALUE / 2) {
  38. return Integer.MIN_VALUE;
  39. }
  40. k += k;
  41. }
  42. a -= value;
  43. res += k;
  44. }
  45. return sign=1?res:-res;
  46. }
  47. }

参考

简单易懂Java/C++ /Python/js/go - 整数除法(剑指) - 整数除法 - 力扣(LeetCode)

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/xoh6Oh
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

发表评论

表情:
评论列表 (有 0 条评论,134人围观)

还没有评论,来说两句吧...

相关阅读