前言
今日练习目的:掌握两个指针通向遍历同一序列的解法,快针通常用于寻找目标,慢针用于记录写入位置
283:移动零
题目要求:给定一个数组,讲数组中为0的元素放在数组最后,同时保持非0元素的相对顺序
核心思路
定义一个快指针:快速遍历数组所有元素
一个慢指针:指向下一个非0元素应该存放的位置
具体流程:
fast从头扫描到尾
遇到非零元素:将其放在slow位置,slow++
最后slow之后的元素全部为0
代码实现
java
int slow=0;
for(int fast=0;fast<nums.length;fast++){
if(nums[fast]!=0){
int temp=nums[fast];
nums[fast]=nums[slow];
nums[slow]=temp;
slow++;
}
}
总结
要有快慢指针思想:同一个数组中寻找元素
进阶写法:减少时间复杂度
把非0往前放,同时把0自动丢到后面
27:移动元素
题目要求:给你一个数组nums和一个值val
要求:原地删除所有等于val的元素,返回删除后数组的新长度
核心思路
与上一题类似
代码实现
java
class Solution {
public int removeElement(int[] nums, int val) {
int slow=0;
int n=nums.length;
for(int fast=0;fast<n;fast++){
if(nums[fast]!=val){
int temp=nums[fast];
nums[fast]=nums[slow];
nums[slow]=temp;
slow++;
}
}
return slow;
}
}
总结
与上一题同样的思路
直接return slow,slow即为新数组长度
26:删除有序数组中的重复项
题目要求:一个非严格递增排列的数组 nums,
要求:原地删除重复元素,并返回新数组长度
核心思考
对于原地删除重复元素,我们要想到用后续不重复元素去覆盖前一个重复元素。
代码实现
java
class Solution {
public int removeDuplicates(int[] nums) {
int slow=0;
for(int fast=1;fast<nums.length;fast++){
if(nums[fast]!=nums[slow]){
slow++;
nums[slow]=nums[fast];
}
}
return slow+1;
}
}
本题进阶
如果题目给的数组元素顺序是完全无序的,我们应该想到HashSet 来去重
代码实现:
java
HashSet<Integer> set=new HashSet<>();
int slow=0;
for(int fast=0;fast<nums.length;fast++){
if(!set.contains(nums[fast]){
set.add(nums[fast]);
nums[slow]=nums[fast];
slow++;
}
}
return slow;
总结
| 情况 | 方法 |
|---|---|
| 有序数组 | 双指针 |
| 无序数组 | HashSet |
| 无序 + 不允许额外空间 | 排序 + 双指针 |
19:删除链表的倒数第N个节点
题目要求:给定一个链表head和一个整数n:
要求:删除倒数第n个节点
返回删除后的链表头
核心思路
其实思路还是一样,只不过本题换成了链表,代表了以下几个地方有修改
- 需要先创建一个虚拟头节点,让fast/slow与链表接轨
- 链表的遍历方式不一样:走一步为fast=fast.next
- 删除节点:slow.next = slow.next.next;直接改变指针定位
- 返回值:dummy.next、
代码实现
java
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
// fast先走n步
for (int i = 0; i < n; i++) {
fast = fast.next;
}
// 一起走
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
// 删除节点
slow.next = slow.next.next;
return dummy.next;
}
}
总结
掌握链表的语法
详见核心思路