内容来自刘宇波老师玩转算法面试
1、二分查找法
二分查找法(Java 实现)
| template<typename T> |
| int binarySearch1(T arr[], int n, T target) { |
| |
| int l = 0; |
| int r = n - 1; |
| int mid; |
| |
| |
| while (l <= r) { |
| mid = l + (r - l) / 2; |
| if (arr[mid] == target) return mid; |
| if (arr[mid] < target) l = mid + 1; |
| else r = mid - 1; |
| } |
| |
| return -1; |
| } |
| |
| template<typename T> |
| int binarySearch2(T arr[], int n, T target) { |
| |
| int l = 0; |
| int r = n; |
| int mid; |
| |
| |
| while (l < r) { |
| mid = l + (r - l) / 2; |
| if (arr[mid] == target) return mid; |
| if (arr[mid] < target) l = mid + 1; |
| else r = mid; |
| } |
| |
| return -1; |
| } |
2、移动零
283 - 移动零
| |
| |
| |
| |
| public static void moveZeroes1(int[] nums) { |
| int[] temp = new int[nums.length]; |
| int index = 0; |
| for (int num : nums) { |
| if (num != 0) temp[index++] = num; |
| } |
| System.arraycopy(temp, 0, nums, 0, temp.length); |
| } |
| |
| |
| |
| |
| |
| public static void moveZeroes2(int[] nums) { |
| |
| int p = 0; |
| for (int num : nums) { |
| if (num != 0) nums[p++] = num; |
| } |
| Arrays.fill(nums, p, nums.length, 0); |
| } |
| |
| |
| |
| |
| |
| public static void moveZeroes3(int[] nums) { |
| |
| int p = 0; |
| for (int i = 0; i < nums.length; i++) { |
| if (nums[i] != 0) { |
| if (p != i) swap(nums, p++, i); |
| else p++; |
| } |
| } |
| } |
| |
| private static void swap(int[] nums, int a, int b) { |
| int k = nums[a]; |
| nums[a] = nums[b]; |
| nums[b] = k; |
| } |
更多问题
27 - 移除元素
26 - 删除有序数组中的重复项
80 - 删除有序数组中的重复项 II
3、颜色分类
75 - 颜色分类
| |
| |
| |
| |
| |
| public static void sortColors1(int[] nums) { |
| |
| |
| int R = 3; |
| int[] cnt = new int[R]; |
| for (int num : nums) cnt[num]++; |
| |
| |
| int[] index = new int[R + 1]; |
| for (int i = 0; i < R; i++) { |
| |
| index[i + 1] = index[i] + cnt[i]; |
| } |
| |
| for (int i = 0; i + 1 < index.length; i++) { |
| |
| for (int j = index[i]; j < index[i + 1]; j++) nums[j] = i; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| public static void sortColors2(int[] nums) { |
| int p1 = -1; |
| int p2 = nums.length; |
| |
| int i = 0; |
| while (i < p2) { |
| if (nums[i] == 0) swap(nums, ++p1, i++); |
| else if (nums[i] == 2) swap(nums, --p2, i); |
| else i++; |
| } |
| } |
| |
| private static void swap(int[] nums, int a, int b) { |
| int k = nums[a]; |
| nums[a] = nums[b]; |
| nums[b] = k; |
| } |
更多问题
88 - 合并两个有序数组
215 - 数组中的第K个最大元素
4、两数之和 II - 输入有序数组
167 - 两数之和 II - 输入有序数组
更多问题
125 - 验证回文串
344 - 反转字符串
345 - 反转字符串中的元音字母
11 - 盛最多水的容器
4.1、二分搜索思路

| public static int[] twoSum(int[] numbers, int target) { |
| for (int i = 0; i < numbers.length; i++) { |
| int complement = target - numbers[i]; |
| int res = binarySearch(numbers, i + 1, numbers.length - 1, complement); |
| if (res != -1) return new int[]{i + 1, res + 1}; |
| } |
| return new int[]{-1, -1}; |
| } |
| |
| private static int binarySearch(int[] arr, int l, int r, int target) { |
| int mid; |
| |
| while (l <= r) { |
| mid = l + (r - l) / 2; |
| if (arr[mid] == target) return mid; |
| else if (arr[mid] > target) r = mid - 1; |
| else l = mid + 1; |
| } |
| |
| return -1; |
| } |
4.2、对撞指针思路

| public static int[] twoSum(int[] numbers, int target) { |
| int p1 = 0; |
| int p2 = numbers.length - 1; |
| while (p1 < p2) { |
| int sum = numbers[p1] + numbers[p2]; |
| if (sum == target) return new int[]{p1 + 1, p2 + 1}; |
| else if (sum < target) p1++; |
| else p2--; |
| } |
| return new int[]{-1, -1}; |
| } |
5、滑动窗口
滑动窗口算法通常使用双指针来维护窗口的左右边界,右指针用于扩展窗口,左指针用于缩小窗口
在每一次移动窗口时,我们都可以根据窗口的状态来更新答案
5.1、长度最小的子数组
209 - 长度最小的子数组
minSubArrayLen1 和 minSubArrayLen2 均可

| public static int minSubArrayLen1(int target, int[] nums) { |
| |
| int l = 0; |
| int r = -1; |
| int sum = 0; |
| int res = nums.length + 1; |
| |
| |
| while (l < nums.length) { |
| if (r + 1 < nums.length && sum < target) sum += nums[++r]; |
| else sum -= nums[l++]; |
| |
| if (sum >= target) res = Math.min(res, r - l + 1); |
| } |
| |
| return res != nums.length + 1 ? res : 0; |
| } |
| |
| public static int minSubArrayLen2(int target, int[] nums) { |
| |
| int l = 0; |
| int r = -1; |
| int sum = 0; |
| int res = nums.length + 1; |
| |
| |
| while (r + 1 < nums.length) { |
| |
| while (r + 1 < nums.length && sum < target) sum += nums[++r]; |
| if (sum >= target) res = Math.min(res, r - l + 1); |
| |
| |
| while (l <= r && sum >= target) { |
| sum -= nums[l++]; |
| if (sum >= target) res = Math.min(res, r - l + 1); |
| } |
| } |
| |
| return res != nums.length + 1 ? res : 0; |
| } |
5.2、无重复字符的最长子串
3 - 无重复字符的最长子串
推荐 lengthOfLongestSubstring3

| public static int lengthOfLongestSubstring1(String s) { |
| |
| int l = 0; |
| int r = -1; |
| int[] freq = new int[256]; |
| int res = 0; |
| |
| |
| while (l < s.length()) { |
| if (r + 1 < s.length() && freq[s.charAt(r + 1)] == 0) freq[s.charAt(++r)]++; |
| else freq[s.charAt(l++)]--; |
| |
| res = Math.max(res, r - l + 1); |
| } |
| |
| return res; |
| } |
| |
| public static int lengthOfLongestSubstring2(String s) { |
| |
| int l = 0; |
| int r = -1; |
| int[] index = new int[256]; |
| Arrays.fill(index, -1); |
| int res = 0; |
| |
| |
| while (l < s.length()) { |
| if (r + 1 < s.length() && index[s.charAt(r + 1)] == -1) index[s.charAt(++r)] = r; |
| else index[s.charAt(l++)] = -1; |
| |
| res = Math.max(res, r - l + 1); |
| } |
| |
| return res; |
| } |
| |
| public static int lengthOfLongestSubstring3(String s) { |
| |
| int l = 0; |
| int r = -1; |
| int[] index = new int[256]; |
| Arrays.fill(index, -1); |
| int res = 0; |
| |
| |
| while (r + 1 < s.length()) { |
| |
| while (r + 1 < s.length() && index[s.charAt(r + 1)] == -1) index[s.charAt(++r)] = r; |
| res = Math.max(res, r - l + 1); |
| |
| |
| if (r + 1 < s.length()) { |
| int i; |
| for (i = l; i <= index[s.charAt(r + 1)]; i++) index[s.charAt(i)] = -1; |
| l = i; |
| } |
| } |
| |
| return res; |
| } |
6、更多题目
6.1、找到字符串中所有字母异位词
438 - 找到字符串中所有字母异位词
推荐 findAnagrams1 和 findAnagrams3
| public static List<Integer> findAnagrams1(String s, String p) { |
| List<Integer> list = new ArrayList<>(); |
| if (s.length() < p.length()) return list; |
| |
| int[] freq_p = new int[26]; |
| for (char c : p.toCharArray()) freq_p[c - 'a']++; |
| |
| |
| int l = 0; |
| int r = l + p.length() - 1; |
| int[] freq_s = new int[26]; |
| for (int i = l; i <= r; i++) freq_s[s.charAt(i) - 'a']++; |
| if (same(freq_s, freq_p)) list.add(l); |
| |
| |
| while (r + 1 < s.length()) { |
| freq_s[s.charAt(++r) - 'a']++; |
| freq_s[s.charAt(l++) - 'a']--; |
| if (same(freq_s, freq_p)) list.add(l); |
| } |
| |
| return list; |
| } |
| |
| public static List<Integer> findAnagrams2(String s, String p) { |
| List<Integer> list = new ArrayList<>(); |
| if (s.length() < p.length()) return list; |
| |
| int[] freq_p = new int[26]; |
| for (char c : p.toCharArray()) freq_p[c - 'a']++; |
| |
| |
| int l = 0; |
| int r = -1; |
| int[] freq_s = new int[26]; |
| |
| |
| while (r + 1 < s.length()) { |
| if (r - l + 1 != p.length()) { |
| freq_s[s.charAt(++r) - 'a']++; |
| if (r - l + 1 == p.length() && same(freq_s, freq_p)) list.add(l); |
| } else { |
| freq_s[s.charAt(++r) - 'a']++; |
| freq_s[s.charAt(l++) - 'a']--; |
| if (same(freq_s, freq_p)) list.add(l); |
| } |
| } |
| |
| return list; |
| } |
| |
| public static List<Integer> findAnagrams3(String s, String p) { |
| List<Integer> list = new ArrayList<>(); |
| if (s.length() < p.length()) return list; |
| |
| int[] freq_p = new int[26]; |
| for (char c : p.toCharArray()) freq_p[c - 'a']++; |
| |
| int[] freq_s = new int[26]; |
| for (int i = 0; i < s.length(); i++) { |
| freq_s[s.charAt(i) - 'a']++; |
| |
| |
| if (i >= p.length() - 1) { |
| if (same(freq_s, freq_p)) list.add(i - p.length() + 1); |
| freq_s[s.charAt(i - p.length() + 1) - 'a']--; |
| } |
| } |
| |
| return list; |
| } |
| |
| private static boolean same(int[] freq_s, int[] freq_p) { |
| for (int i = 0; i < 26; i++) { |
| if (freq_s[i] != freq_p[i]) return false; |
| } |
| return true; |
| } |
6.2、最小覆盖子串
76 - 最小覆盖子串
minWindow1 和 minWindow2 均可
| public static String minWindow1(String s, String t) { |
| int[] freq_t = new int[256]; |
| for (char c : t.toCharArray()) freq_t[c]++; |
| |
| int startIndex = -1; |
| int minLength = s.length() + 1; |
| |
| |
| int l = 0; |
| int r = -1; |
| int[] freq_s = new int[256]; |
| int sCnt = 0; |
| |
| |
| while (l < s.length()) { |
| if (r + 1 < s.length() && sCnt < t.length()) { |
| char c = s.charAt(r + 1); |
| freq_s[c]++; |
| if (freq_s[c] <= freq_t[c]) sCnt++; |
| r++; |
| } else { |
| if (sCnt == t.length() && r - l + 1 < minLength) { |
| minLength = r - l + 1; |
| startIndex = l; |
| } |
| |
| char c = s.charAt(l); |
| freq_s[c]--; |
| if (freq_s[c] < freq_t[c]) sCnt--; |
| l++; |
| } |
| } |
| |
| if (startIndex != -1) return s.substring(startIndex, startIndex + minLength); |
| return ""; |
| } |
| |
| public static String minWindow2(String s, String t) { |
| int[] freq_t = new int[256]; |
| for (char c : t.toCharArray()) freq_t[c]++; |
| |
| int startIndex = -1; |
| int minLength = s.length() + 1; |
| |
| |
| int l = 0; |
| int r = -1; |
| int sCnt = 0; |
| int[] freq_s = new int[256]; |
| |
| |
| while (r + 1 < s.length()) { |
| while (r + 1 < s.length() && sCnt < t.length()) { |
| char c = s.charAt(r + 1); |
| freq_s[c]++; |
| if (freq_s[c] <= freq_t[c]) sCnt++; |
| r++; |
| } |
| |
| while (sCnt == t.length()) { |
| if (r - l + 1 < minLength) { |
| startIndex = l; |
| minLength = r - l + 1; |
| } |
| |
| char c = s.charAt(l); |
| freq_s[c]--; |
| if (freq_s[c] < freq_t[c]) sCnt--; |
| l++; |
| } |
| } |
| |
| if (startIndex != -1) return s.substring(startIndex, startIndex + minLength); |
| return ""; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步