-
两数之和(Two Sum):
- 目标:在数组中找到两个数,使它们的和等于给定的目标值。
- 解题思路:使用哈希表(HashMap)来存储每个元素及其索引,遍历数组,查找是否存在与当前元素的差等于目标值的另一个元素。
- 代码示例:
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); } throw new IllegalArgumentException("No two sum solution"); }
-
反转链表(Reverse Linked List):
- 目标:将链表反转,即将链表的指针方向反转。
- 解题思路:使用三个指针,分别指向当前节点、前一个节点和后一个节点,迭代遍历链表进行指针反转。
- 代码示例:
public ListNode reverseList(ListNode head) { ListNode prev = null; ListNode current = head; while (current != null) { ListNode nextTemp = current.next; current.next = prev; prev = current; current = nextTemp; } return prev; }
-
合并两个有序数组(Merge Sorted Arrays):
- 目标:将两个有序数组合并成一个有序数组。
- 解题思路:从后往前遍历两个数组,依次比较较大的元素放入合并后的数组的末尾。
- 代码示例:
public void merge(int[] nums1, int m, int[] nums2, int n) { int i = m - 1; int j = n - 1; int k = m + n - 1; while (i >= 0 && j >= 0) { if (nums1[i] > nums2[j]) { nums1[k--] = nums1[i--]; } else { nums1[k--] = nums2[j--]; } } while (j >= 0) { nums1[k--] = nums2[j--]; } }
-
快速排序(Quick Sort):
- 目标:将数组排序。
- 解题思路:选择一个基准元素,将数组分成小于基准和大于基准的两部分,然后递归地对这两部分进行快速排序。
- 代码示例:
public void quickSort(int[] arr, int low, int high) { if (low < high) { int pivotIndex = partition(arr, low, high); quickSort(arr, low, pivotIndex - 1); quickSort(arr, pivotIndex + 1, high); } } private int partition(int[] arr, int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j < high; j++) { if (arr[j] < pivot) { i++; swap(arr, i, j); } } swap(arr, i + 1, high); return i + 1; } private void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
-
归并排序(Merge Sort):
- 目标:将数组排序。
- 解题思路:使用分治法,将数组逐步划分为更小的子数组,然后合并这些子数组,保证合并后的数组依然有序。
- 代码示例:
public void mergeSort(int[] arr, int left, int right) { if (left < right) { int mid = left + (right - left) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); merge(arr, left, mid, right); } } private void merge(int[] arr, int left, int mid, int right) { int[] temp = new int[right - left + 1]; int i = left; int j = mid + 1; int k = 0; while (i <= mid && j <= right) { if (arr[i] < arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } while (i <= mid) { temp[k++] = arr[i++]; } while (j <= right) { temp[k++] = arr[j++]; } System.arraycopy(temp, 0, arr, left, temp.length); }
-
二分查找(Binary Search):
- 目标:在有序数组中查找指定元素的位置。
- 解题思路:通过不断缩小查找范围,每次比较中间元素与目标值的大小,以确定在左半部分还是右半部分继续查找。
- 代码示例:
public int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] == target) { return mid; } else if (arr[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return -1; }
-
斐波那契数列(Fibonacci Sequence):
- 目标:求解斐波那契数列的第n项。
- 解题思路:使用递归或动态规划,根
据前两项计算当前项的值。
- 代码示例(递归):
public int fibonacci(int n) { if (n <= 1) { return n; } return fibonacci(n - 1) + fibonacci(n - 2); }
-
最长公共子序列(Longest Common Subsequence):
- 目标:找出两个字符串的最长公共子序列。
- 解题思路:使用动态规划,构建一个二维数组,记录两个字符串的所有子问题的解。
- 代码示例:
public int longestCommonSubsequence(String text1, String text2) { int m = text1.length(); int n = text2.length(); int[][] dp = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (text1.charAt(i - 1) == text2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } } return dp[m][n]; }
-
动态规划背包问题(Knapsack Problem):
- 目标:在给定一定容量的背包和一系列物品的情况下,选择一些物品使其价值最大化。
- 解题思路:使用动态规划,构建一个二维数组,记录不同背包容量下选择不同物品的最大价值。
- 代码示例:
public int knapsack(int[] weights, int[] values, int capacity) { int n = weights.length; int[][] dp = new int[n + 1][capacity + 1]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= capacity; j++) { if (weights[i - 1] <= j) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]); } else { dp[i][j] = dp[i - 1][j]; } } } return dp[n][capacity]; }
-
最短路径算法(Dijkstra’s Algorithm):
- 目标:在加权图中找到从一个节点到另一个节点的最短路径。
- 解题思路:使用贪心算法,维护一个距离数组和一个标记数组,每次选择距离最短且未访问的节点进行松弛操作。
- 代码示例:
public int[] dijkstra(int[][] graph, int source) { int n = graph.length; int[] distances = new int[n]; Arrays.fill(distances, Integer.MAX_VALUE); distances[source] = 0; boolean[] visited = new boolean[n]; for (int i = 0; i < n - 1; i++) { int minDistance = Integer.MAX_VALUE; int minIndex = -1; for (int j = 0; j < n; j++) { if (!visited[j] && distances[j] < minDistance) { minDistance = distances[j]; minIndex = j; } } visited[minIndex] = true; for (int j = 0; j < n; j++) { if (!visited[j] && graph[minIndex][j] != 0 && distances[minIndex] != Integer.MAX_VALUE && distances[minIndex] + graph[minIndex][j] < distances[j]) { distances[j] = distances[minIndex] + graph[minIndex][j]; } } } return distances; }
-
最大子数组和(Maximum Subarray Sum):
- 目标:找到一个数组中连续子数组的最大和。
- 解题思路:使用动态规划,依次遍历数组元素,维护一个当前子数组的最大和和一个全局的最大和。
- 代码示例:
public int maxSubArray(int[] nums) { int maxEndingHere = nums[0]; int maxSoFar = nums[0]; for (int i = 1; i < nums.length; i++) { maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]); maxSoFar = Math.max(maxSoFar, maxEndingHere); } return maxSoFar; }
-
LRU缓存(Least Recently Used Cache):
- 目标:实现一个LRU缓存结构,即在缓存满时,删除最近最少使用的数据。
- 解题思路:使用哈希表和双向链表来实现缓存结构,每次访问数据时,将数据移到链表头部,当缓存满时,删除链表尾部的数据。
- 代码示例:
class LRUCache { private Map<Integer, Integer> cache; private LinkedList<Integer> keys; private int capacity; public LRUCache(int capacity) { this.cache = new HashMap<>(); this.keys = new LinkedList<>(); this.capacity = capacity; } public int get(int key) { if (!cache.containsKey(key)) { return -1; } keys.remove((Integer) key); keys.addFirst(key); return cache.get(key); } public void put(int key, int value) { if (cache.containsKey(key)) { keys.remove((Integer) key); } else if (cache.size() >= capacity) { int lastKey = keys.removeLast(); cache.remove(lastKey); } cache.put(key, value); keys.addFirst(key); } }
-
判断链表是否有环(Detect Cycle in Linked List):
-
目标:判断一个链表是否有环。
-
解题思路:使用快慢指针,如果存在环,快指针最终会追上慢指针;如果不存在环,快指针会先到达链表末尾。
-
代码示例:
public boolean hasCycle(ListNode head) { if (head == null || head.next == null) { return false; } ListNode slow = head; ListNode fast = head.next; while (slow != fast) { if (fast == null || fast.next == null) { return false; } slow = slow.next; fast = fast.next.next; } return true; }
-
-
树的遍历(Tree Traversals):
- 目标:遍历树的所有节点。
- 解题思路:树的遍历有前序、中序、后序和层次遍历。前序遍历首先访问根节点,然后递归遍历左右子树;中序遍历先遍历左子树,然后访问根节点,再遍历右子树;后序遍历先遍历左右子树,最后访问根节点;层次遍历从上到下逐层遍历。
- 代码示例(前序遍历):
public void preorderTraversal(TreeNode root) { if (root != null) { System.out.println(root.val); preorderTraversal(root.left); preorderTraversal(root.right); } }
-
求解平方根(Square Root):
- 目标:实现求解一个数的平方根。
- 解题思路:使用二分查找,查找平方根的近似值。
- 代码示例:
public double sqrt(double x) { double left = 0; double right = x; double epsilon = 1e-7; while (right - left > epsilon) { double mid = left + (right - left) / 2; if (mid * mid > x) { right = mid; } else { left = mid; } } return left; }
-
字符串反转(Reverse String):
- 目标:将一个字符串进行反转操作。
- 解题思路:使用双指针,交换头尾字符的位置,依次向中间靠拢。
- 代码示例:
public String reverseString(String s) { char[] chars = s.toCharArray(); int left = 0; int right = chars.length - 1; while (left < right) { char temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; left++; right--; } return new String(chars); }
-
字符串匹配算法(String Matching):
- 目标:在文本中查找特定模式。
- 解题思路:使用KMP算法(Knuth-Morris-Pratt算法),预处理模式串,构建部分匹配表,然后在文本串中进行匹配。
- 代码示例(部分匹配表构建):
public int[] buildPartialMatchTable(String pattern) { int[] table = new int[pattern.length()]; int j = 0; for (int i = 1; i < pattern.length(); i++) { while (j > 0 && pattern.charAt(i) != pattern.charAt(j)) { j = table[j - 1]; } if (pattern.charAt(i) == pattern.charAt(j)) { j++; } table[i] = j; } return table; }
-
最长上升子序列(Longest Increasing Subsequence):
- 目标:找出数组中最长的上升子序列的长度。
- 解题思路:使用动态规划,维护一个数组,记录以每个元素结尾的最长上升子序列长度。
- 代码示例:
public int longestIncreasingSubsequence(int[] nums) { int n = nums.length; int[] dp = new int[n]; Arrays.fill(dp, 1); for (int i = 1; i < n; i++) { for (int j = 0; j < i; j++) { if (nums[i] > nums[j]) { dp[i] = Math.max(dp[i], dp[j] + 1); } } } int maxLength = 0; for (int len : dp) { maxLength = Math.max(maxLength, len); } return maxLength; }
-
滑动窗口算法(Sliding Window):
- 目标:用于解决一些数组/字符串相关的问题,如最小覆盖子串、最长连续子数组等。
- 解题思路:使用双指针,通过滑动窗口来在数组/字符串上移动,以解决特定问题。
- 代码示例(最小覆盖子串):
public String minWindowSubstring(String s, String t) { int[] targetFreq = new int[128]; for (char c : t.toCharArray()) { targetFreq[c]++; } int left = 0; int right = 0; int minLen = Integer.MAX_VALUE; int minStart = 0; int count = t.length(); while (right < s.length()) { if (targetFreq[s.charAt(right)] > 0) { count--; } targetFreq[s.charAt(right)]--; right++; while (count == 0) { if (right - left < minLen) { minLen = right - left; minStart = left; } targetFreq[s.charAt(left)]++; if (targetFreq[s.charAt(left)] > 0) { count++; } left++; } } return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen); }