代码随想录算法训练营第四天|24.两两交换链表中的节点、19.删除链表的倒数第N的节点、07.链表相交、142.环形链表II
24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
题解:只需要三个节点就可以了。让**pre指向虚拟头结点,然后确保pre.next和pre.next.next不为空,因为要操作的是这两个节点。**接下来就是交换操作:打个比方啊:节点 1,2,3,4,(这里节点1指虚拟头结点)2先指向4,3指向2,1再指向3,最后移动指针位置到下一位,也就是1给到2,循环到最后就完成了。
代码:
class Solution {public ListNode swapPairs(ListNode head) {ListNode dammyhead=new ListNode(0,head);ListNode pre=dammyhead;while(pre.next!=null && pre.next.next!=null){ListNode temp1=pre.next;ListNode temp2=pre.next.next;temp1.next=temp2.next;temp2.next=temp1;pre.next=temp2;pre=temp1;}return dammyhead.next;}
}
19.删除链表的倒数第N的节点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
题解:首先while循环求出链表的长度,使用虚拟头结点的话,删除倒数第n个节点,指针节点需要通过size-n步到达目标节点的前一个节点,然后将这个节点的next直接指向next.next。
代码:
class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dammyhead=new ListNode(0,head);ListNode curr=head;int size=0;while(curr!=null){size++;curr=curr.next;}curr=dammyhead;for(int i=0;i<size-n;i++){curr=curr.next;}curr.next=curr.next.next;return dammyhead.next;}
}
02.07.链表相交
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
图示两个链表在节点 c1
开始相交**:**
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。
题解:**这个方法真的太巧妙了!**首先让这两个链表的长度一致,也就是让长的那个链表先走几步,让其长度和短的链表长度一致。这样的话,就可以直接遍历短的链表,同时判断两条链表的节点值是否相等。需要注意的点是:统一一下将长链表作为第二条链表(当然也可以第一条,总之全局的链表的长的都要在一边)。看着代码理解。
代码:
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode curr1=headA;ListNode curr2=headB;int sizeA=len(headA);int sizeB=len(headB);if(sizeA>sizeB){ListNode temp=headA;headA=headB;headB=temp;}int gap=sizeA<sizeB?(sizeB-sizeA):(sizeA-sizeB);ListNode curr=headB;for(int i=0;i<gap;i++){curr=curr.next;}while(headA!=null){if(headA==curr){return headA;}headA=headA.next;curr=curr.next;}return null;}public int len(ListNode nodea){ListNode curr=nodea;int size=0;while(curr!=null){size++;curr=curr.next;}return size;}
}
142.环形链表II
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
题解:双指针。定义一个快指针一次走两步,一个慢指针一次走一步。当慢指针进入循环时,快指针可能已经走了n圈了。两个都在环内,快指针一次两步,慢指针一次一步,也就是说,快指针在以一次一步的距离接近慢指针,如果有环,二者一定会相遇。而且相遇的那个位置到入口节点的距离正好是头结点到入口节点的距离,所以从此位置开始慢指针和头结点进入while循环找相同的节点,那个节点就是入口节点。
代码:
public class Solution {public ListNode detectCycle(ListNode head) {ListNode fast=head;ListNode slow=head;while(fast!=null && fast.next!=null){fast=fast.next.next;slow=slow.next;if(fast==slow){ //这两个节点相遇,说明有环ListNode curr=head;while(slow!=null){if(slow==curr)return curr;slow=slow.next;curr=curr.next;}}}return null;}
}