Leetcode-Math题型

Leetcode 7. Reverse Integer 【Easy】
难点在于 int 越界问题,用int temp暂时代替即可.

class Solution {
    public int reverse(int x) {
        int res = 0;
        while(x != 0){
            int a = x % 10;
            int temp = res * 10 + a;    //处理越界问题
            if((temp-a)/10 != res) return 0;
            res = temp;
            x = x/10;
        }
        return res;
    }
}

Leetcode 165. Compare Version Numbers.【Medium】
http://www.runoob.com/java/java-regular-expressions.html
java正则表达式中,. 匹配除"\r\n"之外的任何单个字符。\. 表示匹配 . 本身。为什么是两个 \ 呢?java的 \ 等同于其他语言的一个 \ 。
难点在于Math.max() , 和 i

class Solution {
    public int compareVersion(String version1, String version2) {
        String[] v1 = version1.split("\\.");
        String[] v2 = version2.split("\\.");
        for(int i=0; i num2 ) return 1;
            if( num1 < num2 ) return -1;
        }
        return 0; 
    }
}

Leetcode 66. Plus One. 【Easy】
只分为两种情况,一是999,而是其他。
其他,就用for循环倒序遍历来解决。

class Solution {
    public int[] plusOne(int[] digits) {
        for(int i=digits.length-1; i>=0; i--){
            if(digits[i]<9){
                digits[i]++;
                return digits;
            } else {
                digits[i] = 0;
            }
        }
        int[] newDigits = new int[digits.length+1];
        newDigits[0] = 1;
        return newDigits;
    }
}

Leetcode 8. String to Integer (atoi) 【Medium】
判断str.charAt(0),用start记录数字开始的位置。遍历。

class Solution {
    public int myAtoi(String str) {
        str = str.trim();
        if(str == null || str.length() == 0) return 0;
        long res = 0; 
        int start = 0; 
        int sign = 1; 
        if(str.charAt(0) == '+'){
            start++;
        } else if (str.charAt(0) == '-'){
            sign = -1;
            start++;
        }
        for(int i = start; i< str.length();i++){
            if(!Character.isDigit(str.charAt(i))){
                return (int)res * sign;
            }
            res = res * 10 + str.charAt(i) - '0';
            if(sign==1 && res>=Integer.MAX_VALUE) return Integer.MAX_VALUE;
            if(sign==-1 && res>Integer.MAX_VALUE) return Integer.MIN_VALUE;
        }
        return (int)res * sign;
    }
}

Leetcode 258. Add Digits. 【Easy】
常规暴力解法。Time: O(n), Space: O(1).

class Solution {
    public int addDigits(int num) {
        int sum = 0;
        while(true){
            sum = 0;
            while(num>0){
                sum += num % 10;
                num /= 10;
            }
            num = sum;
            if(sum<10) break;
        }
        return sum;
        
    }
}

找规律:以9为循环


num对应的result以9为循环.jpg
class Solution {
    public int addDigits(int num) {
        return (num - 1) % 9 + 1;
    }
}

Leetcode 67. Add Binary 【Easy】
倒序遍历两个数组。用while(i>=0 || j>=0)作为判断,用remainder记录进位。
Time: O(n), Space: O(n).

class Solution {
    public String addBinary(String a, String b) {
        StringBuilder sb = new StringBuilder();
        int i = a.length() - 1;
        int j = b.length() - 1;
        int remainder = 0, sum = 0;
        while(i>=0 || j>=0){
            sum = remainder;
            if(i>=0) sum += a.charAt(i--) -'0';
            if(j>=0) sum += b.charAt(j--) -'0';
            sb = sb.insert(0,sum%2);     
            //如果用sb.append(num%2),就要在最后return sb.reverse().toString()
            remainder = sum/2;  
        }
        if(remainder != 0) sb = sb.insert(0,remainder);
        return sb.toString();
    }
}

Leetcode 43. Multiply Strings. 【Medium】
题目要求4: You must not use any built-in BigInteger library or convert the inputs to integer directly. 不能直接用long,int等。
两个for循环,倒序遍历,每次计算两个一位数的乘积,累加到new int[]对应位置

class Solution {
    public String multiply(String num1, String num2) {
        int[] digits = new int[num1.length()+num2.length()];  //想清楚这里
        for(int i=num1.length()-1; i>=0; i--){
            for(int j=num2.length()-1; j>=0; j--){
                int product = (num1.charAt(i)-'0') * (num2.charAt(j)-'0'); //注意要 -'0'
                int index1 = i + j, index2 = index1 + 1;   //想清楚这里 
                int sum = product + digits[index2]; 
                digits[index2] = sum % 10;    
                digits[index1] += sum / 10;    // 注意是 +=
            }
        }
        
        String res = new String();   // 用String 或 StringBuilder都行
        for(int digit: digits){
            if(!(res.length() == 0 && digit == 0)){   //第一个加入res的必须是非零数
               res += digit; 
            } 
        }
        System.out.println(res);
        return res.length() == 0? "0": res;        
    }
}

Leetcode 29. Divide Two Integers 【Medium】
这题考了左移的操作。用 divideHelper 测试dividend 能装多少个divisor,用的while()循环,实际上是类似二分查找。
注意:把两个负数传入divideHelper,是因为 MIN_VALUE 绝对值比 MAX_VALUE 大1,如果 abs(MIN_VALUE) 会越界。所以干脆传两个负数进helper.

class Solution {
    public int divide(int dividend, int divisor) {
        //负数左移,也是相当于*2,直到小于MIN_VALUE,就越界成为正数(不规则的正数)
        if(dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE;
        boolean isSameSign = (dividend <0) == (divisor<0);
        int res = divideHelper(-Math.abs(dividend),-Math.abs(divisor));        
        return isSameSign ? res : -res;
    }
    
    private int divideHelper(int dividend, int divisor){
        int res = 0;
        int currentDivisor = divisor;
        while(dividend<=divisor){   // abs(divisor) <= abs(dividend)
            int temp = 1;            
            while((currentDivisor << 1)>=dividend && (currentDivisor << 1)<0 ){ //test max temp for: temp * abs(divisor) <= abs(dividend), while temp = 2^n
                temp <<=1;
                currentDivisor <<=1;
            }
            dividend -= currentDivisor;
            res += temp;
            currentDivisor = divisor;   //将currentDivisor恢复为divisor
        }       
        return res;
    }    
}

Leetcode 69. Sqrt(x). 【Easy】
这题,需要写出两种情况:1) 二分法;2) 牛顿法。
二分法:Time: O(logn), Space: O(1).

class Solution {
    public int mySqrt(int x) {
        if(x<=0) return 0;
        int low = 1, high = x;
        while(low<=high){
            long mid = (high - low)/2 + low;
            if(mid * mid == x){     // mid * mid 可能越界,所以应该设置mid为long。比如当x=MAX_VALUE, 第一次计算mid^2就必然越界
                return (int)mid;
            } else if (mid * mid > x){
                high = (int)mid - 1;
            } else {
                low = (int)mid + 1;
            }
        }
        return high;
        // if(high * high < x){ //必定的结果
        //     return high;
        // } 
        // return 0;
    }
}

牛顿法:
牛顿法,又名切线法。

CSDN搜索: leetcode:Sqrt(x) 牛顿迭代法求整数开方
https://blog.csdn.net/newfelen/article/details/23359629

draw a tangent line for function f(x), the tangent line and x axis intersects at point( xn+1, 0). So the tangent line passes both (xn, f(xn)) and (xn+1, 0). We can get the equation for the tangent line, which is ...

公式推导:
经过 (xn+1,0), ( xn, f(xn) ) 且斜率为f'(xn) 的直线,直线表达式为:
( f(xn)-0 ) / (xn - xn+1) = f'(xn) , 化简得到:


牛顿法的迭代公式.jpg

而本题 f(xn) = x^2 - n, f' = 2x. 所以,
xn+1 = xn - (x^2-n)/2x
= (x + n/x)/2.
牛顿法的Time Complexity 是unstable 不稳定的,可以理解为 接近O(logn).

public int mySqrt(int x){
    long res = x; 
    while( res * res > x){
        res = ( res + x / res ) / 2 ; 
    }
    return (int)res;
}

Leetcode 367. Valid Perfect Square. 【Easy】
这题,需要写出两种情况:1) 二分法;2) 牛顿法。
二分法:Time: O(logn), Space: O(1).

class Solution {
    public boolean isPerfectSquare(int num) {
        int low = 1, high = num;
        while(low<=high){
            long mid = (high - low)/2 + low;
            if(mid * mid == num){     // mid * mid 可能越界,所以应该设置mid为long。比如当x=MAX_VALUE, 第一次计算mid^2就必然越界
                return true; 
            } else if (mid * mid < num){
                low = (int)mid + 1;
            } else {
                high = (int)mid - 1;
            }     
        }
        return false;
    }
}

牛顿法:Time 是 uncertain,但在这题可理解为优于O(nlogn).

class Solution {
    public boolean isPerfectSquare(int num) {
        long x = num;
        while(x * x > num){
            x = (x + num/x)/2;
        }
        return x * x == num;
    }
}

Leetcode 50. Pow(x, n) 【Medium】

Time: O(logn), Space: O(1).
本题暴力解法就是O(n), 要提升,必然是二分法,提升到O(logn).
用Iterative方法,每次while循环,让n降低到一半,并对x进行平方。
注意:min的绝对值大于max绝对值,所以Integer.MIN_VALUE的绝对值会越界;所以要用long值记录n的绝对值。

class Solution {
    public double myPow(double x, int n) {
        if(n==0) return 1;
        long abs = Math.abs((long)n);
        double res = 1;
        while(abs >0){
            if(abs%2 != 0) {
                res *= x;
            }
            x *= x;
            abs /= 2;
        }
        if(n<0) {
            return 1/res;
        } else {
            return res;
        }       
    }
}

【不推荐】用Recursive方法做。

    public double myPow(double x, int n) {
        return n<0? 1/helper(x,-n):helper(x,n);                
    }
       
    private double helper(double x, int n){
        if(n==0) return 1;
        double y = helper(x,n/2);
        if(n%2 != 0){
            return y * y * x;
        } else {
            return y * y;
        }
    }

Leetcode 365. Water and Jug Problem 【Medium】
这是纯数学问题。只有当z%(x和y的最大公约数)==0 时才为true。
math theory 链接:Bézout's identity 数学家 Mathematician 读音:/'bezu/ 贝祖

class Solution {
    public boolean canMeasureWater(int x, int y, int z) {
        if(x+y

辗转相除法,英文是Euclidean Algorithm,欧几里得算法。【juːˌklɪdiən】
最大公约数的Recursive写法:

    public int gcd(int a, int b){
        if(b==0) return a;
        return gcd(b,a%b);
    }

Leetcode 204 Count Primes 【Easy】
构建一个boolean[] 用来记录每个数是否为prime。外层for循环遍历数组,内层for循环, 改变 i的倍数对应的boolean,从而得到每个数是否为prime的信息。

class Solution {
    public int countPrimes(int n) {
        boolean[] notPrime = new boolean[n+1]; //j<=n/i情况下用n+1.若是i*j

Leetcode 1. Two Sum. 【Easy】
经典题,用HashMap来记录前面存在的值和对应位置。for循环遍历至某值,查询target-该值在map中是否存在。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[]{-1,-1};
        Map map = new HashMap<>();
        for(int i=0; i

Leetcode 167. Two Sum II - Input array is sorted. 【Easy】
Time: O(n).
题目:已经排序完毕。
经典题,参考了二分法的步骤,但这里是right--或left++,每次只移动一步

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int left = 0, right = numbers.length-1;
        while(lefttarget){
                right--;
            } else {
                left++;
            }
        }
        return new int[]{-1,-1};
    }
}

Leetcode 15. 3Sum. 【Medium】
Time: O(n2).
题目没排序。要用二分法思想,需要先排序。只有在从小到大排序好的数组中,才能移动left和right,而且才能达到避免duplicate的目的。
参考Leetcode 167. 同样是运用了二分法的思想。难点在于怎么把三个数之和转化为两个数之和。
要避免duplicate重复,首先需要排序。用Arrays.sort() 排序。
然后第一层for循环遍历数组,第二层while用left和right,遍历该数右边的子数组。

class Solution {
    public List> threeSum(int[] nums) {
        List> res = new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0; i0 && nums[i]==nums[i-1]) continue; //避免duplicate的关键1
            int left = i+1, right = nums.length-1;
            int sum = 0 - nums[i];
            while(leftsum){
                    right--;
                } else {
                    left++;
                }
            }
        }
        return res;
    }
}

Leetcode 16.
题目没排序。要用二分法思想,需要先排序。只有在从小到大排序好的数组中,才能移动left和right。

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int res = nums[0] + nums[1] + nums[2];
        Arrays.sort(nums);
        for(int i=0; itarget){
                    right--;
                } else {
                    left++;
                }
            }
        }
        return res;
    }
}

Leetcode 259. 3Sum Smaller 【Medium】

class Solution {
    public int threeSumSmaller(int[] nums, int target) {
        int res = 0; 
        Arrays.sort(nums);
        for(int i=0;i

Leetcode 18. 4Sum. 【Medium】

class Solution {
    public List> fourSum(int[] nums, int target) {
        List> list = new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0;i0 && nums[i]==nums[i-1]) continue;
//比3Sum多了一个for和一句continue
            for(int j=i+1; ji+1 && nums[j]==nums[j-1]) continue;
                int left = j+1, right = nums.length-1;
                while(left

你可能感兴趣的:(Leetcode-Math题型)