📂 题型核心:同向快慢指针
这类题目属于双指针中的同向分类。其核心在于通过两个指针同向移动,将数组分为“已处理区域”和“待探索区域”,从而在 O(1) 空间内完成原地修改。
🛠️ 统一通用模板 (Java)
绝大多数原地修改题目(去重、移除、过滤)都可以套用以下逻辑:
1 2 3 4 5 6 7 8 9 10 11
| public int process(int[] nums) { int slow = 0; for (int fast = 0; fast < nums.length; fast++) { if (满足特定条件(nums[fast])) { nums[slow] = nums[fast]; slow++; } } return slow; }
|
1. [LC 26] 删除有序数组中的重复项
💻 我的题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public int removeDuplicates(int[] nums) { if (nums == null || 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; } }
|
📈 复杂度分析
- 时间复杂度:O(N)。
fast 指针遍历一遍数组。
- 空间复杂度:O(1)。原地修改,只使用了两个变量。
2. [LC 27] 移除元素
- 题目链接:27. Remove Element
- 标签:数组、双指针、原地修改、字节高频
- 核心思路:
fast 负责观察每一个元素是否等于 val,slow 只有在发现合法元素时才接纳并移动。
💻 我的题解
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
| class Solution { public int removeElement(int[] nums, int val) { if(nums == null || nums.length == 0 ){ return 0; } int slow = 0, fast = 0; while (fast < nums.length) { if(nums[fast] == val){ fast++; } else{ nums[slow] = nums[fast]; slow++; fast++; } } return slow; } }
|
🚀 优化建议 (Standard Template)
1 2 3 4 5 6
| for (int fast = 0; fast < nums.length; fast++) { if (nums[fast] != val) { nums[slow++] = nums[fast]; } }
|
📈 复杂度分析
3. [LC 283] 移动零
- 题目链接:283. Move Zeroes
- 标签:数组、双指针、逻辑复用、字节跳动高频
- 核心思路:将“移动零”看作“移除所有值为 0 的元素”。先利用快慢指针挤压非零元素,再后期手动补零。
💻 我的题解
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
| class Solution { public void moveZeroes(int[] nums) { if(nums == null || nums.length == 0){ return; } int point = removeZero(nums); for(int i = point; i < nums.length; i++){ nums[i] = 0; } }
int removeZero(int[] nums){ int slow = 0, fast = 0; while (fast < nums.length) { if(nums[fast] == 0){ fast++; } else { nums[slow] = nums[fast]; slow++; fast++; } } return slow; } }
|
📈 复杂度分析