24两两交换链表中的节点
解题思路:
- 交换前两个节点,并且第二节点指向下一个节点位置。由此,先记录不变节点dunmmyHead,它指向头节点。再定义第一节点,第二节点,和存储点三节点的临时节点,和移动头节点。
- 第二节点指向第一节点,第一节点指向临时节点。然后再让移动头节点指向第二节点即可。完成后,最后再将移动节点向后移动两个节点即可反复操作。
- 判断条件:当移动节点的下一节点,和下下节点不为空,即可重复进行操作。
代码:
public class Solution {
public ListNode SwapPairs(ListNode head) {
if(head == null){
return head;
}
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode moveNode = dummyHead; //虚拟头节点
ListNode firstNode ; //第一节点
ListNode SecondNode; //第二节点
while(moveNode.next != null && moveNode.next.next !=null){
firstNode = moveNode.next;
SecondNode = moveNode.next.next;
ListNode temp = moveNode.next.next.next; //临时节点
moveNode.next = SecondNode;
SecondNode.next = firstNode;
firstNode.next = temp;
moveNode = moveNode.next.next;
}
return dummyHead.next;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
19.删除链表的倒数第N个节点
解题思路:
- 看到题后,第一思路,遍历整个链表计算size,然后在遍历第n-1个节点,来删除倒数第n个节点位置。
- 看到题解和之前刷题提交的方法,惭愧,又忘记了。这里使用快慢指针。快指针跑n个节点,然后快指针和慢指针一起跑节点,当快指针跑完size个节点后,满指针少跑了n个节点,即慢指针此时的位置在倒数第n个节点之前一位。
快慢指针法:
public class Solution {
public ListNode RemoveNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode fastNode = dummyHead;
ListNode slowNode = dummyHead;
for(int i =0;i<n;i++){
fastNode = fastNode.next;
}
while(fastNode.next != null){
fastNode = fastNode.next;
slowNode = slowNode.next;
}
slowNode.next = slowNode.next.next;
return dummyHead.next;
}
}
时间复杂度:O(n);
空间复杂度: O(1);
问题点:
- 注意慢指针的位置最后为n-1,此时我们只需将指针指向下两个就行。
- 注意边界判断条件。
02.07链表相交
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
解题思路:
- 假设存在交点,则其交点开始到结束节点长度相同。由此可以判断,对于不同长度A,B链,多出来的部分毫无意义。我们只需要对比相同长度开始的地方即可找出起始节点。
- 第一步,先循环,判断A,B链长度。第二步,去除长度不同的地方。第三步,开始依次对比,直到找到或者结束。
代码部分:
public class Solution {
public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {
ListNode dummyHead1 = new ListNode(-1);
ListNode dummyHead2 = new ListNode(-1);
ListNode temp1 = headA;
ListNode temp2 = headB;
int sizeA = 0;
int sizeB = 0;
dummyHead1.next = headA;
dummyHead2.next = headB;
ListNode first = dummyHead1;
ListNode second = dummyHead2;
while(temp1 != null){
sizeA++;
temp1 = temp1.next;
}
while(temp2 != null){
sizeB++;
temp2 = temp2.next;
}
if(sizeA > sizeB){
int n = sizeA - sizeB;
while(n-->0){
first = first.next;
}
}
else if(sizeA < sizeB){
int n = sizeB- sizeA;
while(n-->0){
second = second.next;
}
}
else{
first = dummyHead1;
second = dummyHead2;
}
while(first.next != null && second.next != null){
if(first.next == second.next){
return first.next;
}
first = first.next;
second = second.next;
}
return null;
}
}
时间复杂度:O(n+m)
空间复杂度:O(1)
142.环形链表
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
解题思路:
- 看到题目的第一想法,想要找到进入循环的点,要使用不同速度的指针去实现。然后,就没然后了,惭愧。
- 看了过去刷题的思路和代码随想录的讲解后得到了思路。使用快慢指针,快指针的速度是慢指针速度的2倍。所以在循环中,存在某一刻,慢指针与快指针在同一节点。由此,我们可以得到,慢指针走了从头到循环点再到交点的距离,快指针也走了这段距离,还多走了n遍循环。然后带入公式进行计算,会发现,起点到循环点的距离,就等于n遍循环加上交点到循环点的距离。
快慢指针解法:
public class Solution {
public ListNode DetectCycle(ListNode head) {
ListNode fastNode = head;
ListNode slowNode = head;
while(fastNode != null && fastNode.next != null){
fastNode = fastNode.next.next;
slowNode = slowNode.next;
if(fastNode == slowNode){
ListNode index1 = head;
ListNode index2 = fastNode;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
难点分析:
- 慢指针进入循环后,在第一次循环没有结束,就被快指针追上。
说明:
满指针进入循环时,快指针已经走了一定长度。满指针走完一个循环,快指针必定走了2个循环。所以在到达慢指针的第一个循环的时候,快慢指针在某一时刻已经相遇。而且快指针的速度相对于慢指针为1,所以必定能遇到慢指针。