目录
素数分解
每一个数都可以分解成素数的乘积,例如 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。
最大公约数最小公倍数
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) * …
1. 生成素数序列
204. Count Primes (Easy)
埃拉托斯特尼筛法在每次找到一个素数时,将能被素数整除的数排除掉。
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;
}
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);
}
3. 使用位操作和减法求解最大公约数
对于 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 都可以转换为移位操作。
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);
}
}
进制转换
十进制转为七进制
十进制转化为n进制,每一位的值都是除以n的余数.
注意:
- 考虑0和负数
public class n504 {
public String convertToBase7(int num) {
//先判断正负
boolean pos = num >= 0;
num = Math.abs(num);
StringBuilder s = new StringBuilder();
while(num > 0){
int i = num % 7;
num = num / 7;
s.insert(0, i+"");
}
if(!pos) s.insert(0,"-");
return s.toString();
}
}
小数的进制转化
题目描述 编写程序实现将任意10进制正小数m转换成n进制的正小数,小数点后保留10位小数。
解答要求 时间限制:1000ms,
内存限制:64MB 输入 输入包含两个数m,n,用空格隔开。输入包含多组测试,当m,n都为0时输入结束。 Limits:
0.0000009<m<1 1<n<10
小数的转换过程:小数不断地乘n取整,注意double取整数的方法intvalue
public class n5 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
while(true){
double m = s.nextDouble();
int n = s.nextInt();
StringBuilder sb = new StringBuilder();
if(m == 0 && n == 0) {
System.out.println(sb);
break;
}
sb.append("0.");
for(int i : getNum(m,n)){
sb.append(i);
}
System.out.println(sb);
}
}
private static int[] getNum(double m, int n) {
int[] arr = new int[10];
double t = (double)n;
for (int i = 0; i < 10; i++) {
m*=n;
arr[i] = new Double(m).intValue();
if(m > 1.0) m-=arr[i];
}
return arr;
}
}
1. 7 进制
504. Base 7 (Easy)
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);
}
2. 16 进制
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();
}
3. 26 进制
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');
}
class Solution {
public String convertToTitle(int n) {
//26进制问题
StringBuilder sb = new StringBuilder();
while(n != 0){
n--;
sb.append((char)('A' + n%26 ) + "");
n /= 26;
}
return sb.reverse().toString();
}
}
阶乘
1. 统计阶乘尾部有多少个 0
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 + …
class Solution {
public int trailingZeroes(int n) {
int res = 0;
while(n > 0){
res += n / 5;
//继续算有多少个25 ...
n /= 5;
}
return res;
}
}
字符串加法减法
1. 二进制加法
67. Add Binary (Easy)
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();
}
2. 字符串加法
415. Add Strings (Easy)
字符串的值为非负整数。
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();
}
相遇问题
1. 改变数组元素使所有的数组元素都相等
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;
}
多数投票问题
1. 数组中出现次数多于 n / 2 的元素
169. Majority Element (Easy)
先对数组排序,最中间那个数出现次数一定多于 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;
}
其它
1. 平方数
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;
}
2. 3 的 n 次方
326. Power of Three (Easy)
public boolean isPowerOfThree(int n) {
return n > 0 && (1162261467 % n == 0);
}
3. 乘积数组
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;
}
4. 找出数组中的乘积最大的三个数
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);
}
模拟运算
分数到小数
class Solution {
public String fractionToDecimal(int numerator, int denominator) {
if (denominator == 0) {
return null;
}
if (numerator == 0) {
return "0";
}
StringBuffer sb = new StringBuffer();
// 先计算符号
if (numerator < 0 ^ denominator < 0) {
sb.append("-");
}
// 考虑溢出的情况-2147483648, 取绝对值之后还是-2147483648
long numeratorL = Math.abs((long)numerator);
long denominatorL = Math.abs((long)denominator);
// 计算整数部分
long tmp = numeratorL / denominatorL;
sb.append(String.valueOf(tmp));
// 小数部分
long remainder = numeratorL % denominatorL;
if (remainder == 0) {
return sb.toString();
}
sb.append(".");
// 记录余数所处的位置
Map<Long, Integer> remainderIndexMap = new HashMap();
while (remainder != 0) {
if (remainderIndexMap.containsKey(remainder)) {
int index = remainderIndexMap.get(remainder);
sb.insert(index, "(");
sb.append(")");
break;
}
remainderIndexMap.put(remainder, sb.length());
remainder *= 10;
sb.append(remainder / denominatorL);
remainder %= denominatorL;
}
return sb.toString();
}
}
作者:si-zhu-ruo-shui
链接:https://leetcode-cn.com/problems/fraction-to-recurring-decimal/solution/ji-lu-yu-shu-de-wei-zhi-fa-ding-wei-xun-huan-wei-z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
那些巧妙的算法
摩尔投票算法
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
Integer candidate = null;
for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}
return candidate;
}
}
埃拉托色尼筛
int countPrimes(int n) {
boolean[] isPrim = new boolean[n];
Arrays.fill(isPrim, true);
for (int i = 2; i * i < n; i++)
if (isPrim[i])
for (int j = i * i; j < n; j += i)
isPrim[j] = false;
int count = 0;
for (int i = 2; i < n; i++)
if (isPrim[i]) count++;
return count;
}
数学问题多多积累吧
坐标
223. 矩形面积
1.什么时候无重叠?
四种情况
2.有重叠的边界怎么算?
比如左边界:就是两个左下角横坐标的最小值
public int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
//求第一个矩形的面积
int length1 = C - A;
int width1 = D - B;
int area1 = length1 * width1;
//求第二个矩形的面积
int length2 = G - E;
int width2 = H - F;
int area2 = length2 * width2;
// 没有重叠的情况
if (E >= C || G <= A || F >= D || H <= B) {
return area1 + area2;
}
//确定右边
int x1 = Math.min(C, G);
//确定左边
int x2 = Math.max(E, A);
int length3 = x1 - x2;
//确定上边
int y1 = Math.min(D, H);
//确定下边
int y2 = Math.max(F, B);
int width3 = y1 - y2;
int area3 = length3 * width3;
return area1 + area2 - area3;
}
作者:windliang
链接:https://leetcode-cn.com/problems/rectangle-area/solution/xiang-xi-tong-su-de-si-lu-fen-xi-by-windliang-4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
基本类型的转换方法
一、string 和int之间的转换
1、string转换成int :Integer.valueOf(“12”)
(2020.2.19,用这个出问题了,没有搞懂为什么出了问题。找了另外一种字符型转为int的方法,char-int:
1 = ‘1’ - ‘0’。字符型1减去‘0’的ascii码,即为数字1.
2、int转换成string : String.valueOf(12)
二、char和int之间的转换
1、将int转换成char:
第一步:String str=String.valueOf(‘2’)
第二步:char c = str.charAt(0)
2、将char/String转换成int
Integer.valueOf(str) 或者Integer.PaseInt(str)
备注:Integer.valueOf返回的是Integer对象,Integer.paseInt返回的是int
三、Int和double之间的转换
1.int转换为double:强制类型转换
Double d = (double)123;
2.double转换为int:不能用强制类型转换
int i = new Double(0.123).intValue();
有关各个位数的操作
258. 各位相加
迭代和递归都可以
class Solution {
public int addDigits(int num) {
//方法1:将num转化为数组
//迭代
while(num >= 10){
int next = 0;
while(num != 0){
next += num % 10;
num /= 10;
}
num = next;
}
return num;
}
}
public int addDigits(int num) {
if (num < 10) {
return num;
}
int next = 0;
while (num != 0) {
next = next + num % 10;
num /= 10;
}
return addDigits(next);
}
作者:windliang
链接:https://leetcode-cn.com/problems/add-digits/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-5-7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
有关因数的问题
class Solution {
public boolean isUgly(int num) {
//我的思路:依次5,3,1,2,直至除近
if(num == 0) return false;
while (num % 5 == 0) num /= 5;
while (num % 3 == 0) num /= 3;
while (num % 2 == 0) num /= 2;
if(num != 1) return false;
return true;
}
}
264. 丑数 II
我一开始想的非常致命的错误:
class Solution {
public int nthUglyNumber(int n) {
int a = 0, b = 0, c = 0;
int[] dp = new int[n];
dp[0] = 1;
for(int i = 1; i < n; i++) {
int n2 = dp[a] * 2, n3 = dp[b] * 3, n5 = dp[c] * 5;
dp[i] = Math.min(Math.min(n2, n3), n5);
if(dp[i] == n2) a++;
if(dp[i] == n3) b++;
if(dp[i] == n5) c++;
}
return dp[n - 1];
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/chou-shu-lcof/solution/mian-shi-ti-49-chou-shu-dong-tai-gui-hua-qing-xi-t/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
求众数
求出现超过一班的数
摩尔投票法
求出现超过n/3的数
需要有两个候选人
class Solution {
public List<Integer> majorityElement(int[] nums) {
//摩尔投票,两个候选人,最后看谁超过n/3
List<Integer> res = new ArrayList<>();
if(nums==null || nums.length <= 0) return res;
int cand1 = 0; int count1 = 0;
int cand2 = 0; int count2 = 0;
for (int i = 0; i < nums.length; i++) {
int t = nums[i];
if(t==cand1) {
count1++;
continue;
}
else if(t==cand2) {
count2++;
continue;
}
if(count1 == 0) {
cand1 = t;
count1++;
continue;
}
if (count2 == 0) {
cand2 =t;
count2++;
continue;
}
count1--;
count2--;
}
count1 = 0;
count2 = 0;
for (int num : nums) {
if (cand1 == num) count1++;
else if (cand2 == num) count2++;
}
if (count1 > nums.length / 3) res.add(cand1);
if (count2 > nums.length / 3) res.add(cand2);
return res;
}
}
表达式
在下面这篇中介绍了较多的表达式的计算
https://blog.youkuaiyun.com/weixin_42886721/article/details/106954964
注意:
我总结的递归的三要素:结束条件,返回值,当前层的操作
在本题中:
- 递归的终点是只有一个数字且没有符号
- 递归的返回值是一个列表
- 当前层的操作:将上一层的列表中的元素依次组合
class Solution {
private static Map<String, List<Integer>> map = new HashMap<>();
public List<Integer> diffWaysToCompute(String input) {
//分析:几个运算符就有几个括号
//主函数里调用一个拆分的函数
return split(input);
}
public static List<Integer> split(String input){
if(map.keySet().contains(input)){
return map.get(input);
}
List<Integer> result = new LinkedList<>();
//返回条件
if(!input.contains("+")&!input.contains("-")&!input.contains("*")){
result.add(Integer.valueOf(input));
return result;
}
for(int i = 0; i < input.length(); i++){
if(input.charAt(i) == '+' || input.charAt(i) == '-' || input.charAt(i) == '*'){
for(Integer left : split(input.substring(0,i))){
for(Integer right : split(input.substring(i+1,input.length()))){
if(input.charAt(i)=='+'){
result.add(left+right);
}
if(input.charAt(i)=='-'){
result.add(left-right);
}
if(input.charAt(i)=='*'){
result.add(left*right);
}
}
}
}
}
map.put(input, result);
return result;
}
}
1.只出现一次的数字 II
- 只出现一次的数字 II](https://leetcode-cn.com/problems/single-number-ii/)
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
https://leetcode-cn.com/problems/single-number-ii/solution/single-number-ii-mo-ni-san-jin-zhi-fa-by-jin407891/
先考虑一比特数的情况,输入1和0的状态变化如下.三种状态用两位来表示
第一位计算方法如下
if two == 0:
if n == 0:
one = one
if n == 1:
one = ~one
if two == 1:
one = 0
可简化为
one = one ^ n & ~two
同理第二位是
two = two ^ n & ~one
代码为:
class Solution {
public int singleNumber(int[] nums) {
int ones = 0, twos = 0;
for(int num : nums){
ones = (ones ^ num) & ~twos;
twos = (twos ^ num) & ~ones;
}
return ones;
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/single-number-ii/solution/single-number-ii-mo-ni-san-jin-zhi-fa-by-jin407891/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
实现数据结构
常数时间插入、删除和获取随机元素
380. 常数时间插入、删除和获取随机元素
只需要一个arrayList和一个hashmap就可以实现
关键在删除:
public boolean remove(int val) {
if (! dict.containsKey(val)) return false;
// move the last element to the place idx of the element to delete
int lastElement = list.get(list.size() - 1);
int idx = dict.get(val);
list.set(idx, lastElement);
dict.put(lastElement, idx);
// delete the last element
list.remove(list.size() - 1);
dict.remove(val);
return true;
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/insert-delete-getrandom-o1/solution/chang-shu-shi-jian-cha-ru-shan-chu-he-huo-qu-sui-j/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
只需要将list的最后一个元素与将要删除的元素换一下,然后将最后这个元素删除即可.