算法笔记
1.判断奇数偶数
为真为奇数
(k & 1) == 1;
2.double计算比int要慢,所以中间记录的值要设成int型,最后返回的时候再转换成double
int x=10;
return 1.0*x;
迭代器
Iterator<类型> iterator=迭代对象.iterator();
分割符
String s="sdj-kad";
for (String s1 : s.split("-")) {
System.out.println(s1);
}
结果:
sdj
kad
String s="sdj-ka-d";
for (String s1 : s.split("-",2)) {
System.out.println(s1);
}
结果:
sdj
ka-d
反转链表(拉不拉东)
ListNode reverse(ListNode head) {
if (head.next == null) return head;
ListNode last = reverse(head.next);
head.next.next = head;
head.next = null;
return last;
}
值得一提的时候,在 Java 中,以下代码会 超时。这就不得不讲一讲 Java 中的 算术右移 和 逻辑右移 。
算术右移 >> :舍弃最低位,高位用符号位填补;
逻辑右移 >>> :舍弃最低位,高位用 0 填补。
那么对于负数而言,其二进制最高位是 1,如果使用算术右移,那么高位填补的仍然是 1。也就是 n 永远不会为 0。所以下面的代码会超时 TLE。
Java
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
while (n != 0) {
count += n & 1;
n >>= 1;
}
return count;
}
}
在 Java 中需要使用逻辑右移,即 >>> ,while 的判断条件才能是 n != 0 。正确的代码如下:
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
while (n != 0) {
count += n & 1;
n >>>= 1;
}
return count;
}
}
# bit操作
& 符号,x & y ,会将两个十进制数在二进制下进行与运算
| 符号,x | y ,会将两个十进制数在二进制下进行或运算
^ 符号,x ^ y ,会将两个十进制数在二进制下进行异或运算
<< 符号,x << y 左移操作,最右边用 0 填充
>> 符号,x >> y 右移操作,最左边用 0 填充
~ 符号,~x ,按位取反操作,将 x 在二进制下的每一位取反
# 整数集合set位运算
# 整数集合做标志时,比如回溯时的visited标志数组
vstd 访问 i :vstd | (1 << i)
vstd 离开 i :vstd & ~(1 << i)
vstd 不包含 i : not vstd & (1 << i)
并集 :A | B
交集 :A & B
全集 :(1 << n) - 1
补集 :((1 << n) - 1) ^ A
子集 :(A & B) == B
判断是否是 2 的幂 :A & (A - 1) == 0
最低位的 1 变为 0 :n &= (n - 1)
最低位的 1:A & (-A),最低位的 1 一般记为 lowbit(A)
回溯算法:
回溯法是一种算法思想,而递归是一种编程方法,回溯法可以用递归来实现。
回溯法的整体思路是:搜索每一条路,每次回溯是对具体的一条路径而言的。对当前搜索路径下的的未探索区域进行搜索,则可能有两种情况:
当前未搜索区域满足结束条件,则保存当前路径并退出当前搜索;
当前未搜索区域需要继续搜索,则遍历当前所有可能的选择:如果该选择符合要求,则把当前选择加入当前的搜索路径中,并继续搜索新的未探索区域。
上面说的未搜索区域是指搜索某条路径时的未搜索区域,并不是全局的未搜索区域。
回溯法搜所有可行解的模板一般是这样的:
res = []
path = []
def backtrack(未探索区域, res, path):
if path 满足条件:
res.add(path) # 深度拷贝
# return # 如果不用继续搜索需要 return
for 选择 in 未探索区域当前可能的选择:
if 当前选择符合要求:
path.add(当前选择)
backtrack(新的未探索区域, res, path)
path.pop()
backtrack 的含义是:未探索区域中到达结束条件的所有可能路径,path 变量是保存的是一条路径,res 变量保存的是所有搜索到的路径。所以当「未探索区域满足结束条件」时,需要把 path 放到结果 res 中。
path.pop() 是啥意思呢?它是编程实现上的一个要求,即我们从始至终只用了一个变量 path,所以当对 path 增加一个选择并 backtrack 之后,需要清除当前的选择,防止影响其他路径的搜索。
求最大公约数
//这个函数就是求最大公约数
public static int gcd(int a, int b) {;
if (b == 0)
return a;
//如果一开始a小于b,那么下一个次的迭代就是互换顺序,往后的a都大于b
return gcd(b, a % b);
}
数组去重通解&&双指针解法
public int removeDuplicates(int[] nums) {
return process(nums, 2);
}
//k代表保留个数,此时就是保留两个chon
int process(int[] nums,int k){
int u=0;
for (int x : nums) {
if(u<k||nums[u-k]!=x){
nums[u++]=x;
}
}
return u;
}
看到要求两个整数 x,y 如何拼接得到结果更大时,就想到先转字符串,然后比较 x+y 和 y+x。这是经验了。
public String largestNumber(int[] nums) {
int n = nums.length;
String[] ss = new String[n];
for (int i = 0; i < n; i++) ss[i] = "" + nums[i];
Arrays.sort(ss,(a,b)->{
String sa=a+b;
String sb=b+a;
return sb.compareTo(sa);
});
StringBuilder sb = new StringBuilder();
for (String s : ss) sb.append(s);
int len = sb.length();
int k = 0;
while (k < len - 1 && sb.charAt(k) == '0') k++;
return sb.substring(k);
}
无穷大量可用0x3f3f3f3f来定义
int INF = 0x3f3f3f3f;
异或基本知识!
- x ⊕ x = 0
x ⊕ y = y ⊕ x
(x⊕ y) ⊕ z = x ⊕ (y ⊕z)
x ⊕ y ⊕ y = x
对于任意的 i 属于整数,有4i ⊕ (4i+1) ⊕ (4i+2) ⊕ (4i+3)=0