目录
1. 二分法
private static int dichotomy(List<Integer> list, Integer target) {
int left = 0, right = list.size() - 1;
while(left <= right) {
int middle = (left + right)/2;
if (list.get(middle).equals(target)) {
return middle;
} else if (list.get(middle) > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return -1;
}
public int binarySearch(int[] nums, int target, boolean lower) {
int left = 0, right = nums.length - 1, ans = nums.length;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
2.并查集
private static class UnionFind {
private int[] parent;
/**
* 以 i 为根结点的子树的高度(引入了路径压缩以后该定义并不准确)
*/
private int[] rank;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; ++i) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
return parent[x] != x ? parent[x] = find(parent[x]) : x;
}
public void union(int x, int y) {
int xRoot = find(x);
int yRoot = find(y);
if (xRoot == yRoot) {
return;
}
if (rank[xRoot] == rank[yRoot]) {
parent[xRoot] = yRoot;
rank[yRoot]++;
} else if (rank[xRoot] < rank[yRoot]) {
parent[xRoot] = yRoot;
} else {
parent[yRoot] = xRoot;
}
//parent[find(x)] = find(y);
}
}
3. 线段树
(1)建立2N长度的树:tree[i]=tree[2i]+tree[2i+1];
(2)更新:pos更新,循环左找右, 右找左,求pos/2,往前找循环更新;
(3)求和:找到左偶数位,右奇数位除2(否则累加,加减除2)
static class NumArray { //线段树
int[] tree;
int n;
public NumArray(int[] nums) {
if (nums.length > 0) {
n = nums.length;
tree = new int[n * 2];
buildTree(nums);
}
}
private void buildTree(int[] nums) {
for (int i = n, j = 0; i < 2 * n; i++, j++)
tree[i] = nums[j];
for (int i = n - 1; i > 0; --i)
tree[i] = tree[i * 2] + tree[i * 2 + 1]; //even + odd
}
void update(int pos, int val) {
pos += n;
tree[pos] = val;
while (pos > 0) {
int left = pos;
int right = pos;
if (pos % 2 == 0) {
right = pos + 1;
} else {
left = pos - 1;
}
// parent is updated after child is updated
tree[pos / 2] = tree[left] + tree[right];
pos /= 2;
}
}
public int sumRange(int l, int r) {
// get leaf with value 'l'
l += n;
// get leaf with value 'r'
r += n;
int sum = 0;
while (l <= r) {
if ((l % 2) == 1) { //left add only is odd number
sum += tree[l];
l++;
}
if ((r % 2) == 0) { // right add only is even number
sum += tree[r];
r--;
}
l /= 2;
r /= 2;
}
return sum;
}
}
4.单调栈
private static int[] dailyTemperaturesDeque(int[] temperatures) {
Deque<Integer> deque = new LinkedList<>();
int[] result = new int[temperatures.length];
deque.add(0);
for (int i = 1; i < temperatures.length; i++) {
while (!deque.isEmpty() &&
temperatures[i] > temperatures[deque.getLast()]){
int index = deque.pollLast();
result[index] = i - index;
}
deque.add(i);
}
return result;
}
5.递归
(1)DFS
public static void dfs(char[][] grid, int i, int j) {
//边界,跳出,搜索到的条件
if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') {
return;
}
grid[i][j] = '0';
dfs(grid, i + 1, j);
dfs(grid, i - 1, j);
dfs(grid, i, j + 1);
dfs(grid, i, j - 1);
}
(2)BFS
public static int dfs(int n) {///标准bfs
int result = 0;
Set<Integer> queue = new HashSet<>();
queue.add(n);
while (queue.size() > 0) {
result++;
Set<Integer> next_queue = new HashSet<>();//bfs重在分层
for (Integer thisLevel : queue) { // 处理这层
for (int i = 1; i * i <= thisLevel; i++) {
if (thisLevel.equals(i*i)) {
return result;
} else {
next_queue.add(thisLevel - i*i); //生成下一层
}
}
}
queue = next_queue;
}
return -1;
}
6.排序:
直接上个Comparator,实用。
static class Room {
public int roomId = 0;
public Room(int id) {
roomId = id;
}
}
public static void main(String[] args) {
List<Room> list = new ArrayList<>();
list.add(new Room(1));
list.add(new Room(2));
list.add(new Room(3));
Collections.sort(list, (x1, x2) -> { //1 - 2: 升序
return x1.roomId - x2.roomId;
});
Collections.sort(list, new Comparator<Room>() {
@Override
public int compare(Room o1, Room o2) {
return calculateMethod(o1, o2);
}
});
list.stream().map(x -> x.roomId).forEach(System.out::print);
}
private static int calculateMethod(Room r1, Room r2) {
return r2.roomId - r1.roomId; //逆序
}
7.滑动窗口
public int lengthOfLongestSubstring(String s) {
if(s.length()<2) {
return s.length();
}
int l=0, h=1;//常见滑动起点
int most =0;
while (h < s.length()) {
String gets = s.substring(l, h);
if(gets.contains(String.valueOf(s.charAt(h)))) {
most = Math.max(most, gets.length());
l = l+gets.indexOf(s.charAt(h)) + 1; // 左侧窗口滑动条件
} else {
most = Math.max(most, gets.length()+1);
}
h++; //滑动窗口常规框架
}
return most;
}
8. 动态规划
public static int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount +1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (coin <= i) {
dp[i] = Math.min(dp[i], dp[i-coin] + 1);//转移方程最重要
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
9.差分
一加,一减,然后求前缀和
int[] years = new int[101]; //统计1950-2050的人口数量
final int offset = 1950; //下标模拟年份,偏移值1950
for (int[] log : logs) {
years[log[0] - offset]++; //一加, 一减是关键,减是为了求前缀和是加上
years[log[1] - offset]--;
}
int ans = 0;
for (int i = 1; i < years.length; i++) { //对差分数组求前缀和
years[i] += years[i - 1];
if (years[i] > years[ans]) ans = i;
}
return ans + offset;
10.前缀和
前缀和i - 前缀和j = i到j的和;
11.贪心
一般使用排序,或双指针,重思路。
12.字典树
将路径做成树状结构
13.有向无环图
费头发