LeetCode-数学专题总结

数学

素数

素数分解

每一个数都可以分解成素数的乘积,例如 84 = 22 * 31 * 50 * 71 * 110 * 130 * 170 * …

整除

令 x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * …

令 y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * …

如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。

生成素数序列

204. Count Primes (Easy)

埃拉托斯特尼筛法在每次找到一个素数时,将能被素数整除的数排除掉。

class Solution {
    public int countPrimes(int n) {
        boolean[] notPrimes = new boolean[n + 1];
        int count = 0;
        for (int i = 2; i < n; i++) {
            if (notPrimes[i]) {
                continue;
            }
            count++;
            for (long j = (long) i * i; j < n; j += i) {
                notPrimes[(int) j] = true;
            }
        }
        return count;
    }
}

最大公约数

最大公约数最小公倍数

x 和 y 的最大公约数为:gcd(x,y) = 2min(m0,n0) * 3min(m1,n1) * 5min(m2,n2) * …

x 和 y 的最小公倍数为:lcm(x,y) = 2max(m0,n0) * 3max(m1,n1) * 5max(m2,n2) * …

使用位操作和减法求解最大公约数

对于 a 和 b 的最大公约数 f(a, b),有:

  • 如果 a 和 b 均为偶数,f(a, b) = 2*f(a/2, b/2);
  • 如果 a 是偶数 b 是奇数,f(a, b) = f(a/2, b);
  • 如果 b 是偶数 a 是奇数,f(a, b) = f(a, b/2);
  • 如果 a 和 b 均为奇数,f(a, b) = f(b, a-b);

乘 2 和除 2 都可以转换为移位操作。

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

最小公倍数为两数的乘积除以最大公约数。

int lcm(int a, int b) {
    return a * b / gcd(a, b);
}

进制转换

7 进制

504. Base 7 (Easy)

class Solution {
    public String convertToBase7(int num) {
        if (0 == num) {
            return "0";
        }
        boolean negative = num < 0 ? true : false;
        if (negative) {
            num = - num;
        }
        StringBuilder result = new StringBuilder();
        int a = 0, b = 0;
        while (num > 0) {
            a = num / 7;
            b = num % 7;
            num = a;
            result.append(b);
        }
        String ret = result.reverse().toString();
        return negative == true ? "-" + ret : ret;
    }
}

Java 中 static String toString(int num, int radix) 可以将一个整数转换为 radix 进制表示的字符串。

public String convertToBase7(int num) {
    return Integer.toString(num, 7);
}

16 进制

405. Convert a Number to Hexadecimal (Easy)

Input:
26

Output:
"1a"

Input:
-1

Output:
"ffffffff"

负数要用它的补码形式。

class Solution {
    public String toHex(int num) {
        if (0 == num) {
            return "0";
        }
        char[] map = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        StringBuilder result = new StringBuilder();
        while (num != 0) {
            result.append(map[num & 0b1111]);
            num = num >>> 4;
        }
        String ret = result.reverse().toString();
        return ret;
    }
}

26 进制

168. Excel Sheet Column Title (Easy)

1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB

因为是从 1 开始计算的,而不是从 0 开始,因此需要对 n 执行 -1 操作。

lass Solution {
    public String convertToTitle(int n) {
        if (0 == n) {
            return "";
        }
        n--;
        int a = n / 26;
        int b = n % 26;
        return convertToTitle(a) + (char)(b + 'A');
    }
}

字符串加法减法

二进制加法

67. Add Binary (Easy)

a = "11"
b = "1"
Return "100".
class Solution {
    public String addBinary(String a, String b) {
        if (0 == a.length() && 0 == b.length()) {
            return "";
        }
        if (0 == a.length()) {
            return b;
        }
        if (0 == b.length()) {
            return a;
        }
        if (a.length() < b.length()) {
            while (a.length() != b.length()) {
                a = "0" + a;
            }
        } else if (a.length() > b.length()) {
            while (a.length() != b.length()) {
                b = "0" + b;
            }
        }
        int[] ret = new int[a.length() + 1];
        int index = a.length();
        for (int i = a.length() - 1; i >= 0; i--) {
            int x = a.charAt(i) - '0';
            int y = b.charAt(i) - '0';
            ret[index--] = x + y;
        }
        for (int i = a.length(); i >= 0; i--) {
            if (ret[i] >= 2) {
                ret[i] = ret[i] - 2;
                ret[i - 1]++;
            }
        }
        String result = "";
        for (int i = 0; i <= a.length(); i++) {
            if (i == 0 && ret[i] == 0) {
                continue;
            }
            result += ret[i];
        }
        return result;
    }
}

字符串加法

415. Add Strings (Easy)

字符串的值为非负整数。

class Solution {
    public String addStrings(String num1, String num2) {
        if (null == num1 || null == num2) {
            return "";
        }
        if (0 == num1.length() && 0 == num2.length()) {
            return "";
        }
        if (0 == num1.length()) {
            return num2;
        }
        if (0 == num2.length()) {
            return num1;
        }
        if (num1.length() < num2.length()) {
            while (num1.length() != num2.length()) {
                num1 = "0" + num1;
            }
        } else if (num1.length() > num2.length()) {
            while (num1.length() != num2.length()) {
                num2 = "0" + num2;
            }
        }
        int[] ret = new int[num1.length() + 1];
        int index = num1.length();
        for (int i = num1.length() - 1; i >= 0; i--) {
            int a = num1.charAt(i) - '0';
            int b = num2.charAt(i) - '0';
            ret[index--] = a + b;
        }
        for (int i = num1.length(); i >= 0; i--) {
            if (ret[i] >= 10) {
                ret[i - 1] += ret[i] / 10;
                ret[i] = ret[i] % 10;
            }
        }
        String result = "";
        for (int i = 0; i <= num1.length(); i++) {
            if (i == 0 && ret[i] == 0) {
                continue;
            }
            result += ret[i];
        }
        return result;
    }
}

相遇问题

改变数组元素使所有的数组元素都相等

462. Minimum Moves to Equal Array Elements II (Medium)

Input:
[1,2,3]

Output:
2

Explanation:
Only two moves are needed (remember each move increments or decrements one element):

[1,2,3]  =>  [2,2,3]  =>  [2,2,2]

每次可以对一个数组元素加一或者减一,求最小的改变次数。

这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下:

设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。

设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。

解法 1

先排序,时间复杂度:O(NlogN)

class Solution{
	public int minMoves2(int[] nums) {
    	Arrays.sort(nums);
    	int move = 0;
    	int l = 0, h = nums.length - 1;
    	while (l <= h) {
			move += nums[h] - nums[l];
        	l++;
        	h--;
    	}
    	return move;
	}
}

解法 2

使用快速选择找到中位数,时间复杂度 O(N)

class Solution {
    public int minMoves2(int[] nums) {
        if (null == nums || 0 == nums.length) {
            return 0;
        }
        int n = nums.length;
        int mid = findKthNumber(nums, n / 2);
        int moves = 0;
        for (int i = 0; i < n; i++) {
            moves += Math.abs(nums[i] - mid);
        }
        return moves;
    }
    public int findKthNumber(int[] nums, int length) {
        int i = 0, j = nums.length - 1;
        while (i < j) {
            int index = partition(nums, i, j);
            if (index == length) {
                break;
            } else if (index < length) {
                i = index + 1;
            } else {
                j = index - 1;
            }
        }
        return nums[length];
    }
    public int partition(int[] nums, int left, int right) {
        int i = left, j = right, base = nums[left];
        while (i < j) {
            while (i < j && base <= nums[j]) {
                j--;
            }
            if (i < j) {
                nums[i++] = nums[j];
            }
            while (i < j && base >= nums[i]) {
                i++;
            }
            if (i < j) {
                nums[j--] = nums[i];
            }
        }
        nums[i] = base;
        return j;
    }
}

多数投票问题

数组中出现次数多于 n / 2 的元素

169. Majority Element (Easy)

class Solution {
    public int majorityElement(int[] nums) {
        int n = nums.length;
        int max = nums[0], pre = nums[0], cnt = 1;
        if (n <= 1) {
            return max;
        }
        for (int i = 1; i < n; i++) {
            if (nums[i] == pre) {
                cnt++;
            } else {
                cnt--;
                if (0 == cnt) {
                    pre = nums[i];
                    max = nums[i];
                    cnt = 1;
                }
            }
        }
        return max;
    }
}

其它

平方数

367. Valid Perfect Square (Easy)

Input: 16
Returns: True

平方序列:1,4,9,16,…

间隔:3,5,7,…

间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。

class Solution {
    public boolean isPerfectSquare(int num) {
        int sub = 1;
        while (num > 0) {
            num -= sub;
            sub += 2;
        }
        return num == 0;
    }
}

乘积数组

238. Product of Array Except Self (Medium)

For example, given [1,2,3,4], return [24,12,8,6].

给定一个数组,创建一个新数组,新数组的每个元素为原始数组中除了该位置上的元素之外所有元素的乘积。

要求时间复杂度为 O(N),并且不能使用除法。

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        int[] result = new int[n];
        result[0] = 1;
        for(int i = 1;i < n;i++){
            result[i] = result[i - 1] * nums[i - 1];
        }
        int x = 1;
        for(int i = n - 2;i >= 0;i--){
            x *= nums[i + 1];
            result[i] *= x;
        }
        return result;
    }
}

找出数组中的乘积最大的三个数

628. Maximum Product of Three Numbers (Easy)

Input: [1,2,3,4]
Output: 24
class Solution {
    public int maximumProduct(int[] nums) {
        if (null == nums || nums.length < 3) {
            return -1;
        }
        int n = nums.length;
        Arrays.sort(nums);
        return Math.max(nums[0] * nums[1] * nums[n - 1], nums[n - 3] * nums[n - 2] * nums[n - 1]);
    }
}

你可能感兴趣的:(coding)