13.1 数组与字符串
面试重要程度:⭐⭐⭐⭐⭐
常见提问方式: "手写双指针算法" "实现滑动窗口" "KMP字符串匹配原理"
预计阅读时间:40分钟
🎯 双指针技巧
对撞指针
/** * 双指针经典问题解决方案 */ public class TwoPointerSolutions { /** * 两数之和 - 有序数组版本 * LeetCode 167: Two Sum II - Input array is sorted */ public int[] twoSum(int[] numbers, int target) { int left = 0, right = numbers.length - 1; while (left < right) { int sum = numbers[left] + numbers[right]; if (sum == target) { return new int[]{left + 1, right + 1}; // 题目要求1-indexed } else if (sum < target) { left++; } else { right--; } } return new int[]{-1, -1}; // 未找到 } /** * 三数之和 * LeetCode 15: 3Sum */ public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> result = new ArrayList<>(); Arrays.sort(nums); // 先排序 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; int target = -nums[i]; while (left < right) { int sum = nums[left] + nums[right]; if (sum == target) { result.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 < target) { left++; } else { right--; } } } return result; } /** * 盛最多水的容器 * LeetCode 11: Container With Most Water */ public int maxArea(int[] height) { int left = 0, right = height.length - 1; int maxWater = 0; while (left < right) { int width = right - left; int currentWater = Math.min(height[left], height[right]) * width; maxWater = Math.max(maxWater, currentWater); // 移动较短的指针 if (height[left] < height[right]) { left++; } else { right--; } } return maxWater; } /** * 回文字符串验证 * LeetCode 125: Valid Palindrome */ public boolean isPalindrome(String s) { int left = 0, right = s.length() - 1; while (left < right) { // 跳过非字母数字字符 while (left < right && !Character.isLetterOrDigit(s.charAt(left))) { left++; } while (left < right && !Character.isLetterOrDigit(s.charAt(right))) { right--; } if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) { return false; } left++; right--; } return true; } }
快慢指针
/** * 快慢指针应用 */ public class FastSlowPointer { /** * 移除重复元素 * LeetCode 26: Remove Duplicates from Sorted Array */ public int removeDuplicates(int[] nums) { if (nums.length == 0) return 0; int slow = 0; // 慢指针指向不重复元素的末尾 for (int fast = 1; fast < nums.length; fast++) { if (nums[fast] != nums[slow]) { slow++; nums[slow] = nums[fast]; } } return slow + 1; } /** * 移动零 * LeetCode 283: Move Zeroes */ public void moveZeroes(int[] nums) { int slow = 0; // 慢指针指向非零元素的末尾 // 第一遍:将非零元素移到前面 for (int fast = 0; fast < nums.length; fast++) { if (nums[fast] != 0) { nums[slow] = nums[fast]; slow++; } } // 第二遍:将剩余位置填充为0 while (slow < nums.length) { nums[slow] = 0; slow++; } } /** * 颜色分类(荷兰国旗问题) * LeetCode 75: Sort Colors */ public void sortColors(int[] nums) { int left = 0, right = nums.length - 1; int current = 0; while (current <= right) { if (nums[current] == 0) { swap(nums, left, current); left++; current++; } else if (nums[current] == 2) { swap(nums, current, right); right--; // 注意:这里current不自增,因为交换过来的元素还需要检查 } else { current++; } } } private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }
🪟 滑动窗口算法
固定窗口大小
/** * 滑动窗口算法实现 */ public class SlidingWindowSolutions { /** * 长度为K的子数组的最大值 * LeetCode 239: Sliding Window Maximum */ public int[] maxSlidingWindow(int[] nums, int k) { if (nums.length == 0 || k == 0) return new int[0]; int[] result = new int[nums.length - k + 1]; Deque<Integer> deque = new ArrayDeque<>(); // 存储索引 for (int i = 0; i < nums.length; i++) { // 移除窗口外的元素 while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) { deque.pollFirst(); } // 移除比当前元素小的元素(保持单调递减) while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) { deque.pollLast(); } deque.offerLast(i); // 当窗口大小达到k时,记录最大值 if (i >= k - 1) { result[i - k + 1] = nums[deque.peekFirst()]; } } return result; } /** * 字符串中所有字母异位词 * LeetCode 438: Find All Anagrams in a String */ public List<Integer> findAnagrams(String s, String p) { List<Integer> result = new ArrayList<>(); if (s.length() < p.length()) return result; int[] pCount = new int[26]; int[] windowCount = new int[26]; // 统计p中字符频率 for (char c : p.toCharArray()) { pCount[c - 'a']++; } int windowSize = p.length(
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经