算法与数据结构核心思想与解题蓝图 目录 
哈希(Hash)  
双指针(Two Pointers)  
滑动窗口(Sliding Window)  
子串(Substring)  
普通数组(Array)  
矩阵(Matrix)  
链表(Linked List)  
二叉树(Binary Tree)  
图论(Graph Theory)  
回溯(Backtracking)  
二分查找(Binary Search)  
栈(Stack)  
贪心算法(Greedy)  
动态规划(DP)  
多维动态规划(Multi-dimensional DP)  
技巧(Tricks)  
 
接下来我将简单介绍以上16种算法思想及其使用场景
哈希:快速查找和存储数据 双指针:有序数组/链表问题 滑动窗口:子数组/子串问题 子串:字符串匹配问题 普通数组:数组遍历、查找 矩阵:二维数组遍历 链表:遍历、反转 二叉树:遍历、搜索 图论:图的遍历 回溯:组合、排列 二分查找:有序数组查找 栈:逆序遍历 贪心算法:局部最优解 动态规划:最优解 多维动态规划:多维数组问题 技巧:位运算、前缀和 
 
哈希(Hash) 核心思想 :利用哈希表(O(1)时间复杂度)快速查找和存储数据适用场景 :需要快速查找/去重的场景,如两数之和、重复元素检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Map<Integer, Integer> map = new  HashMap <>(); map.put(key, value);        int  val  =  map.get(key);     boolean  exists  =  map.containsKey(key); public  int [] twoSum(int [] nums, int  target) {    Map<Integer, Integer> map = new  HashMap <>();     for  (int  i  =  0 ; i < nums.length; i++) {         int  complement  =  target - nums[i];         if  (map.containsKey(complement)) {             return  new  int []{map.get(complement), i};         }         map.put(nums[i], i);     }     return  new  int [0 ]; } Set<Integer> set = new  HashSet <>(); for  (int  num : nums) {    if  (set.contains(num)) {              }     set.add(num); } 
 
 
双指针(Two Pointers) 核心思想 :使用两个指针协同遍历数据结构适用场景 :有序数组/链表问题,如归并数组、判断回文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public  void  reverse (int [] nums)  {    int  left  =  0 , right = nums.length - 1 ;     while  (left < right) {         int  temp  =  nums[left];         nums[left++] = nums[right];         nums[right--] = temp;     } } public  boolean  hasCycle (ListNode head)  {    ListNode  slow  =  head, fast = head;     while  (fast != null  && fast.next != null ) {         slow = slow.next;         fast = fast.next.next;         if  (slow == fast) return  true ;     }     return  false ; } public  List<List<Integer>> threeSum (int [] nums)  {    Arrays.sort(nums);     List<List<Integer>> res = new  ArrayList <>();     for  (int  i  =  0 ; i < nums.length - 2 ; i++) {         if  (i > 0  && nums[i] == nums[i-1 ]) continue ;         int  left  =  i+1 , right = nums.length-1 ;         while  (left < right) {             int  sum  =  nums[i] + nums[left] + nums[right];             if  (sum == 0 ) {                 res.add(Arrays.asList(nums[i], nums[left], nums[right]));                 while  (left < right && nums[left] == nums[left+1 ]) left++;                 while  (left < right && nums[right] == nums[right-1 ]) right--;                 left++; right--;             } else  if  (sum < 0 ) left++;             else  right--;         }     }     return  res; } 
 
 
滑动窗口(Sliding Window) 核心思想 :维护一个可变大小的窗口在数据结构上滑动适用场景 :子数组/子串问题,如最小覆盖子串、最长无重复子串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public  int  slidingWindowTemplate (String s)  {    Map<Character, Integer> window = new  HashMap <>();     int  left  =  0 , right = 0 ;     int  maxLen  =  0 ;          while  (right < s.length()) {         char  c  =  s.charAt(right++);         window.put(c, window.getOrDefault(c, 0 ) + 1 );                  while  () {             char  d  =  s.charAt(left++);             window.put(d, window.get(d) - 1 );             if  (window.get(d) == 0 ) window.remove(d);         }                  maxLen = Math.max(maxLen, right - left);     }     return  maxLen; } public  int  lengthOfLongestSubstring (String s)  {    Map<Character, Integer> window = new  HashMap <>();     int  left  =  0 , right = 0 ;     int  maxLen  =  0 ;          while  (right < s.length()) {         char  c  =  s.charAt(right++);         window.put(c, window.getOrDefault(c, 0 ) + 1 );                  while  (window.get(c) > 1 ) {             char  d  =  s.charAt(left++);             window.put(d, window.get(d) - 1 );         }                  maxLen = Math.max(maxLen, right - left);     }     return  maxLen; } 
 
 
子串(Substring) 核心思想 :处理字符串中的连续字符序列问题适用场景 :字符串匹配、子串查找、回文子串等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public  String longestPalindrome (String s)  {    if  (s == null  || s.length() < 1 ) return  "" ;     int  start  =  0 , end = 0 ;     for  (int  i  =  0 ; i < s.length(); i++) {         int  len1  =  expandAroundCenter(s, i, i);             int  len2  =  expandAroundCenter(s, i, i + 1 );          int  len  =  Math.max(len1, len2);         if  (len > end - start) {             start = i - (len - 1 ) / 2 ;             end = i + len / 2 ;         }     }     return  s.substring(start, end + 1 ); } private  int  expandAroundCenter (String s, int  left, int  right)  {    while  (left >= 0  && right < s.length() && s.charAt(left) == s.charAt(right)) {         left--;         right++;     }     return  right - left - 1 ; } public  int  strStr (String haystack, String needle)  {    if  (needle.isEmpty()) return  0 ;     int [] lps = computeLPSArray(needle);     int  i  =  0 , j = 0 ;     while  (i < haystack.length()) {         if  (haystack.charAt(i) == needle.charAt(j)) {             i++; j++;             if  (j == needle.length()) return  i - j;         } else  {             if  (j != 0 ) j = lps[j-1 ];             else  i++;         }     }     return  -1 ; } private  int [] computeLPSArray(String pattern) {    int [] lps = new  int [pattern.length()];     int  len  =  0 , i = 1 ;     while  (i < pattern.length()) {         if  (pattern.charAt(i) == pattern.charAt(len)) {             lps[i++] = ++len;         } else  {             if  (len != 0 ) len = lps[len-1 ];             else  lps[i++] = 0 ;         }     }     return  lps; } 
 
 
普通数组(Array) 核心思想 :利用数组索引和元素关系解决问题适用场景 :元素操作、排序、搜索等基础问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public  void  reverseArray (int [] nums)  {    for  (int  i  =  0 ; i < nums.length / 2 ; i++) {         int  temp  =  nums[i];         nums[i] = nums[nums.length - 1  - i];         nums[nums.length - 1  - i] = temp;     } } public  void  sortColors (int [] nums)  {    int  low  =  0 , high = nums.length - 1 ;     int  i  =  0 ;     while  (i <= high) {         if  (nums[i] == 0 ) {             swap(nums, low++, i++);         } else  if  (nums[i] == 2 ) {             swap(nums, i, high--);         } else  {             i++;         }     } } private  void  swap (int [] nums, int  i, int  j)  {    int  temp  =  nums[i];     nums[i] = nums[j];     nums[j] = temp; } class  PrefixSum  {    private  int [] prefix;          public  PrefixSum (int [] nums)  {         prefix = new  int [nums.length + 1 ];         for  (int  i  =  0 ; i < nums.length; i++) {             prefix[i + 1 ] = prefix[i] + nums[i];         }     }          public  int  sumRange (int  left, int  right)  {         return  prefix[right + 1 ] - prefix[left];     } } 
 
 
矩阵(Matrix) 核心思想 :二维数组的特殊遍历和操作技巧适用场景 :图像处理、矩阵运算、二维搜索等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public  List<Integer> spiralOrder (int [][] matrix)  {    List<Integer> res = new  ArrayList <>();     if  (matrix == null  || matrix.length == 0 ) return  res;     int  top  =  0 , bottom = matrix.length - 1 ;     int  left  =  0 , right = matrix[0 ].length - 1 ;          while  (true ) {                  for  (int  i  =  left; i <= right; i++) res.add(matrix[top][i]);         if  (++top > bottom) break ;                           for  (int  i  =  top; i <= bottom; i++) res.add(matrix[i][right]);         if  (--right < left) break ;                           for  (int  i  =  right; i >= left; i--) res.add(matrix[bottom][i]);         if  (--bottom < top) break ;                           for  (int  i  =  bottom; i >= top; i--) res.add(matrix[i][left]);         if  (++left > right) break ;     }     return  res; } public  void  rotate (int [][] matrix)  {    int  n  =  matrix.length;          for  (int  i  =  0 ; i < n; i++) {         for  (int  j  =  i; j < n; j++) {             int  temp  =  matrix[i][j];             matrix[i][j] = matrix[j][i];             matrix[j][i] = temp;         }     }          for  (int  i  =  0 ; i < n; i++) {         for  (int  j  =  0 ; j < n / 2 ; j++) {             int  temp  =  matrix[i][j];             matrix[i][j] = matrix[i][n - 1  - j];             matrix[i][n - 1  - j] = temp;         }     } } public  int  numIslands (char [][] grid)  {    if  (grid == null  || grid.length == 0 ) return  0 ;     int  count  =  0 ;     for  (int  i  =  0 ; i < grid.length; i++) {         for  (int  j  =  0 ; j < grid[0 ].length; j++) {             if  (grid[i][j] == '1' ) {                 dfs(grid, i, j);                 count++;             }         }     }     return  count; } private  void  dfs (char [][] grid, int  i, int  j)  {    if  (i < 0  || j < 0  || i >= grid.length || j >= grid[0 ].length || grid[i][j] != '1' ) 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 ); } 
 
 
链表(Linked List) 核心思想 :指针操作和虚拟头节点技巧适用场景 :链表反转、环检测、节点操作等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 class  ListNode  {    int  val;     ListNode next;     ListNode(int  x) { val = x; } } public  ListNode reverseList (ListNode head)  {    ListNode  prev  =  null , curr = head;     while  (curr != null ) {         ListNode  nextTemp  =  curr.next;         curr.next = prev;         prev = curr;         curr = nextTemp;     }     return  prev; } public  ListNode reverseListRecursive (ListNode head)  {    if  (head == null  || head.next == null ) return  head;     ListNode  p  =  reverseListRecursive(head.next);     head.next.next = head;     head.next = null ;     return  p; } public  ListNode mergeTwoLists (ListNode l1, ListNode l2)  {    ListNode  dummy  =  new  ListNode (0 );     ListNode  curr  =  dummy;     while  (l1 != null  && l2 != null ) {         if  (l1.val < l2.val) {             curr.next = l1;             l1 = l1.next;         } else  {             curr.next = l2;             l2 = l2.next;         }         curr = curr.next;     }     curr.next = l1 != null  ? l1 : l2;     return  dummy.next; } public  ListNode detectCycle (ListNode head)  {    ListNode  slow  =  head, fast = head;     while  (fast != null  && fast.next != null ) {         slow = slow.next;         fast = fast.next.next;         if  (slow == fast) {             ListNode  ptr  =  head;             while  (ptr != slow) {                 ptr = ptr.next;                 slow = slow.next;             }             return  ptr;         }     }     return  null ; } 
 
 
二叉树(Binary Tree) 核心思想 :递归和迭代遍历,分治思想适用场景 :树结构相关问题,如遍历、构造、属性判断等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 class  TreeNode  {    int  val;     TreeNode left, right;     TreeNode(int  x) { val = x; } } public  List<Integer> preorderTraversal (TreeNode root)  {    List<Integer> res = new  ArrayList <>();     preorder(root, res);     return  res; } private  void  preorder (TreeNode node, List<Integer> res)  {    if  (node == null ) return ;     res.add(node.val);     preorder(node.left, res);     preorder(node.right, res); } public  List<Integer> inorderTraversal (TreeNode root)  {    List<Integer> res = new  ArrayList <>();     Stack<TreeNode> stack = new  Stack <>();     TreeNode  curr  =  root;     while  (curr != null  || !stack.isEmpty()) {         while  (curr != null ) {             stack.push(curr);             curr = curr.left;         }         curr = stack.pop();         res.add(curr.val);         curr = curr.right;     }     return  res; } public  List<List<Integer>> levelOrder (TreeNode root)  {    List<List<Integer>> res = new  ArrayList <>();     if  (root == null ) return  res;     Queue<TreeNode> queue = new  LinkedList <>();     queue.offer(root);     while  (!queue.isEmpty()) {         int  levelSize  =  queue.size();         List<Integer> level = new  ArrayList <>();         for  (int  i  =  0 ; i < levelSize; i++) {             TreeNode  node  =  queue.poll();             level.add(node.val);             if  (node.left != null ) queue.offer(node.left);             if  (node.right != null ) queue.offer(node.right);         }         res.add(level);     }     return  res; } public  int  maxDepth (TreeNode root)  {    if  (root == null ) return  0 ;     return  1  + Math.max(maxDepth(root.left), maxDepth(root.right)); } 
 
 
图论(Graph Theory) 核心思想 :DFS/BFS遍历,并查集,最短路径算法适用场景 :网络结构、路径查找、连通性问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 List<List<Integer>> graph = new  ArrayList <>(); public  void  dfs (int  node, boolean [] visited, List<List<Integer>> graph)  {    visited[node] = true ;     for  (int  neighbor : graph.get(node)) {         if  (!visited[neighbor]) {             dfs(neighbor, visited, graph);         }     } } public  void  bfs (int  start, List<List<Integer>> graph)  {    boolean [] visited = new  boolean [graph.size()];     Queue<Integer> queue = new  LinkedList <>();     queue.offer(start);     visited[start] = true ;     while  (!queue.isEmpty()) {         int  node  =  queue.poll();         for  (int  neighbor : graph.get(node)) {             if  (!visited[neighbor]) {                 visited[neighbor] = true ;                 queue.offer(neighbor);             }         }     } } public  int [] dijkstra(List<List<int []>> graph, int  start) {    int  n  =  graph.size();     int [] dist = new  int [n];     Arrays.fill(dist, Integer.MAX_VALUE);     dist[start] = 0 ;     PriorityQueue<int []> pq = new  PriorityQueue <>((a, b) -> a[1 ] - b[1 ]);     pq.offer(new  int []{start, 0 });     while  (!pq.isEmpty()) {         int [] curr = pq.poll();         int  u  =  curr[0 ], d = curr[1 ];         if  (d > dist[u]) continue ;         for  (int [] edge : graph.get(u)) {             int  v  =  edge[0 ], w = edge[1 ];             if  (dist[v] > dist[u] + w) {                 dist[v] = dist[u] + w;                 pq.offer(new  int []{v, dist[v]});             }         }     }     return  dist; } class  UnionFind  {    private  int [] parent;     public  UnionFind (int  size)  {         parent = new  int [size];         for  (int  i  =  0 ; i < size; i++) parent[i] = i;     }     public  int  find (int  x)  {         if  (parent[x] != x) parent[x] = find(parent[x]);         return  parent[x];     }     public  void  union (int  x, int  y)  {         parent[find(x)] = find(y);     } } 
 
 
回溯(Backtracking) 核心思想 :尝试-回溯-剪枝,系统性地搜索解空间适用场景 :排列组合、子集、棋盘类问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public  List<List<Integer>> backtrack (int [] nums)  {    List<List<Integer>> res = new  ArrayList <>();     backtrackHelper(res, new  ArrayList <>(), nums, 0 );     return  res; } private  void  backtrackHelper (List<List<Integer>> res, List<Integer> temp, int [] nums, int  start)  {         if  () {         res.add(new  ArrayList <>(temp));         return ;     }     for  (int  i  =  start; i < nums.length; i++) {                  if  () continue ;         temp.add(nums[i]);          backtrackHelper(res, temp, nums, i + 1 );          temp.remove(temp.size() - 1 );      } } public  List<List<Integer>> permute (int [] nums)  {    List<List<Integer>> res = new  ArrayList <>();     backtrack(nums, new  ArrayList <>(), res);     return  res; } private  void  backtrack (int [] nums, List<Integer> temp, List<List<Integer>> res)  {    if  (temp.size() == nums.length) {         res.add(new  ArrayList <>(temp));         return ;     }     for  (int  i  =  0 ; i < nums.length; i++) {         if  (temp.contains(nums[i])) continue ;          temp.add(nums[i]);         backtrack(nums, temp, res);         temp.remove(temp.size() - 1 );     } } public  List<List<String>> solveNQueens (int  n)  {    List<List<String>> res = new  ArrayList <>();     char [][] board = new  char [n][n];     for  (char [] row : board) Arrays.fill(row, '.' );     backtrack(res, board, 0 );     return  res; } private  void  backtrack (List<List<String>> res, char [][] board, int  row)  {    if  (row == board.length) {         res.add(construct(board));         return ;     }     for  (int  col  =  0 ; col < board.length; col++) {         if  (isValid(board, row, col)) {             board[row][col] = 'Q' ;             backtrack(res, board, row + 1 );             board[row][col] = '.' ;         }     } } private  boolean  isValid (char [][] board, int  row, int  col)  {         for  (int  i  =  0 ; i < row; i++) {         if  (board[i][col] == 'Q' ) return  false ;     }          for  (int  i  =  row-1 , j = col-1 ; i >=0  && j >=0 ; i--, j--) {         if  (board[i][j] == 'Q' ) return  false ;     }          for  (int  i  =  row-1 , j = col+1 ; i >=0  && j < board.length; i--, j++) {         if  (board[i][j] == 'Q' ) return  false ;     }     return  true ; } private  List<String> construct (char [][] board)  {    List<String> res = new  ArrayList <>();     for  (char [] row : board) {         res.add(new  String (row));     }     return  res; } 
 
 
二分查找(Binary Search) 核心思想 :每次将搜索范围减半,高效查找适用场景 :有序数据查找,边界查找,旋转数组问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public  int  binarySearch (int [] nums, int  target)  {    int  left  =  0 , right = nums.length - 1 ;     while  (left <= right) {         int  mid  =  left + (right - left) / 2 ;         if  (nums[mid] == target) return  mid;         else  if  (nums[mid] < target) left = mid + 1 ;         else  right = mid - 1 ;     }     return  -1 ; } public  int  leftBound (int [] nums, int  target)  {    int  left  =  0 , right = nums.length;     while  (left < right) {         int  mid  =  left + (right - left) / 2 ;         if  (nums[mid] >= target) right = mid;         else  left = mid + 1 ;     }     return  left < nums.length && nums[left] == target ? left : -1 ; } public  int  rightBound (int [] nums, int  target)  {    int  left  =  0 , right = nums.length;     while  (left < right) {         int  mid  =  left + (right - left) / 2 ;         if  (nums[mid] <= target) left = mid + 1 ;         else  right = mid;     }     return  left > 0  && nums[left-1 ] == target ? left-1  : -1 ; } public  int  searchInRotatedArray (int [] nums, int  target)  {    int  left  =  0 , right = nums.length - 1 ;     while  (left <= right) {         int  mid  =  left + (right - left) / 2 ;         if  (nums[mid] == target) return  mid;                  if  (nums[left] <= nums[mid]) {             if  (nums[left] <= target && target < nums[mid]) right = mid - 1 ;             else  left = mid + 1 ;         }                   else  {             if  (nums[mid] < target && target <= nums[right]) left = mid + 1 ;             else  right = mid - 1 ;         }     }     return  -1 ; } 
 
 
栈(Stack) 核心思想 :LIFO特性,用于处理对称、嵌套类问题适用场景 :括号匹配、表达式求值、单调栈问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public  boolean  isValid (String s)  {    Stack<Character> stack = new  Stack <>();     for  (char  c : s.toCharArray()) {         if  (c == '(' ) stack.push(')' );         else  if  (c == '[' ) stack.push(']' );         else  if  (c == '{' ) stack.push('}' );         else  if  (stack.isEmpty() || stack.pop() != c) return  false ;     }     return  stack.isEmpty(); } public  int [] nextGreaterElement(int [] nums) {    int [] res = new  int [nums.length];     Stack<Integer> stack = new  Stack <>();     for  (int  i  =  nums.length - 1 ; i >= 0 ; i--) {         while  (!stack.isEmpty() && stack.peek() <= nums[i]) {             stack.pop();         }         res[i] = stack.isEmpty() ? -1  : stack.peek();         stack.push(nums[i]);     }     return  res; } public  int  calculate (String s)  {    Stack<Integer> stack = new  Stack <>();     int  num  =  0 , res = 0 , sign = 1 ;     for  (char  c : s.toCharArray()) {         if  (Character.isDigit(c)) {             num = num * 10  + (c - '0' );         } else  if  (c == '+' ) {             res += sign * num;             num = 0 ;             sign = 1 ;         } else  if  (c == '-' ) {             res += sign * num;             num = 0 ;             sign = -1 ;         } else  if  (c == '(' ) {             stack.push(res);             stack.push(sign);             res = 0 ;             sign = 1 ;         } else  if  (c == ')' ) {             res += sign * num;             num = 0 ;             res *= stack.pop();              res += stack.pop();          }     }     if  (num != 0 ) res += sign * num;     return  res; } 
 
 
贪心算法(Greedy) 核心思想 :局部最优选择希望导致全局最优适用场景 :区间调度、分配问题、跳跃游戏等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public  int  intervalSchedule (int [][] intervals)  {    if  (intervals.length == 0 ) return  0 ;          Arrays.sort(intervals, (a, b) -> a[1 ] - b[1 ]);     int  count  =  1 ;     int  end  =  intervals[0 ][1 ];     for  (int [] interval : intervals) {         int  start  =  interval[0 ];         if  (start >= end) {             count++;             end = interval[1 ];         }     }     return  count; } public  boolean  canJump (int [] nums)  {    int  farthest  =  0 ;     for  (int  i  =  0 ; i < nums.length; i++) {         if  (i > farthest) return  false ;         farthest = Math.max(farthest, i + nums[i]);         if  (farthest >= nums.length - 1 ) return  true ;     }     return  false ; } public  int  findContentChildren (int [] g, int [] s)  {    Arrays.sort(g);     Arrays.sort(s);     int  i  =  0 , j = 0 ;     while  (i < g.length && j < s.length) {         if  (s[j] >= g[i]) i++;         j++;     }     return  i; } 
 
 
动态规划(DP) 核心思想 :将问题分解为子问题,存储中间结果避免重复计算适用场景 :最优化问题,如最长子序列、背包问题、路径问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public  int  fib (int  n)  {    int [] memo = new  int [n + 1 ];     return  helper(n, memo); } private  int  helper (int  n, int [] memo)  {    if  (n <= 1 ) return  n;     if  (memo[n] != 0 ) return  memo[n];     memo[n] = helper(n - 1 , memo) + helper(n - 2 , memo);     return  memo[n]; } public  int  fibIterative (int  n)  {    if  (n <= 1 ) return  n;     int  a  =  0 , b = 1 ;     for  (int  i  =  2 ; i <= n; i++) {         int  c  =  a + b;         a = b;         b = c;     }     return  b; } public  int  lengthOfLIS (int [] nums)  {    int [] dp = new  int [nums.length];     Arrays.fill(dp, 1 );     int  max  =  1 ;     for  (int  i  =  1 ; i < nums.length; i++) {         for  (int  j  =  0 ; j < i; j++) {             if  (nums[i] > nums[j]) {                 dp[i] = Math.max(dp[i], dp[j] + 1 );             }         }         max = Math.max(max, dp[i]);     }     return  max; } public  int  knapsack (int  W, int [] wt, int [] val)  {    int  n  =  wt.length;     int [][] dp = new  int [n + 1 ][W + 1 ];     for  (int  i  =  1 ; i <= n; i++) {         for  (int  w  =  1 ; w <= W; w++) {             if  (wt[i - 1 ] <= w) {                 dp[i][w] = Math.max(val[i - 1 ] + dp[i - 1 ][w - wt[i - 1 ]], dp[i - 1 ][w]);             } else  {                 dp[i][w] = dp[i - 1 ][w];             }         }     }     return  dp[n][W]; } public  int  minDistance (String word1, String word2)  {    int  m  =  word1.length(), n = word2.length();     int [][] dp = new  int [m + 1 ][n + 1 ];     for  (int  i  =  0 ; i <= m; i++) dp[i][0 ] = i;     for  (int  j  =  0 ; j <= n; j++) dp[0 ][j] = j;     for  (int  i  =  1 ; i <= m; i++) {         for  (int  j  =  1 ; j <= n; j++) {             if  (word1.charAt(i - 1 ) == word2.charAt(j - 1 )) {                 dp[i][j] = dp[i - 1 ][j - 1 ];             } else  {                 dp[i][j] = 1  + Math.min(dp[i - 1 ][j - 1 ],                      Math.min(dp[i][j - 1 ], dp[i - 1 ][j]));             }         }     }     return  dp[m][n]; } 
 
 
多维动态规划(Multi-dimensional DP) 核心思想 :扩展DP状态到多个维度适用场景 :复杂约束条件的最优化问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public  int  maxProfit (int [] prices)  {    if  (prices == null  || prices.length == 0 ) return  0 ;     int  n  =  prices.length;     int [][] dp = new  int [n][3 ];                    dp[0 ][0 ] = -prices[0 ];     for  (int  i  =  1 ; i < n; i++) {         dp[i][0 ] = Math.max(dp[i - 1 ][0 ], dp[i - 1 ][2 ] - prices[i]);         dp[i][1 ] = dp[i - 1 ][0 ] + prices[i];         dp[i][2 ] = Math.max(dp[i - 1 ][1 ], dp[i - 1 ][2 ]);     }     return  Math.max(dp[n - 1 ][1 ], dp[n - 1 ][2 ]); } public  boolean  isMatch (String s, String p)  {    int  m  =  s.length(), n = p.length();     boolean [][] dp = new  boolean [m + 1 ][n + 1 ];     dp[0 ][0 ] = true ;     for  (int  j  =  1 ; j <= n; j++) {         if  (p.charAt(j - 1 ) == '*' ) {             dp[0 ][j] = dp[0 ][j - 2 ];         }     }     for  (int  i  =  1 ; i <= m; i++) {         for  (int  j  =  1 ; j <= n; j++) {             if  (s.charAt(i - 1 ) == p.charAt(j - 1 ) || p.charAt(j - 1 ) == '.' ) {                 dp[i][j] = dp[i - 1 ][j - 1 ];             } else  if  (p.charAt(j - 1 ) == '*' ) {                 if  (s.charAt(i - 1 ) == p.charAt(j - 2 ) || p.charAt(j - 2 ) == '.' ) {                     dp[i][j] = dp[i][j - 2 ] || dp[i - 1 ][j];                 } else  {                     dp[i][j] = dp[i][j - 2 ];                 }             }         }     }     return  dp[m][n]; } public  int  maximalSquare (char [][] matrix)  {    if  (matrix == null  || matrix.length == 0 ) return  0 ;     int  m  =  matrix.length, n = matrix[0 ].length;     int [][] dp = new  int [m + 1 ][n + 1 ];     int  maxLen  =  0 ;     for  (int  i  =  1 ; i <= m; i++) {         for  (int  j  =  1 ; j <= n; j++) {             if  (matrix[i - 1 ][j - 1 ] == '1' ) {                 dp[i][j] = Math.min(dp[i - 1 ][j - 1 ], Math.min(dp[i - 1 ][j], dp[i][j - 1 ])) + 1 ;                 maxLen = Math.max(maxLen, dp[i][j]);             }         }     }     return  maxLen * maxLen; } 
 
 
技巧(Tricks) 核心思想 :各种实用技巧和小算法适用场景 :位操作、数学技巧、随机化等
```java // 位操作技巧 public int hammingWeight(int n) {     int count = 0;     while (n != 0) {         n &= (n - 1); // 清除最低位的1         count++;     }     return count; }
// 洗牌算法(Fisher-Yates) public void shuffle(int[] nums) {     Random rand = new Random();     for (int i = nums.length - 1; i > 0; i—) {         int j = rand.nextInt(i + 1);         swap(nums, i, j);     } }
// 蓄水池抽样 public int getRandom(ListNode head) {     Random rand = new Random();     int res = 0, i = 1;     ListNode curr = head;     while (curr != null) {         if (rand.nextInt(i) == 0) {             res = curr.val;         }         i++;         curr = curr.next;     }     return res; }
// 摩尔投票法(多数元素) public int majorityElement(int[] nums) {     int count = 0, candidate = 0;     for (int num : nums) {         if (count == 0) candidate = num;         count += (num == candidate) ? 1 : -1;     }     return candidate; }
// 快速幂 public double myPow(double x, int n) {     long N = n;     if (N < 0) {         x = 1 / x;         N = -N;     }     double res = 1;