Q29 Divede Two Integers

难度:Medium

题目

给定两个整数dividend和divisor,将两数相除但不能使用乘,除和取模操作符。> 返回商,整数除法只保留整数部分。

注:- 除数和被除数都为32位有符号整数- 除数不会为0- 假定运行环境只能储存32位有符号整数(范围[ − 2 31 , 2 31 − 1 -2^{31}, 2^{31}-1 231,2311])。对本问题,当返回结果溢出时直接返回 2 31 − 1 2^{31}-1 2311

用例

1

Input: dividend = 10, divisor = 3
Output: 3

2

Input: dividend = 7, divisor = -3
Output: -2

解法

思路1

不能乘除那就加减,当余数小于0时停止并计算减的次数。实现方式:

  • 直接计算
  • 使用位运算(左移)来加快计算
  • 使用递归隐藏过程

代码实现

代码1:直接计算

实际上该方法计算用例(-2147483648,1),一直减2147483648次,当然会计算超时而无法提交。

 public int INT_MIN = Integer.MAX_VALUE, INT_MAX = Integer.MIN_VALUE;    
 public int divide(int dividend, int divisor) {     
 // 仅有一种情况会产生溢出(-2147483648, -1)    
	if(dividend == INT_MAX && divisor == -1) 
		return INT_MIN; //get 1    
  	int count = 0;     
  	// 简化求符号过程    
    	int sign = (dividend > 0 ^ divisor > 0) ? -1 : 1; // get 2    
     // 避免(-2147483648,1)的超界情况     
     long dvd = Math.abs((long)dividend), dvs = Math.abs(divisor); // get3         
       // Math.abs(dividend)==> -2147483648 因为补码取反的原因   
      while(dvd >= dvs) {         
          count++;           
          dvd = dvd - dvs;    
      }     
      return sign * count;    
}  

代码2:使用位运算简化

位运算将除数通过左移1位来实现*2的目的,减少了计算所需的次数。
(但未通过用例(-1010369383, -2147483648),TLE,原因是当除数为int -2147483648时取绝对值函数无法正确处理,需要先转换为long型。

Runtime: 1 ms, Memory Usage: 32.3 MB.

    public int divide(int dividend, int divisor) {
     if(dividend == INT_MAX && divisor == -1) return INT_MIN; 
      int sign = (dividend > 0 ^ divisor > 0) ? -1 : 1; 
     long dvd = Math.abs((long)dividend), dvs = Math.abs((long)divisor), count = 0; 
     
     while(dvd >= dvs) {    
      long temp = dvs, m = 1; // get 1
      while(temp << 1 <= dvd) {
          m <<= 1;; // get 3        
       temp <<= 1;
      }
      dvd -= temp;
      count += m; // get 2
     }
        return sign * (int)count;
    }

代码3:递归方式

递归方式上述代码思路一致,只不过是使用递归改写了原迭代方式。

Runtime: 1 ms, Memory Usage: 32.4 MB.

    public int divide(int dividend, int divisor) {
     if(dividend == INT_MAX && divisor == -1) return INT_MIN; 
      int sign = (dividend > 0 ^ divisor > 0) ? -1 : 1; 
     long dvd = Math.abs((long)dividend), dvs = Math.abs((long)divisor), count = 0;      
     count = ldivide(dvd, dvs);
        return sign * (int)count;
    }
    private long ldivide(long dvd, long dvs) {
     if(dvd < dvs) return 0; // 递归出口 
     
     long temp = dvs, m = 1;
     while(temp << 1 < dvd) {
      temp <<= 1;
      m <<= 1;
     }
     return m + ldivide(dvd - temp, dvs);
    }

收获

  1. 两数相乘除判断结果符号的方式,显然从数学角度同号为正,异号为负。
  • 首先可以使用if语句实现,但有些繁琐
  • 最简洁的方式就是使用位运算^再结合三元表达式做
  1. 递归和迭代只不过是两种

你可能感兴趣的:(每天一道编程题)