day4|24.两两交换链表的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II
用虚拟头结点,这样会方便很多。
本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。
题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode cur = new ListNode();
ListNode listNode1 = head;
ListNode listNode2 = new ListNode();
cur.next=listNode1;
ListNode head2=head.next;
while (cur.next!= null && cur.next.next!= null){
listNode2.next=cur.next.next;
cur.next.next=listNode2.next.next;
listNode2.next.next=cur.next;
cur.next=cur.next.next;
if(listNode2.next.next.next!=null&&listNode2.next.next.next.next!=null)
listNode2.next.next.next=listNode2.next.next.next.next;
}
return head2;
}
}
if(listNode2.next.next.next!=null&&listNode2.next.next.next.next!=null)
listNode2.next.next.next=listNode2.next.next.next.next;
这个是为了使链表能够接上,提前指向下下节点
双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head.next==null && n==1){
return head.next;
}
ListNode listNode = new ListNode();
ListNode cur= new ListNode();
cur.next=head;
ListNode res= new ListNode();
res.next=head;
listNode.next=head;
int p=0;
int q=0;
while (cur.next.next!= null){
if(q-p !=n){
cur.next=cur.next.next;
q++;
}else {
cur.next=cur.next.next;
listNode.next=listNode.next.next;
}
}
if(q-p!=n){
res.next= res.next.next;
}
listNode.next.next=listNode.next.next.next;
return res.next;
}
双指针妙用,一趟就行
if(q-p!=n){
res.next= res.next.next;
}
注意一种情况 就是删除头结点
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p=headA;
ListNode q=headB;
if(p==null||q==null)
return null;
int count=0;
while (p!=q && count<3){
if(p.next==null)
{
p=headB;
count++;
}else {
p=p.next;
}
if(q.next==null)
{
q=headA;
count++;
}else {
q=q.next;
}
}
return count>3?null:p;
}
}
两个数组 最后必然相同,知道这个就方便了
[4,1,8,4,5 5,0,1,8,4,5]
[5,0,1,8,4,5 4,1,8,4,5]
算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null)
return null;
ListNode fast=head;
ListNode slow=head;
while (fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
ListNode index1=fast;
ListNode index2=head;
while (index2!=index1){
index2=index2.next;
index1=index1.next;
}
return index1;
}
}
return null;
}
}
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
ListNode index1=fast;
ListNode index2=head;
while (index2!=index1){
index2=index2.next;
index1=index1.next;
}
双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。
换言之,双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算。
对撞指针是指在有序数组中,将指向最左侧的索引定义为左指针(left)
,最右侧的定义为右指针(right)
,然后从两头向中间进行数组遍历。
对撞数组适用于有序数组,也就是说当你遇到题目给定有序数组时,应该第一时间想到用对撞指针解题。
两数之和
二分法
快慢指针也是双指针,但是两个指针从同一侧开始遍历数组,将这两个指针分别定义为快指针(fast)
和慢指针(slow)
,两个指针以不同的策略移动,直到两个指针的值相等(或其他特殊条件)为止,如fast每次增长两个,slow每次增长一个。
以LeetCode 141.环形链表为例,,判断给定链表中是否存在环,可以定义快慢两个指针,快指针每次增长一个,而慢指针每次增长两个,最后两个指针指向节点的值相等,则说明有环。就好像一个环形跑道上有一快一慢两个运动员赛跑,如果时间足够长,跑地快的运动员一定会赶上慢的运动员。