开设这个专栏主要是在面试中算法避免一些踩坑,首先,经过我本人亲自实践+网上各位大佬总结:
当我们刷算法题的时候,比如力扣、牛客这些网站,很多的题目只需要我们写出函数体(核心代码),平台就可以自动帮助我们补齐输入输出,进行调试,但,在笔试和面试中,往往需要自己写出可以运行的完整代码(ACM模式),这个时候,需要我们去了解一下自己所使用的语言下的输入输出如何去设计。
Leetcode hot100题解以及平时学习的一些算法模板以及例题全部放到云盘,欢迎大家获取
https://www.123pan.com/s/e7ipTd-RUh5H.html
核心代码模式与ACM模式 当我们刷算法题的时候,比如力扣、牛客这些网站,很多的题目只需要我们写出函数体(核心代码),平台就可以自动帮助我们补齐输入输出,进行调试,但,在笔试和面试中,往往需要自己写出可以运行的完整代码(ACM模式),这个时候,需要我们去了解一下自己所使用的语言下的输入输出如何去设计。
首先给出几个注意事项:
1.笔试平台用的比较多的,比如牛客,赛码,可以提前去熟悉熟悉上面的操作。
2.有些笔试,需要自己写输入输出,有些,则不需要,但我们必须要把输入输出搞懂,这样就不怕是什么类型的笔试了,而且输入输出本身是不难的,学习一下就可以完全掌握。最好不要出现,算法题的核心思路会写,卡在了输入输出上,这样就很难受了。
3.有些笔试,还会让大伙自己设计测试用例,这个平时练习的时候也可以注意一下,主要核心的思想就是测试用例设计的几个原则。
4.不仅仅是笔试,有些面试,也会要求你写输入输出和测试用例。
面试手撕代码的几种形式 1.平台类
去面试官给定的平台上去面试,上面可以编写代码,调试和运行,这些平台有的写好了函数框架,有的是白板,需要自己写全部内容
2.自己的IDE
面试官要求候选人打开自己的ide,并共享桌面进行编写,这种肯定是要自己写全输入输出了
3.要求补齐测试用例
有些面试官,比如微软的面试官,可能会让你写完代码后,自己设计尽可能全面的测试用例,对你编写的代码进行测试。
java处理输入输出 然后我是javaer,所以就给出java的acm模式处理输入输出的方式:
因为我之前参加算法比赛中,一般都是对时间卡的比较严格,所以都是用java的快读快写,但是笔试或者面试中手撕,一般不会要求那么严格,或者测试用例比较少,所以我么们直接使用Scanner就完全够用了
情况1: 全都是数字的输入,每行数字个数不定 情况2:每行第一个数字为确定的数字n,后面跟着n个数字 情况3: 每行确定有n个数字的情况 情况4: 第一行是一个数字n, 第二行是n个字符串 避坑点 全局只能new出一个Scanner对象,如果有多个,会出现不可预见的问题! 关于next() 函数、nextInt()函数、nextLine()函数: nextInt(): 只读取整数类型数据, nextInt()在读取完输入后把光标放在读取数据的同一行,该数据的后面。
next(): 只读取到空格,不能读取被空格分开的两个单词(也就是不能读取空格),并且在读取完后把光标放在读取数据的同一行,该数据的后面。(同上)
nextLine(): 读取整行的数据包括单词间的空格,到回车结束(也就是从开始读一整行包括回车),读取结束后,光标放在下一行开头。
总结: 不论是acm模式,还是核心代码模式,面试官考察的还是算法能力,要提高算法能力,说再多也没用,练就有效,像leetcode,牛客,洛谷,都是非常好的刷题网站,如果是零基础,并且要用java去应对笔试,我推荐去b站上搜索左程云老师,先入门,再刷题,每天坚持,无问西东。
各类算法模板(只提供JAVA): 只记录比较死的模板。各类算法模板学习自–左程云老师
更多java模板以及例题我已经上传至云盘,欢迎获取 https://www.123pan.com/s/e7ipTd-RUh5H.html
1.选择排序、插入排序、冒泡排序 public class SelectBubbleInsert { public static void swap (int [] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } public static void selectionSort (int [] arr) { if (arr == null || arr.length < 2 ) { return ; } for (int minIndex, i = 0 ; i < arr.length - 1 ; i++) { minIndex = i; for (int j = i + 1 ; j < arr.length; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } swap(arr, i, minIndex); } } public static void bubbleSort (int [] arr) { if (arr == null || arr.length < 2 ) { return ; } for (int end = arr.length - 1 ; end > 0 ; end--) { for (int i = 0 ; i < end; i++) { if (arr[i] > arr[i + 1 ]) { swap(arr, i, i + 1 ); } } } } public static void insertionSort (int [] arr) { if (arr == null || arr.length < 2 ) { return ; } for (int i = 1 ; i < arr.length; i++) { for (int j = i - 1 ; j >= 0 && arr[j] > arr[j + 1 ]; j--) { swap(arr, j, j + 1 ); } } } }
2.二叉树及其三种序 public static class TreeNode { public int val; public TreeNode left; public TreeNode right; public TreeNode (int v) { val = v; } } public static void preOrder (TreeNode head) { if (head == null ) { return ; } System.out.print(head.val + " " ); preOrder(head.left); preOrder(head.right); } public static void inOrder (TreeNode head) { if (head == null ) { return ; } inOrder(head.left); System.out.print(head.val + " " ); inOrder(head.right); } public static void posOrder (TreeNode head) { if (head == null ) { return ; } posOrder(head.left); posOrder(head.right); System.out.print(head.val + " " ); } public static void preOrder (TreeNode head) { if (head != null ) { Stack<TreeNode> stack = new Stack <>(); stack.push(head); while (!stack.isEmpty()) { head = stack.pop(); System.out.print(head.val + " " ); if (head.right != null ) { stack.push(head.right); } if (head.left != null ) { stack.push(head.left); } } System.out.println(); } } public static void inOrder (TreeNode head) { if (head != null ) { Stack<TreeNode> stack = new Stack <>(); while (!stack.isEmpty() || head != null ) { if (head != null ) { stack.push(head); head = head.left; } else { head = stack.pop(); System.out.print(head.val + " " ); head = head.right; } } System.out.println(); } } public static void posOrderTwoStacks (TreeNode head) { if (head != null ) { Stack<TreeNode> stack = new Stack <>(); Stack<TreeNode> collect = new Stack <>(); stack.push(head); while (!stack.isEmpty()) { head = stack.pop(); collect.push(head); if (head.left != null ) { stack.push(head.left); } if (head.right != null ) { stack.push(head.right); } } while (!collect.isEmpty()) { System.out.print(collect.pop().val + " " ); } System.out.println(); } }
3.归并排序 public static int [] sortArray(int [] nums) { if (nums.length > 1 ) { mergeSort2(nums); } return nums; } public static int MAXN = 50001 ;public static int [] help = new int [MAXN]; public static void mergeSort1 (int [] arr) { sort(arr, 0 , arr.length - 1 ); } public static void sort (int [] arr, int l, int r) { if (l == r) { return ; } int m = (l + r) / 2 ; sort(arr, l, m); sort(arr, m + 1 , r); merge(arr, l, m, r); } public static void mergeSort2 (int [] arr) { int n = arr.length; for (int l, m, r, step = 1 ; step < n; step <<= 1 ) { l = 0 ; while (l < n) { m = l + step - 1 ; if (m + 1 >= n) { break ; } r = Math.min(l + (step << 1 ) - 1 , n - 1 ); merge(arr, l, m, r); l = r + 1 ; } } } public static void merge (int [] arr, int l, int m, int r) { int i = l; int a = l; int b = m + 1 ; while (a <= m && b <= r) { help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++]; } while (a <= m) { help[i++] = arr[a++]; } while (b <= r) { help[i++] = arr[b++]; } for (i = l; i <= r; i++) { arr[i] = help[i]; } }
4.快速排序 public static int [] sortArray(int [] nums) { if (nums.length > 1 ) { quickSort(nums, 0 , nums.length - 1 ); } return nums; } public static void quickSort (int [] arr, int l, int r) { if (l >= r) { return ; } int x = arr[l + (int ) (Math.random() * (r - l + 1 ))]; partition(arr, l, r, x); int left = first; int right = last; quickSort(arr, l, left - 1 ); quickSort(arr, right + 1 , r); } public static int first, last; public static void partition (int [] arr, int l, int r, int x) { first = l; last = r; int i = l; while (i <= last) { if (arr[i] == x) { i++; } else if (arr[i] < x) { swap(arr, first++, i++); } else { swap(arr, i, last--); } } } public static void swap (int [] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
5.含有嵌套的表达式求值 public static int calculate (String str) { where = 0 ; return f(str.toCharArray(), 0 ); } public static int where; public static int f (char [] s, int i) { int cur = 0 ; ArrayList<Integer> numbers = new ArrayList <>(); ArrayList<Character> ops = new ArrayList <>(); while (i < s.length && s[i] != ')' ) { if (s[i] >= '0' && s[i] <= '9' ) { cur = cur * 10 + s[i++] - '0' ; } else if (s[i] != '(' ) { push(numbers, ops, cur, s[i++]); cur = 0 ; } else { cur = f(s, i + 1 ); i = where + 1 ; } } push(numbers, ops, cur, '+' ); where = i; return compute(numbers, ops); } public static void push (ArrayList<Integer> numbers, ArrayList<Character> ops, int cur, char op) { int n = numbers.size(); if (n == 0 || ops.get(n - 1 ) == '+' || ops.get(n - 1 ) == '-' ) { numbers.add(cur); ops.add(op); } else { int topNumber = numbers.get(n - 1 ); char topOp = ops.get(n - 1 ); if (topOp == '*' ) { numbers.set(n - 1 , topNumber * cur); } else { numbers.set(n - 1 , topNumber / cur); } ops.set(n - 1 , op); } } public static int compute (ArrayList<Integer> numbers, ArrayList<Character> ops) { int n = numbers.size(); int ans = numbers.get(0 ); for (int i = 1 ; i < n; i++) { ans += ops.get(i - 1 ) == '+' ? numbers.get(i) : -numbers.get(i); } return ans; }
6.最大公约数和最小公倍数 public static long gcd (long a, long b) { return b == 0 ? a : gcd(b, a % b); } public static long lcm (long a, long b) { return (long ) a / gcd(a, b) * b; }
7.返回无序数组中累加和为给定值的最长子数组长(一维构建前缀信息) import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StreamTokenizer;import java.util.HashMap;public class Code02_LongestSubarraySumEqualsAim { public static int MAXN = 100001 ; public static int [] arr = new int [MAXN]; public static int n, aim; public static HashMap<Integer, Integer> map = new HashMap <>(); public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int ) in.nval; in.nextToken(); aim = (int ) in.nval; for (int i = 0 ; i < n; i++) { in.nextToken(); arr[i] = (int ) in.nval; } out.println(compute()); } out.flush(); out.close(); br.close(); } public static int compute () { map.clear(); map.put(0 , -1 ); int ans = 0 ; for (int i = 0 , sum = 0 ; i < n; i++) { sum += arr[i]; if (map.containsKey(sum - aim)) { ans = Math.max(ans, i - map.get(sum - aim)); } if (!map.containsKey(sum)) { map.put(sum, i); } } return ans; } }
8.一维差分 例题链接
public static int [] corpFlightBookings(int [][] bookings, int n) { int [] cnt=new int [n+2 ]; for (int [] book : bookings) { cnt[book[0 ]]+=book[2 ]; cnt[book[1 ]+1 ]-=book[2 ]; } for (int i = 1 ; i < cnt.length; i++) { cnt[i]+=cnt[i-1 ]; } int [] ans=new int [n]; for (int i = 0 ; i < ans.length; i++) { ans[i]=cnt[i+1 ]; } return ans; }
9.二维构建前缀信息 public int [][] sum; public NumMatrix (int [][] matrix) { int n = matrix.length; int m = matrix[0 ].length; sum = new int [n + 1 ][m + 1 ]; for (int a = 1 , c = 0 ; c < n; a++, c++) { for (int b = 1 , d = 0 ; d < m; b++, d++) { sum[a][b] = matrix[c][d]; } } for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { sum[i][j] += sum[i][j - 1 ] + sum[i - 1 ][j] - sum[i - 1 ][j - 1 ]; } } } public int sumRegion (int a, int b, int c, int d) { c++; d++; return sum[c][d] - sum[c][b] - sum[a][d] + sum[a][b]; }
10.二维差分 import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StreamTokenizer;public class Code03_DiffMatrixNowcoder { public static int MAXN = 1005 ; public static int MAXM = 1005 ; public static long [][] diff = new long [MAXN][MAXM]; public static int n, m, q; public static void add (int a, int b, int c, int d, int k) { diff[a][b] += k; diff[c + 1 ][b] -= k; diff[a][d + 1 ] -= k; diff[c + 1 ][d + 1 ] += k; } public static void build () { for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { diff[i][j] += diff[i - 1 ][j] + diff[i][j - 1 ] - diff[i - 1 ][j - 1 ]; } } } public static void clear () { for (int i = 1 ; i <= n + 1 ; i++) { for (int j = 1 ; j <= m + 1 ; j++) { diff[i][j] = 0 ; } } } public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int ) in.nval; in.nextToken(); m = (int ) in.nval; in.nextToken(); q = (int ) in.nval; for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { in.nextToken(); add(i, j, i, j, (int ) in.nval); } } for (int i = 1 , a, b, c, d, k; i <= q; i++) { in.nextToken(); a = (int ) in.nval; in.nextToken(); b = (int ) in.nval; in.nextToken(); c = (int ) in.nval; in.nextToken(); d = (int ) in.nval; in.nextToken(); k = (int ) in.nval; add(a, b, c, d, k); } build(); for (int i = 1 ; i <= n; i++) { out.print(diff[i][1 ]); for (int j = 2 ; j <= m; j++) { out.print(" " + diff[i][j]); } out.println(); } clear(); } out.flush(); out.close(); br.close(); } }
11.滑动窗口 以“累加和大于等于target的最短子数组长度 ”为例
public static int minSubArrayLen (int target, int [] nums) { int ans = Integer.MAX_VALUE; for (int l = 0 , r = 0 , sum = 0 ; r < nums.length; r++) { sum += nums[r]; while (sum - nums[l] >= target) { sum -= nums[l++]; } if (sum >= target) { ans = Math.min(ans, r - l + 1 ); } } return ans == Integer.MAX_VALUE ? 0 : ans; }
12.二分答案法 以“爱吃香蕉的珂珂 ”为例
public class Code01_KokoEatingBananas { public static int minEatingSpeed (int [] piles, int h) { int l = 1 ; int r = 0 ; for (int pile : piles) { r = Math.max(r, pile); } int ans = 0 ; int m = 0 ; while (l <= r) { m = l + ((r - l) >> 1 ); if (f(piles, m) <= h) { ans = m; r = m - 1 ; } else { l = m + 1 ; } } return ans; } public static long f (int [] piles, int speed) { long ans = 0 ; for (int pile : piles) { ans += (pile + speed - 1 ) / speed; } return ans; }
13.单调栈 求每个位置左右两侧,离当前位置最近、且值严格小于/大于的位置
public static int MAXN = 1000001 ; public static int [] arr = new int [MAXN]; public static int [] stack = new int [MAXN]; public static int [][] ans = new int [MAXN][2 ]; public static int n, r; public static void compute () { r = 0 ; int cur; for (int i = 0 ; i < n; i++) { while (r > 0 && arr[stack[r - 1 ]] >= arr[i]) { cur=stack[--r]; ans[cur][0 ]=r>0 ?stack[r-1 ]:-1 ; ans[cur][1 ]=i; } stack[r++]=i; } while (r>0 ) { cur=stack[--r]; ans[cur][0 ]=r>0 ?stack[r-1 ]:-1 ; ans[cur][1 ]=-1 ; } for (int i = n-2 ; i >=0 ; i--) { if (ans[i][1 ]!=-1 &&arr[ans[i][1 ]]==arr[i]) { ans[i][1 ]=ans[ans[i][1 ]][1 ]; } }
14.单调队列 以“滑动窗口最大值 ”为例
public static int MAXN = 100001 ; public static int [] deque = new int [MAXN]; public static int h, t; public static int [] maxSlidingWindow(int [] arr, int k) { h = t = 0 ; int n = arr.length; for (int i = 0 ; i < k - 1 ; i++) { while (h < t && arr[deque[t - 1 ]] <= arr[i]) { t--; } deque[t++] = i; } int m = n - k + 1 ; int [] ans = new int [m]; for (int l = 0 , r = k - 1 ; l < m; l++, r++) { while (h < t && arr[deque[t - 1 ]] <= arr[r]) { t--; } deque[t++] = r; ans[l] = arr[deque[h]]; if (deque[h] == l) { h++; } } return ans; }
15.并查集模板 import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StreamTokenizer;public class Code02_UnionFindLuogu { public static int MAXN = 10001 ; public static int [] father = new int [MAXN]; public static int n; public static void build () { for (int i = 0 ; i <= n; i++) { father[i] = i; } } public static int find (int i) { if (i != father[i]) { father[i] = find(father[i]); } return father[i]; } public static boolean isSameSet (int x, int y) { return find(x) == find(y); } public static void union (int x, int y) { father[find(x)] = find(y); } public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int ) in.nval; build(); in.nextToken(); int m = (int ) in.nval; for (int i = 0 ; i < m; i++) { in.nextToken(); int z = (int ) in.nval; in.nextToken(); int x = (int ) in.nval; in.nextToken(); int y = (int ) in.nval; if (z == 1 ) { union(x, y); } else { out.println(isSameSet(x, y) ? "Y" : "N" ); } } } out.flush(); out.close(); br.close(); }
16.洪水填充问题 以“岛屿数量 ”为例
public static int numIslands (char [][] board) { int n = board.length; int m = board[0 ].length; int islands = 0 ; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { if (board[i][j] == '1' ) { islands++; dfs(board, n, m, i, j); } } } return islands; } public static void dfs (char [][] board, int n, int m, int i, int j) { if (i < 0 || i == n || j < 0 || j == m || board[i][j] != '1' ) { return ; } board[i][j] = 0 ; dfs(board, n, m, i - 1 , j); dfs(board, n, m, i + 1 , j); dfs(board, n, m, i, j - 1 ); dfs(board, n, m, i, j + 1 ); }
17.三种建图方式 import java.util.ArrayList;import java.util.Arrays;public class Code01_CreateGraph { public static int MAXN = 11 ; public static int MAXM = 21 ; public static int [][] graph1 = new int [MAXN][MAXN]; public static ArrayList<ArrayList<int []>> graph2 = new ArrayList <>(); public static int [] head = new int [MAXN]; public static int [] next = new int [MAXM]; public static int [] to = new int [MAXM]; public static int [] weight = new int [MAXM]; public static int cnt; public static void build (int n) { for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= n; j++) { graph1[i][j] = 0 ; } } graph2.clear(); for (int i = 0 ; i <= n; i++) { graph2.add(new ArrayList <>()); } cnt = 1 ; Arrays.fill(head, 1 , n + 1 , 0 ); } public static void addEdge (int u, int v, int w) { next[cnt] = head[u]; to[cnt] = v; weight[cnt] = w; head[u] = cnt++; } public static void directGraph (int [][] edges) { for (int [] edge : edges) { graph1[edge[0 ]][edge[1 ]] = edge[2 ]; } for (int [] edge : edges) { graph2.get(edge[0 ]).add(new int [] { edge[1 ], edge[2 ] }); } for (int [] edge : edges) { addEdge(edge[0 ], edge[1 ], edge[2 ]); } } public static void undirectGraph (int [][] edges) { for (int [] edge : edges) { graph1[edge[0 ]][edge[1 ]] = edge[2 ]; graph1[edge[1 ]][edge[0 ]] = edge[2 ]; } for (int [] edge : edges) { graph2.get(edge[0 ]).add(new int [] { edge[1 ], edge[2 ] }); graph2.get(edge[1 ]).add(new int [] { edge[0 ], edge[2 ] }); } for (int [] edge : edges) { addEdge(edge[0 ], edge[1 ], edge[2 ]); addEdge(edge[1 ], edge[0 ], edge[2 ]); } } public static void traversal (int n) { System.out.println("邻接矩阵遍历 :" ); for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= n; j++) { System.out.print(graph1[i][j] + " " ); } System.out.println(); } System.out.println("邻接表遍历 :" ); for (int i = 1 ; i <= n; i++) { System.out.print(i + "(邻居、边权) : " ); for (int [] edge : graph2.get(i)) { System.out.print("(" + edge[0 ] + "," + edge[1 ] + ") " ); } System.out.println(); } System.out.println("链式前向星 :" ); for (int i = 1 ; i <= n; i++) { System.out.print(i + "(邻居、边权) : " ); for (int ei = head[i]; ei > 0 ; ei = next[ei]) { System.out.print("(" + to[ei] + "," + weight[ei] + ") " ); } System.out.println(); } }
18.拓扑排序模板 import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StreamTokenizer;import java.util.ArrayList;import java.util.Arrays;public class Code02_TopoSortDynamicNowcoder { public static int MAXN = 200001 ; public static int [] queue = new int [MAXN]; public static int l, r; public static int [] indegree = new int [MAXN]; public static int [] ans = new int [MAXN]; public static int n, m; public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int ) in.nval; in.nextToken(); m = (int ) in.nval; ArrayList<ArrayList<Integer>> graph = new ArrayList <>(); for (int i = 0 ; i <= n; i++) { graph.add(new ArrayList <>()); } Arrays.fill(indegree, 0 , n + 1 , 0 ); for (int i = 0 , from, to; i < m; i++) { in.nextToken(); from = (int ) in.nval; in.nextToken(); to = (int ) in.nval; graph.get(from).add(to); indegree[to]++; } if (!topoSort(graph)) { out.println(-1 ); } else { for (int i = 0 ; i < n - 1 ; i++) { out.print(ans[i] + " " ); } out.println(ans[n - 1 ]); } } out.flush(); out.close(); br.close(); } public static boolean topoSort (ArrayList<ArrayList<Integer>> graph) { l = r = 0 ; for (int i = 1 ; i <= n; i++) { if (indegree[i] == 0 ) { queue[r++] = i; } } int fill = 0 ; while (l < r) { int cur = queue[l++]; ans[fill++] = cur; for (int next : graph.get(cur)) { if (--indegree[next] == 0 ) { queue[r++] = next; } } } return fill == n; } }
19.Prim算法模版 Prim与Kruskal都是用来求最小生成树的,但更推荐使用Prim,所以就只给出Prim的模板
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StreamTokenizer;import java.util.ArrayList;import java.util.PriorityQueue;public class Code02_PrimDynamic { public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { ArrayList<ArrayList<int []>> graph = new ArrayList <>(); int n = (int ) in.nval; for (int i = 0 ; i <= n; i++) { graph.add(new ArrayList <>()); } in.nextToken(); int m = (int ) in.nval; for (int i = 0 , u, v, w; i < m; i++) { in.nextToken(); u = (int ) in.nval; in.nextToken(); v = (int ) in.nval; in.nextToken(); w = (int ) in.nval; graph.get(u).add(new int [] { v, w }); graph.get(v).add(new int [] { u, w }); } PriorityQueue<int []> heap = new PriorityQueue <>((a, b) -> a[1 ] - b[1 ]); for (int [] edge : graph.get(1 )) { heap.add(edge); } boolean [] set = new boolean [n + 1 ]; int nodeCnt = 1 ; set[1 ] = true ; int ans = 0 ; while (!heap.isEmpty()) { int [] edge = heap.poll(); int next = edge[0 ]; int cost = edge[1 ]; if (!set[next]) { nodeCnt++; set[next] = true ; ans += cost; for (int [] e : graph.get(next)) { heap.add(e); } } } out.println(nodeCnt == n ? ans : "orz" ); } out.flush(); out.close(); br.close(); }
20.BFS 以“地图分析 ”为例
public static int MAXN = 101 ; public static int MAXM = 101 ; public static int [][] queue = new int [MAXN * MAXM][2 ]; public static int l, r; public static boolean [][] visited = new boolean [MAXN][MAXM]; public static int [] move = new int [] { -1 , 0 , 1 , 0 , -1 }; public static int maxDistance (int [][] grid) { l = r = 0 ; int n = grid.length; int m = grid[0 ].length; int seas = 0 ; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { if (grid[i][j] == 1 ) { visited[i][j] = true ; queue[r][0 ] = i; queue[r++][1 ] = j; } else { visited[i][j] = false ; seas++; } } } if (seas == 0 || seas == n * m) { return -1 ; } int level = 0 ; while (l < r) { level++; int size = r - l; for (int k = 0 , x, y, nx, ny; k < size; k++) { x = queue[l][0 ]; y = queue[l++][1 ]; for (int i = 0 ; i < 4 ; i++) { nx = x + move[i]; ny = y + move[i + 1 ]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny]) { visited[nx][ny] = true ; queue[r][0 ] = nx; queue[r++][1 ] = ny; } } } } return level - 1 ; }
21.dijkstra 以“最小体力消耗路径 ”为模板
public static int [] move = new int [] { -1 , 0 , 1 , 0 , -1 };public int minimumEffortPath (int [][] heights) { int n = heights.length; int m = heights[0 ].length; int [][] distance = new int [n][m]; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { distance[i][j] = Integer.MAX_VALUE; } } distance[0 ][0 ] = 0 ; boolean [][] visited = new boolean [n][m]; PriorityQueue<int []> heap = new PriorityQueue <int []>((a, b) -> a[2 ] - b[2 ]); heap.add(new int [] { 0 , 0 , 0 }); while (!heap.isEmpty()) { int [] record = heap.poll(); int x = record[0 ]; int y = record[1 ]; int c = record[2 ]; if (visited[x][y]) { continue ; } if (x == n - 1 && y == m - 1 ) { return c; } visited[x][y] = true ; for (int i = 0 ; i < 4 ; i++) { int nx = x + move[i]; int ny = y + move[i + 1 ]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny]) { int nc = Math.max(c, Math.abs(heights[x][y] - heights[nx][ny])); if (nc < distance[nx][ny]) { distance[nx][ny] = nc; heap.add(new int [] { nx, ny, nc }); } } } } return -1 ; }
22.Floyd算法 public static int MAXN = 101 ;public static int MAXM = 10001 ;public static int [] path = new int [MAXM];public static int [][] distance = new int [MAXN][MAXN];public static int n, m, ans;public static void build () { for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n; j++) { distance[i][j] = Integer.MAX_VALUE; } } } public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int ) in.nval; in.nextToken(); m = (int ) in.nval; for (int i = 0 ; i < m; i++) { in.nextToken(); path[i] = (int ) in.nval - 1 ; } build(); for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n; j++) { in.nextToken(); distance[i][j] = (int ) in.nval; } } floyd(); ans = 0 ; for (int i = 1 ; i < m; i++) { ans += distance[path[i - 1 ]][path[i]]; } out.println(ans); } out.flush(); out.close(); br.close(); } public static void floyd () { for (int bridge = 0 ; bridge < n; bridge++) { for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n; j++) { if (distance[i][bridge] != Integer.MAX_VALUE && distance[bridge][j] != Integer.MAX_VALUE && distance[i][j] > distance[i][bridge] + distance[bridge][j]) { distance[i][j] = distance[i][bridge] + distance[bridge][j]; } } } } }
23.子数组最大累加和 public static int maxSubArray1 (int [] nums) { int n = nums.length; int [] dp = new int [n]; dp[0 ] = nums[0 ]; int ans = nums[0 ]; for (int i = 1 ; i < n; i++) { dp[i] = Math.max(nums[i], dp[i - 1 ] + nums[i]); ans = Math.max(ans, dp[i]); } return ans; }
24.最长递增子序列 public static int lengthOfLIS (int [] nums) { int n = nums.length; int [] ends = new int [n]; int len = 0 ; for (int i = 0 , find; i < n; i++) { find = bs(ends, len, nums[i]); if (find == -1 ) { ends[len++] = nums[i]; } else { ends[find] = nums[i]; } } return len; } public static int bs (int [] ends, int len, int num) { int l = 0 , r = len - 1 , m, ans = -1 ; while (l <= r) { m = l+(r-l) / 2 ; if (ends[m] >= num) { ans = m; r = m - 1 ; } else { l = m + 1 ; } } return ans; }
25. 01背包 public static int compute1 () { int [][] dp = new int [n + 1 ][t + 1 ]; for (int i = 1 ; i <= n; i++) { for (int j = 0 ; j <= t; j++) { dp[i][j] = dp[i - 1 ][j]; if (j - cost[i] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[i - 1 ][j - cost[i]] + val[i]); } } } return dp[n][t]; }
26.有依赖的背包 public static int MAXN = 33001 ; public static int MAXM = 61 ; public static int [] cost = new int [MAXM]; public static int [] val = new int [MAXM]; public static boolean [] king = new boolean [MAXM]; public static int [] fans = new int [MAXM]; public static int [][] follows = new int [MAXM][2 ]; public static int [] dp = new int [MAXN]; public static int n, m; public static void clean () { for (int i = 1 ; i <= m; i++) { fans[i] = 0 ; } } public static int compute1 () { int [][] dp = new int [m + 1 ][n + 1 ]; int p = 0 ; for (int i = 1 , fan1, fan2; i <= m; i++) { if (king[i]) { for (int j = 0 ; j <= n; j++) { dp[i][j] = dp[p][j]; if (j - cost[i] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[p][j - cost[i]] + val[i]); } fan1 = fans[i] >= 1 ? follows[i][0 ] : -1 ; fan2 = fans[i] >= 2 ? follows[i][1 ] : -1 ; if (fan1 != -1 && j - cost[i] - cost[fan1] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[p][j - cost[i] - cost[fan1]] + val[i] + val[fan1]); } if (fan2 != -1 && j - cost[i] - cost[fan2] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[p][j - cost[i] - cost[fan2]] + val[i] + val[fan2]); } if (fan1 != -1 && fan2 != -1 && j - cost[i] - cost[fan1] - cost[fan2] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[p][j - cost[i] - cost[fan1] - cost[fan2]] + val[i] + val[fan1] + val[fan2]); } } p = i; } } return dp[p][n]; }
27.分组背包 public static int MAXN = 1001 ;public static int MAXM = 1001 ;public static int [][] arr = new int [MAXN][3 ];public static int [] dp = new int [MAXM];public static int m, n;public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { m = (int ) in.nval; in.nextToken(); n = (int ) in.nval; for (int i = 1 ; i <= n; i++) { in.nextToken(); arr[i][0 ] = (int ) in.nval; in.nextToken(); arr[i][1 ] = (int ) in.nval; in.nextToken(); arr[i][2 ] = (int ) in.nval; } Arrays.sort(arr, 1 , n + 1 , (a, b) -> a[2 ] - b[2 ]); out.println(compute1()); } out.flush(); out.close(); br.close(); } public static int compute1 () { int teams = 1 ; for (int i = 2 ; i <= n; i++) { if (arr[i - 1 ][2 ] != arr[i][2 ]) { teams++; } } int [][] dp = new int [teams + 1 ][m + 1 ]; for (int start = 1 , end = 2 , i = 1 ; start <= n; i++) { while (end <= n && arr[end][2 ] == arr[start][2 ]) { end++; } for (int j = 0 ; j <= m; j++) { dp[i][j] = dp[i - 1 ][j]; for (int k = start; k < end; k++) { if (j - arr[k][0 ] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[i - 1 ][j - arr[k][0 ]] + arr[k][1 ]); } } } start = end++; } return dp[teams][m]; }
28.完全背包 public static int MAXM = 10001 ;public static int MAXT = 10000001 ;public static int [] cost = new int [MAXM];public static int [] val = new int [MAXM];public static long [] dp = new long [MAXT];public static int t, m;public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { t = (int ) in.nval; in.nextToken(); m = (int ) in.nval; for (int i = 1 ; i <= m; i++) { in.nextToken(); cost[i] = (int ) in.nval; in.nextToken(); val[i] = (int ) in.nval; } out.println(compute2()); } out.flush(); out.close(); br.close(); } public static long compute1 () { int [][] dp = new int [m + 1 ][t + 1 ]; for (int i = 1 ; i <= m; i++) { for (int j = 0 ; j <= t; j++) { dp[i][j] = dp[i - 1 ][j]; if (j - cost[i] >= 0 ) { dp[i][j] = Math.max(dp[i][j], dp[i][j - cost[i]] + val[i]); } } } return dp[m][t]; }
29.多重背包 public static int MAXN = 1001 ;public static int MAXW = 40001 ;public static int [] v = new int [MAXN];public static int [] w = new int [MAXN];public static int [] dp = new int [MAXW];public static int n, t, m;public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader (new InputStreamReader (System.in)); StreamTokenizer in = new StreamTokenizer (br); PrintWriter out = new PrintWriter (new OutputStreamWriter (System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { n = (int ) in.nval; in.nextToken(); t = (int ) in.nval; m = 0 ; for (int i = 1 , value, weight, cnt; i <= n; i++) { in.nextToken(); value = (int ) in.nval; in.nextToken(); weight = (int ) in.nval; in.nextToken(); cnt = (int ) in.nval; for (int k = 1 ; k <= cnt; k <<= 1 ) { v[++m] = k * value; w[m] = k * weight; cnt -= k; } if (cnt > 0 ) { v[++m] = cnt * value; w[m] = cnt * weight; } } out.println(compute()); } out.flush(); out.close(); br.close(); } public static int compute () { Arrays.fill(dp, 0 , t + 1 , 0 ); for (int i = 1 ; i <= m; i++) { for (int j = t; j >= w[i]; j--) { dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]); } } return dp[t]; }
我将记录手撕题目: 写一个快速排序 链接
public static int [] sortArray(int [] nums) { if (nums.length > 1 ) { quickSort(nums, 0 , nums.length - 1 ); } return nums; } public static void quickSort (int [] arr, int l, int r) { if (l >= r) { return ; } int x = arr[l + (int ) (Math.random() * (r - l + 1 ))]; partition(arr, l, r, x); int left = first; int right = last; quickSort(arr, l, left - 1 ); quickSort(arr, right + 1 , r); } public static int first, last;public static void partition (int [] arr, int l, int r, int x) { first = l; last = r; int i = l; while (i <= last) { if (arr[i] == x) { i++; } else if (arr[i] < x) { swap(arr, first++, i++); } else { swap(arr, i, last--); } } } public static void swap (int [] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
求最长递增子序列 链接
public static int lengthOfLIS (int [] nums) { int n = nums.length; int [] ends = new int [n]; int len = 0 ; for (int i = 0 , find; i < n; i++) { find = bs1(ends, len, nums[i]); if (find == -1 ) { ends[len++] = nums[i]; } else { ends[find] = nums[i]; } } return len; } public static int bs1 (int [] ends, int len, int num) { int l = 0 , r = len - 1 , m, ans = -1 ; while (l <= r) { m = (l + r) / 2 ; if (ends[m] >= num) { ans = m; r = m - 1 ; } else { l = m + 1 ; } } return ans; } public static int bs2 (int [] ends, int len, int num) { int l = 0 , r = len - 1 , m, ans = -1 ; while (l <= r) { m = (l + r) / 2 ; if (ends[m] > num) { ans = m; r = m - 1 ; } else { l = m + 1 ; } } return ans; }
LRU缓存 链接
class LRUCache { class DoubleNode { public int key; public int val; public DoubleNode last; public DoubleNode next; public DoubleNode (int k, int v) { key = k; val = v; } } class DoubleList { private DoubleNode head; private DoubleNode tail; public DoubleList () { head = null ; tail = null ; } public void addNode (DoubleNode newNode) { if (newNode == null ) { return ; } if (head == null ) { head = newNode; tail = newNode; } else { tail.next = newNode; newNode.last = tail; tail = newNode; } } public void moveNodeToTail (DoubleNode node) { if (tail == node) { return ; } if (head == node) { head = node.next; head.last = null ; } else { node.last.next = node.next; node.next.last = node.last; } node.last = tail; node.next = null ; tail.next = node; tail = node; } public DoubleNode removeHead () { if (head == null ) { return null ; } DoubleNode ans = head; if (head == tail) { head = null ; tail = null ; } else { head = ans.next; ans.next = null ; head.last = null ; } return ans; } } private HashMap<Integer, DoubleNode> keyNodeMap; private DoubleList nodeList; private final int capacity; public LRUCache (int cap) { keyNodeMap = new HashMap <>(); nodeList = new DoubleList (); capacity = cap; } public int get (int key) { if (keyNodeMap.containsKey(key)) { DoubleNode ans = keyNodeMap.get(key); nodeList.moveNodeToTail(ans); return ans.val; } return -1 ; } public void put (int key, int value) { if (keyNodeMap.containsKey(key)) { DoubleNode node = keyNodeMap.get(key); node.val = value; nodeList.moveNodeToTail(node); } else { if (keyNodeMap.size() == capacity) { keyNodeMap.remove(nodeList.removeHead().key); } DoubleNode newNode = new DoubleNode (key, value); keyNodeMap.put(key, newNode); nodeList.addNode(newNode); } } }
反转链表 一般要求递归和迭代都要写出来
链接
迭代:
public ListNode reverseList (ListNode head) { ListNode next=null ; ListNode pre=null ; while (head!=null ){ next=head.next; head.next=pre; pre=head; head=next; } return pre; }
递归:
public ListNode reverseList (ListNode head) { return recur(head, null ); } private ListNode recur (ListNode cur, ListNode pre) { if (cur == null ) return pre; ListNode res = recur(cur.next, cur); cur.next = pre; return res; }
无重复字符的最长子串 经典滑动窗口
链接
public int lengthOfLongestSubstring (String str) { char [] s = str.toCharArray(); int n=s.length; int [] last=new int [256 ]; Arrays.fill(last,-1 ); int ans=0 ; for (int l = 0 ,r=0 ; r<n; r++) { l=Math.max(l,last[s[r]]+1 ); ans=Math.max(ans,r-l+1 ); last[s[r]]=r; } return ans; }
K个一组翻转链表 链接
public ListNode reverseKGroup (ListNode head, int k) { ListNode start=head; ListNode end=teamEnd(start,k); if (end==null ) { return head; } head=end; reverse(start,end); ListNode lastTeamEnd=start; while (lastTeamEnd.next!=null ) { start=lastTeamEnd.next; end=teamEnd(start,k); if (end==null ) { return head; } reverse(start,end); lastTeamEnd.next=end; lastTeamEnd=start; } return head; } private void reverse (ListNode s, ListNode e) { e=e.next; ListNode pre=null ,cur=s,next=null ; while (cur != e) { next = cur.next; cur.next = pre; pre = cur; cur = next; } s.next = e; } private ListNode teamEnd (ListNode s, int k) { while (--k!=0 &&s!=null ) { s=s.next; } return s; }
数组中的第K个最大元素 链接
要实现O(n)的算法,实际上就是写一个快排。
public static void quickSort (int [] arr, int l, int r) { if (l >= r) { return ; } int x = arr[l + (int ) (Math.random() * (r - l + 1 ))]; partition(arr, l, r, x); int left = first; int right = last; quickSort(arr, l, left - 1 ); quickSort(arr, right + 1 , r); } public static int first, last; public static void partition (int [] arr, int l, int r, int x) { first = l; last = r; int i = l; while (i <= last) { if (arr[i] == x) { i++; } else if (arr[i] < x) { swap(arr, first++, i++); } else { swap(arr, i, last--); } } } public static void swap (int [] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } public int findKthLargest (int [] nums, int k) { quickSort(nums,0 ,nums.length-1 ); return nums[nums.length-k]; }
三数之和 链接
public List<List<Integer>> threeSum (int [] nums) { int n=nums.length; Arrays.sort(nums); List<List<Integer>> ans=new ArrayList <>(); for (int first=0 ;first<n;first++){ if (first>0 &&nums[first]==nums[first-1 ]){ continue ; } int third=n-1 ; int target=-nums[first]; for (int second=first+1 ;second<n;second++){ if (second>first+1 &&nums[second]==nums[second-1 ]){ continue ; } while (second<third&&nums[second]+nums[third]>target){ --third; } if (second==third){ break ; } if (nums[second]+nums[third]==target){ List<Integer> list=new ArrayList <>(); list.add(nums[first]); list.add(nums[second]); list.add(nums[third]); ans.add(list); } } } return ans; }
合并两个有序链表 链接
public ListNode mergeTwoLists (ListNode head1, ListNode head2) { if (head1 == null || head2 == null ) { return head1 == null ? head2 : head1; } ListNode head = head1.val <= head2.val ? head1 : head2; ListNode h1 = head.next; ListNode h2 = head == head1 ? head2 : head1; ListNode pre = head; while (h1 != null && h2 != null ) { if (h1.val <= h2.val) { pre.next = h1; h1 = h1.next; } else { pre.next = h2; h2 = h2.next; } pre = pre.next; } pre.next = h1 != null ? h1 : h2; return head; }
排序数组 链表
public static int first, last; public int [] sortArray(int [] nums) { int n = nums.length; if (n > 1 ) { quickSort(nums, 0 , n - 1 ); } return nums; } public static void quickSort (int [] nums, int l, int r) { if (l >= r) { return ; } int x = nums[l + (int ) (Math.random() * (r - l + 1 ))]; partition(nums, l, r,x); int left = first; int right=last; quickSort(nums,l,left-1 ); quickSort(nums,right+1 ,r); } public static void partition (int [] nums,int l,int r,int x) { first=l; last=r; int i=l; while (i<=last){ if (nums[i]==x){ i++; }else if (nums[i]<x){ swap(nums,first++,i++); }else { swap(nums,i,last--); } } } public static void swap (int [] nums,int i,int j) { int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; }
搜索旋转排序数组 链接
public int search (int [] nums, int target) { if (nums == null || nums.length == 0 ){ return -1 ; } int start = 0 ; int end = nums.length - 1 ; while (start <= end){ int mid = start + (end -start)/2 ; if (nums[mid] == target){ return mid; } if (nums[mid] < nums[end]){ if (nums[mid] < target && target <= nums[end]){ start = mid + 1 ; } else { end = mid - 1 ; } } else { if (nums[mid] > target && target >= nums[start]){ end = mid - 1 ; } else { start = mid + 1 ; } } } return -1 ; }
合并K个排序数组 链接
public ListNode mergeKLists (ListNode[] lists) { PriorityQueue<ListNode> pq = new PriorityQueue <>((a, b) -> a.val - b.val); for (ListNode head : lists) if (head != null ) pq.offer(head); ListNode dummy = new ListNode (); ListNode cur = dummy; while (!pq.isEmpty()) { ListNode node = pq.poll(); if (node.next != null ) pq.offer(node.next); cur.next = node; cur = cur.next; } return dummy.next; }
反转链表|| 链接
public ListNode reverseBetween (ListNode head, int left, int right) { ListNode dummyNode = new ListNode (-1 ); dummyNode.next = head; ListNode pre = dummyNode; for (int i = 0 ; i < left - 1 ; i++) { pre = pre.next; } ListNode cur = pre.next; ListNode next; for (int i = 0 ; i < right - left; i++) { next = cur.next; cur.next = next.next; next.next = pre.next; pre.next = next; } return dummyNode.next; }
二叉树的层序遍历 链接
public static int MAXN = 2001 ;public static TreeNode[] queue = new TreeNode [MAXN];public static int l, r;public static List<List<Integer>> levelOrder (TreeNode root) { List<List<Integer>> ans = new ArrayList <>(); if (root != null ) { l = r = 0 ; queue[r++] = root; while (l < r) { int size = r - l; List<Integer> list = new ArrayList <>(); for (int i = 0 ; i < size; i++) { TreeNode cur = queue[l++]; list.add(cur.val); if (cur.left != null ) { queue[r++] = cur.left; } if (cur.right != null ) { queue[r++] = cur.right; } } ans.add(list); } } return ans; }
最长回文子串 链接
public String longestPalindrome (String s) { int len=s.length(); int left=0 ,right=0 ,res=0 ; boolean [][] dp=new boolean [len][len]; for (int i=len-1 ;i>=0 ;i--){ for (int j=i;j<len;j++){ if (s.charAt(i)==s.charAt(j)&&(j-i<=1 ||dp[i+1 ][j-1 ])){ dp[i][j]=true ; if (j-i>res){ res=j-i; left=i; right=j; } } } } return s.substring(left,right+1 ); }
相似题目–最长回文子序列
public static int longestPalindromeSubseq2 (String str) { char [] s = str.toCharArray(); int n = s.length; int [][] dp = new int [n][n]; return f(s, 0 , n - 1 , dp); } public static int f (char [] s, int l, int r, int [][] dp) { if (l == r) { return 1 ; } if (l + 1 == r) { return s[l] == s[r] ? 2 : 1 ; } if (dp[l][r] != 0 ) { return dp[l][r]; } int ans; if (s[l] == s[r]) { ans = 2 + f(s, l + 1 , r - 1 , dp); } else { ans = Math.max(f(s, l + 1 , r, dp), f(s, l, r - 1 , dp)); } dp[l][r] = ans; return ans; }
二叉树的锯齿形层序遍历 链接
public static int MAXN=2001 ;public static TreeNode[] queue=new TreeNode [MAXN];public static int l,r;public List<List<Integer>> zigzagLevelOrder (TreeNode root) { List<List<Integer>> ans=new ArrayList <>(); if (root!=null ) { l=r=0 ; queue[r++]=root; boolean reverse=false ; while (l<r) { int size=r-l; ArrayList<Integer> list=new ArrayList <>(); for (int i = reverse?r-1 :l,k=0 ;k < size; i += reverse?-1 :1 , k++) { TreeNode cur = queue[i]; list.add(cur.val); } for (int i = 0 ; i < size; i++) { TreeNode cur = queue[l++]; if (cur.left != null ) { queue[r++] = cur.left; } if (cur.right != null ) { queue[r++] = cur.right; } } ans.add(list); reverse = !reverse; } } return ans; }
二叉树的最近公共祖先 链接
public TreeNode lowestCommonAncestor (TreeNode root, TreeNode p, TreeNode q) { if (root==null ||p==root||q==root){ return root; } TreeNode left= lowestCommonAncestor(root.left,p,q); TreeNode right= lowestCommonAncestor(root.right,p,q); if (left!=null &&right!=null ) return root; if (left==null ) return right; return left; }
最大子数组和 链接
public int maxSubArray (int [] nums) { int n=nums.length; int [] dp=new int [n]; dp[0 ]=nums[0 ]; int ans=dp[0 ]; for (int i=1 ;i<n;i++) { dp[i]=Math.max(dp[i-1 ]+nums[i],nums[i]); ans=Math.max(dp[i],ans); } return ans; }
重排链表 链接
public void reorderList (ListNode head) { ListNode fast = head, slow = head; while (fast.next != null && fast.next.next != null ) { slow = slow.next; fast = fast.next.next; } ListNode cur = slow.next; slow.next = null ; ListNode pre = null ; while (cur != null ) { ListNode t = cur.next; cur.next = pre; pre = cur; cur = t; } cur = head; while (pre != null ) { ListNode t = pre.next; pre.next = cur.next; cur.next = pre; cur = pre.next; pre = t; } }
相交链表 链接
public ListNode getIntersectionNode (ListNode h1, ListNode h2) { if (h1==null ||h2==null ){ return null ; } int diff=0 ; ListNode a=h1; ListNode b=h2; while (a.next!=null ){ a=a.next; diff++; } while (b.next!=null ){ b=b.next; diff--; } if (diff>=0 ){ a=h1; b=h2; }else { a=h2; b=h1; } diff=Math.abs(diff); while (diff-->0 ){ a=a.next; } while (a!=b){ a=a.next; b=b.next; } return a; }
螺旋矩阵 链接
public List<Integer> spiralOrder (int [][] matrix) { List<Integer> list = new ArrayList <Integer>(); if (matrix == null || matrix.length == 0 ) return list; int m = matrix.length; int n = matrix[0 ].length; int i = 0 ; int count = (Math.min(m, n)+1 )/2 ; while (i < count) { for (int j = i; j < n-i; j++) { list.add(matrix[i][j]); } for (int j = i+1 ; j < m-i; j++) { list.add(matrix[j][(n-1 )-i]); } for (int j = (n-1 )-(i+1 ); j >= i && (m-1 -i) != i; j--) { list.add(matrix[(m-1 )-i][j]); } for (int j = (m-1 )-(i+1 ); j >= i+1 && (n-1 -i) != i; j--) { list.add(matrix[j][i]); } i++; } return list; }
接雨水 链接
public int trap (int [] nums) { int l=1 ,r=nums.length-2 ,lmax=nums[0 ],rmax=nums[nums.length-1 ]; int ans=0 ; while (l<=r){ if (lmax<=rmax){ ans+=Math.max(0 ,lmax-nums[l]); lmax=Math.max(lmax,nums[l++]); }else { ans+=Math.max(0 ,rmax-nums[r]); rmax=Math.max(rmax,nums[r--]); } } return ans; }
岛屿数量 链接
public int numIslands (char [][] grid) { int n=grid.length; int m=grid[0 ].length; int island=0 ; for (int i=0 ;i<n;i++){ for (int j=0 ;j<m;j++){ if (grid[i][j]=='1' ){ island++; dfs(grid,i,j,n,m); } } } return island; } public void dfs (char [][] grid,int i,int j,int n,int m) { if (i<0 ||i>=n||j<0 ||j>=m||grid[i][j]!='1' ){ return ; } grid[i][j]='0' ; dfs(grid,i+1 ,j,n,m); dfs(grid,i-1 ,j,n,m); dfs(grid,i,j+1 ,n,m); dfs(grid,i,j-1 ,n,m); }
环形链表 链接
public boolean hasCycle (ListNode head) { ListNode slow=head; ListNode fast=head; while (fast!=null &&fast.next!=null ){ slow=slow.next; fast=fast.next.next; if (slow==fast){ return true ; } } return false ; }
买卖股票的最佳时机 链接
public static int maxProfit (int [] prices) { int ans = 0 ; for (int i = 1 , min = prices[0 ]; i < prices.length; i++) { min = Math.min(min, prices[i]); ans = Math.max(ans, prices[i] - min); } return ans; }
全排列 链接
public List<List<Integer>> permute (int [] nums) { List<List<Integer>> ans=new ArrayList <>(); f(nums,0 ,ans); return ans; } private void f (int [] nums,int i,List<List<Integer>> ans) { if (i==nums.length){ List<Integer> list=new ArrayList <>(); for (int j=0 ;j<nums.length;j++){ list.add(nums[j]); } ans.add(list); }else { for (int j = i; j < nums.length; j++) { swap(nums,i,j); f(nums, i+1 , ans); swap(nums,i,j); } } } private void swap (int [] nums,int i,int j) { int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; }
最长递增子序列 链接
public static int lengthOfLIS (int [] nums) { int n = nums.length; int [] ends = new int [n]; int len = 0 ; for (int i = 0 , find; i < n; i++) { find = bs(ends, len, nums[i]); if (find == -1 ) { ends[len++] = nums[i]; } else { ends[find] = nums[i]; } } return len; } public static int bs (int [] ends, int len, int num) { int l = 0 , r = len - 1 , m, ans = -1 ; while (l <= r) { m = l+(r-l) / 2 ; if (ends[m] >= num) { ans = m; r = m - 1 ; } else { l = m + 1 ; } } return ans; }
两数之和 链接
public int [] twoSum(int [] nums, int target) { Map<Integer,Integer> map=new HashMap <>(); for (int i=0 ;i<nums.length;i++) { if (map.containsKey(target-nums[i])) { return new int [] {map.get(target-nums[i]),i}; } map.put(nums[i],i); } return new int [0 ]; }
合并两个有序数组 链接
public void merge (int [] nums1, int m, int [] nums2, int n) { if (n == 0 ) return ; int i = m + n - 1 ; m--; n--; while (n >= 0 ) { if (m < 0 || nums2[n] > nums1[m]) { nums1[i--] = nums2[n--]; } else { nums1[i--] = nums1[m--]; } } }
删除排序链表中的重复元素II 链接
public ListNode deleteDuplicates (ListNode head) { if (head == null ) { return head; } ListNode dummy = new ListNode (0 , head); ListNode cur = dummy; while (cur.next != null && cur.next.next != null ) { if (cur.next.val == cur.next.next.val) { int x = cur.next.val; while (cur.next != null && cur.next.val == x) { cur.next = cur.next.next; } } else { cur = cur.next; } } return dummy.next; }
有效的括号 链接
public boolean isValid (String s) { Deque<Character> stack=new LinkedList <>(); for (int i = 0 ; i < s.length(); i++) { char c = s.charAt(i); if (c=='(' ){ stack.push(')' ); }else if (c=='[' ){ stack.push(']' ); }else if (c=='{' ){ stack.push('}' ); }else { if (!stack.isEmpty()&&c==stack.peek()){ stack.pop(); }else { return false ; } } } return stack.isEmpty(); }
字符串相加 链接
public String addStrings (String num1, String num2) { int i = num1.length() - 1 , j = num2.length() - 1 , add = 0 ; StringBuffer ans = new StringBuffer (); while (i >= 0 || j >= 0 || add != 0 ) { int x = i >= 0 ? num1.charAt(i) - '0' : 0 ; int y = j >= 0 ? num2.charAt(j) - '0' : 0 ; int result = x + y + add; ans.append(result % 10 ); add = result / 10 ; i--; j--; } ans.reverse(); return ans.toString(); }
环形链表II 链接
public ListNode detectCycle (ListNode head) { ListNode fast = head, slow = head; while (true ) { if (fast == null || fast.next == null ) return null ; fast = fast.next.next; slow = slow.next; if (fast == slow) break ; } fast = head; while (slow != fast) { slow = slow.next; fast = fast.next; } return fast; }
合并区间 链接
public int [][] merge(int [][] intervals){ Arrays.sort(intervals,(a,b)->a[0 ]-b[0 ]); List<int []> res=new ArrayList <>(); for (int [] interval:intervals) { if (res.size()==0 ||interval[0 ]>res.get(res.size()-1 )[1 ]) { res.add(interval); }else { res.get(res.size()-1 )[1 ]=Math.max(res.get(res.size()-1 )[1 ],interval[1 ]); } } return res.toArray(new int [res.size()][2 ]); }
二叉树中的最大路径和 链接
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this .val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this .val = val; this .left = left; this .right = right; } } int maxSum = Integer.MIN_VALUE; public int maxPathSum (TreeNode root) { maxGain(root); return maxSum; } public int maxGain (TreeNode node) { if (node == null ) { return 0 ; } int leftGain = Math.max(maxGain(node.left), 0 ); int rightGain = Math.max(maxGain(node.right), 0 ); int priceNewpath = node.val + leftGain + rightGain; maxSum = Math.max(maxSum, priceNewpath); return node.val + Math.max(leftGain, rightGain); }
编辑距离 链接
public int minDistance (String word1, String word2) { return editDistance(word1,word2,1 ,1 ,1 ); } private int editDistance (String word1, String word2, int a, int b, int c) { char [] s1 = word1.toCharArray(); char [] s2 = word2.toCharArray(); int n=s1.length; int m=s2.length; int [][] dp=new int [n+1 ][m+1 ]; for (int i= 1 ; i <=n; i++) { dp[i][0 ]=i*b; } for (int j = 1 ; j <=m; j++) { dp[0 ][j]=j*a; } for (int i = 1 ; i <=n; i++) { for (int j = 1 ; j <=m; j++) { int p1=Integer.MAX_VALUE; if (s1[i-1 ]==s2[j-1 ]) { p1=dp[i-1 ][j-1 ]; } int p2=Integer.MAX_VALUE; if (s1[i-1 ]!=s2[j-1 ]) { p2=dp[i-1 ][j-1 ]+c; } int p3=dp[i][j-1 ]+a; int p4=dp[i-1 ][j]+b; dp[i][j]=Math.min(Math.min(p1, p2),Math.min(p3, p4)); } } return dp[n][m]; }
复原IP地址 List<String> ans=new ArrayList <>(); char [] s1; public List<String> restoreIpAddresses (String s) { s1 = s.toCharArray(); dfs(0 ,s1.length, new ArrayList <>()); return ans; } void dfs (int ids,int n,List<Integer> cur) { if (cur.size()>4 ) return ; if (ids==n){ if (cur.size()==4 ){ StringBuilder sb=new StringBuilder (); for (int i=0 ;i<4 ;i++) sb.append(cur.get(i)).append("." ); ans.add(sb.substring(0 ,sb.length()-1 )); } }else { for (int i=ids;i<n;i++){ int t=0 ; for (int j=ids;j<=i;j++) t=t*10 +(s1[j]-'0' ); if (s1[ids] == '0' && i != ids) break ; if (t > 255 ) break ; cur.add(t); dfs(i + 1 , n, cur); cur.remove(cur.size() - 1 ); } } }
最长公共子序列 链接
public int longestCommonSubsequence (String text1, String text2) { char [] s1 = text1.toCharArray(); char [] s2 = text2.toCharArray(); int n=s1.length; int m=s2.length; int [][] dp=new int [n+1 ][m+1 ]; for (int len1 = 1 ; len1 <=n; len1++) { for (int len2 = 1 ; len2 <=m; len2++) { if (s1[len1-1 ]==s2[len2-1 ]) { dp[len1][len2]=dp[len1-1 ][len2-1 ]+1 ; }else { dp[len1][len2]=Math.max(dp[len1-1 ][len2],dp[len1][len2-1 ]); } } } return dp[n][m]; }
二叉树的中序遍历 链接
public List<Integer> inorderTraversal (TreeNode root) { List<Integer> res=new ArrayList <>(); Deque<TreeNode> stack=new LinkedList <TreeNode>(); while (root!=null ||!stack.isEmpty()){ while (root!=null ){ stack.push(root); root=root.left; } root=stack.pop(); res.add(root.val); root=root.right; } return res; }
二分查找 链接
public int search (int [] nums, int target) { int i=0 ; int j=nums.length-1 ; while (i<=j){ int m=(i+j)>>>1 ; if (nums[m]<target){ i=m+1 ; }else if (nums[m]>target){ j=m-1 ; }else { return m; } } return -1 ; }
二叉树的右视图 链接
public List<Integer> rightSideView (TreeNode root) { List<Integer> res = new ArrayList <>(); Deque<TreeNode> queue = new LinkedList <>(); if (root == null ) return res; queue.offer(root); for (;!queue.isEmpty();){ int size = queue.size(); TreeNode lastOne = null ; for (int i=0 ; i<size; i++){ lastOne = queue.poll(); if (lastOne.left != null ) queue.offer(lastOne.left); if (lastOne.right != null ) queue.offer(lastOne.right); } res.add(lastOne.val); } return res; }
寻找两个正序数组中的中位数 链接
public double findMedianSortedArrays (int [] nums1, int [] nums2) { if (nums1.length > nums2.length) { return findMedianSortedArrays(nums2, nums1); } int m = nums1.length; int n = nums2.length; int left = 0 , right = m; int median1 = 0 , median2 = 0 ; while (left <= right) { int i = (left + right) / 2 ; int j = (m + n + 1 ) / 2 - i; int nums_im1 = (i == 0 ? Integer.MIN_VALUE : nums1[i - 1 ]); int nums_i = (i == m ? Integer.MAX_VALUE : nums1[i]); int nums_jm1 = (j == 0 ? Integer.MIN_VALUE : nums2[j - 1 ]); int nums_j = (j == n ? Integer.MAX_VALUE : nums2[j]); if (nums_im1 <= nums_j) { median1 = Math.max(nums_im1, nums_jm1); median2 = Math.min(nums_i, nums_j); left = i + 1 ; } else { right = i - 1 ; } } return (m + n) % 2 == 0 ? (median1 + median2) / 2.0 : median1; }
下一个排列 链接
public void nextPermutation (int [] nums) { int n = nums.length, k = n - 1 ; while (k - 1 >= 0 && nums[k - 1 ] >= nums[k]) k--; if (k == 0 ) { reverse(nums, 0 , n - 1 ); } else { int u = k; while (u + 1 < n && nums[u + 1 ] > nums[k - 1 ]) u++; swap(nums, k - 1 , u); reverse(nums, k, n - 1 ); } } void reverse (int [] nums, int a, int b) { int l = a, r = b; while (l < r) swap(nums, l++, r--); } void swap (int [] nums, int a, int b) { int c = nums[a]; nums[a] = nums[b]; nums[b] = c; }
用栈实现队列 链接
class MyQueue { Deque<Integer> inStack; Deque<Integer> outStack; public MyQueue () { inStack=new ArrayDeque <Integer>(); outStack=new ArrayDeque <Integer>(); } public void push (int x) { inStack.push(x); } public int pop () { if (outStack.isEmpty()){ while (!inStack.isEmpty()){ outStack.push(inStack.pop()); } } return outStack.pop(); } public int peek () { if (outStack.isEmpty()){ while (!inStack.isEmpty()){ outStack.push(inStack.pop()); } } return outStack.peek(); } public boolean empty () { return inStack.isEmpty()&&outStack.isEmpty(); } }
只要我还在刷题,持续更新