素數分解html
每個數均可以分解成素數的乘積,例如 84 = 22 * 31 * 50 * 71 * 110 * 130 * 170 * …java
令 x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * …git
令 y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * …github
若是 x 整除 y(y mod x == 0),則對於全部 i,mi <= ni。算法
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) * ...數組
埃拉託斯特尼篩法在每次找到一個素數時,將能被素數整除的數排除掉。ui
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++; // 從 i * i 開始,由於若是 k < i,那麼 k * i 在以前就已經被去除過了 for (long j = (long) (i) * i; j < n; j += i) { notPrimes[(int) j] = true; } } return count; }
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
最小公倍數爲兩數的乘積除以最大公約數。spa
int lcm(int a, int b) { return a * b / gcd(a, b); }
對於 a 和 b 的最大公約數 f(a, b),有:
乘 2 和除 2 均可以轉換爲移位操做。
public int gcd(int a, int b) { if (a < b) { return gcd(b, a); } if (b == 0) { return a; } boolean isAEven = isEven(a), isBEven = isEven(b); if (isAEven && isBEven) { return 2 * gcd(a >> 1, b >> 1); } else if (isAEven && !isBEven) { return gcd(a >> 1, b); } else if (!isAEven && isBEven) { return gcd(a, b >> 1); } else { return gcd(b, a - b); } }
public String convertToBase7(int num) { if (num == 0) { return "0"; } StringBuilder sb = new StringBuilder(); boolean isNegative = num < 0; if (isNegative) { num = -num; } while (num > 0) { sb.append(num % 7); num /= 7; } String ret = sb.reverse().toString(); return isNegative ? "-" + ret : ret; }
Java 中 static String toString(int num, int radix) 能夠將一個整數轉換爲 radix 進製表示的字符串。
public String convertToBase7(int num) { return Integer.toString(num, 7); }
405. Convert a Number to Hexadecimal (Easy)
Input:
26
Output:
"1a"
Input:
-1
Output:
"ffffffff"
負數要用它的補碼形式。
public String toHex(int num) { char[] map = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; if (num == 0) return "0"; StringBuilder sb = new StringBuilder(); while (num != 0) { sb.append(map[num & 0b1111]); num >>>= 4; // 由於考慮的是補碼形式,所以符號位就不能有特殊的意義,須要使用無符號右移,左邊填 0 } return sb.reverse().toString(); }
168. Excel Sheet Column Title (Easy)
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
由於是從 1 開始計算的,而不是從 0 開始,所以須要對 n 執行 -1 操做。
public String convertToTitle(int n) { if (n == 0) { return ""; } n--; return convertToTitle(n / 26) + (char) (n % 26 + 'A'); }
172. Factorial Trailing Zeroes (Easy)
尾部的 0 由 2 * 5 得來,2 的數量明顯多於 5 的數量,所以只要統計有多少個 5 便可。
對於一個數 N,它所包含 5 的個數爲:N/5 + N/52 + N/53 + ...,其中 N/5 表示不大於 N 的數中 5 的倍數貢獻一個 5,N/52 表示不大於 N 的數中 52 的倍數再貢獻一個 5 ...。
public int trailingZeroes(int n) { return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5); }
若是統計的是 N! 的二進制表示中最低位 1 的位置,只要統計有多少個 2 便可,該題目出自 編程之美:2.2 。和求解有多少個 5 同樣,2 的個數爲 N/2 + N/22 + N/23 + ...
a = "11"
b = "1"
Return "100".
public String addBinary(String a, String b) { int i = a.length() - 1, j = b.length() - 1, carry = 0; StringBuilder str = new StringBuilder(); while (carry == 1 || i >= 0 || j >= 0) { if (i >= 0 && a.charAt(i--) == '1') { carry++; } if (j >= 0 && b.charAt(j--) == '1') { carry++; } str.append(carry % 2); carry /= 2; } return str.reverse().toString(); }
字符串的值爲非負整數。
public String addStrings(String num1, String num2) { StringBuilder str = new StringBuilder(); int carry = 0, i = num1.length() - 1, j = num2.length() - 1; while (carry == 1 || i >= 0 || j >= 0) { int x = i < 0 ? 0 : num1.charAt(i--) - '0'; int y = j < 0 ? 0 : num2.charAt(j--) - '0'; str.append((x + y + carry) % 10); carry = (x + y + carry) / 10; } return str.reverse().toString(); }
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)
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)
public int minMoves2(int[] nums) { int move = 0; int median = findKthSmallest(nums, nums.length / 2); for (int num : nums) { move += Math.abs(num - median); } return move; } private int findKthSmallest(int[] nums, int k) { int l = 0, h = nums.length - 1; while (l < h) { int j = partition(nums, l, h); if (j == k) { break; } if (j < k) { l = j + 1; } else { h = j - 1; } } return nums[k]; } private int partition(int[] nums, int l, int h) { int i = l, j = h + 1; while (true) { while (nums[++i] < nums[l] && i < h) ; while (nums[--j] > nums[l] && j > l) ; if (i >= j) { break; } swap(nums, i, j); } swap(nums, l, j); return j; } private void swap(int[] nums, int i, int j) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; }
先對數組排序,最中間那個數出現次數必定多於 n / 2。
public int majorityElement(int[] nums) { Arrays.sort(nums); return nums[nums.length / 2]; }
能夠利用 Boyer-Moore Majority Vote Algorithm 來解決這個問題,使得時間複雜度爲 O(N)。能夠這麼理解該算法:使用 cnt 來統計一個元素出現的次數,當遍歷到的元素和統計元素不相等時,令 cnt--。若是前面查找了 i 個元素,且 cnt == 0,說明前 i 個元素沒有 majority,或者有 majority,可是出現的次數少於 i / 2,由於若是多於 i / 2 的話 cnt 就必定不會爲 0。此時剩下的 n - i 個元素中,majority 的數目依然多於 (n - i) / 2,所以繼續查找就能找出 majority。
public int majorityElement(int[] nums) { int cnt = 0, majority = nums[0]; for (int num : nums) { majority = (cnt == 0) ? num : majority; cnt = (majority == num) ? cnt + 1 : cnt - 1; } return majority; }
367. Valid Perfect Square (Easy)
Input: 16
Returns: True
平方序列:1,4,9,16,..
間隔:3,5,7,...
間隔爲等差數列,使用這個特性能夠獲得從 1 開始的平方序列。
public boolean isPerfectSquare(int num) { int subNum = 1; while (num > 0) { num -= subNum; subNum += 2; } return num == 0; }
public boolean isPowerOfThree(int n) { return n > 0 && (1162261467 % n == 0); }
238. Product of Array Except Self (Medium)
For example, given [1,2,3,4], return [24,12,8,6].
給定一個數組,建立一個新數組,新數組的每一個元素爲原始數組中除了該位置上的元素以外全部元素的乘積。
要求時間複雜度爲 O(N),而且不能使用除法。
public int[] productExceptSelf(int[] nums) { int n = nums.length; int[] products = new int[n]; Arrays.fill(products, 1); int left = 1; for (int i = 1; i < n; i++) { left *= nums[i - 1]; products[i] *= left; } int right = 1; for (int i = n - 2; i >= 0; i--) { right *= nums[i + 1]; products[i] *= right; } return products; }
628. Maximum Product of Three Numbers (Easy)
Input: [1,2,3,4]
Output: 24
public int maximumProduct(int[] nums) { int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE, min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE; for (int n : nums) { if (n > max1) { max3 = max2; max2 = max1; max1 = n; } else if (n > max2) { max3 = max2; max2 = n; } else if (n > max3) { max3 = n; } if (n < min1) { min2 = min1; min1 = n; } else if (n < min2) { min2 = n; } } return Math.max(max1*max2*max3, max1*min1*min2); }