训练营第四天了, 也进入周末了, 还是得趁周日把之前的重新写几遍,不然就忘了; 关于链表的话话题更可以帮助理解, 重点无非就是理解指针谁指向谁, cur放在哪里,加油吧南部武士
两两交换链表中的节点
思路, 和之前的大同小异,只不过要考虑指针的方向,和建立多个临时节点, 首先还是要虚拟头节点, 然后cur节点指向它, 进入while循环, 这里使用短路和&&要重视, 首先用temp保存节点一和节点三, 然后cur指向第二个节点, 第二个指向第一个, 第一个指向第三个, 执行完将cur指针后移两位就行了
(细节: 记得把dummy.next = head, 不然就啥都没执行了)
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
dummy.next = head;
while(cur.next != null && cur.next.next != null){
ListNode temp = cur.next;
ListNode temp1 = cur.next.next.next;
cur.next = cur.next.next; //让头节点指向节点二
cur.next.next = temp; //让节点二指向节点一
temp.next = temp1; //让节点一指向节点三
cur = cur.next.next; //向前移动两个
}
return dummy.next;
}
}
补充:
区别&&只要第一个条件不满足,后面条件就不再判断。
&要对所有的条件都进行判断。
区别是||只要满足第一个条件,后面的条件就不再判断。
|要对所有的条件进行判断
==================================================================================================================================================================================
删除链表倒数第n个节点
思路: 这里有多种思路, 包括韩顺平讲的先获取长度, 再length - index + 1; 也可以用栈; 也可以用双指针, 这里用双指针分析一下: 一个快指针,一个慢指针, 快指针去前面先走n+1步,然后慢指针开始走,直到快指到null, 这样可以保证slow停在待删除节点的前面
细节:
1. 有两个循环, 第一个循环条件是 n-- > 0, 也就是走n步,循环结束后再写一遍fast = fast.next; (也可以直接写n-- >= 0)
2. 第二个循环就简单判断 (fast != null), 之后return dummy.next;
(记得是dummy.next = head,然后指针是直接到dummy的)
(移动n步, 就n-- > 0, 移动n+1步, 就n-- >= 0)
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
while(n-- >= 0){
fast = fast.next;
}
//fast = fast.next; //再多走一步, 让slow停在待删除节点前面一个
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
==============================================================================================================================================================================
链表相交
这题有两个解法
先遍历长度再, 让他们到同一个节点, 之后遍历判断是否相同
思路:
- 定义int lenA, lenB, 和节点curA, curB
- 利用求出A链表长度, B链表长度
- 让curA始终是长的那一个, 所以判断lenA < lenB, 否则调换len和cur(要temp)
- 求出AB长度差, 然后让A先走gap, 到达同一起点
- 开始遍历判断if curA == curB, return curA, 否则AB后移, 如果遍历完了还没return curA说明AB不相等, 直接return null.
注意细节: 遍历完AB求完长度之后, 需要重新定义到头节点初始化, 否则会空指针异常
记得gap-- > 0 就是移动gap步; 记得加ListNode
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while(curA != null){
lenA++;
curA = curA.next;
}
while(curB != null){
lenB++;
curB = curB.next;
}
//求完长度之后,要重新定义cur,让他们回到开头
curA = headA;
curB = headB;
if(lenA < lenB){
//调转长度
int tempL = lenA;
lenA = lenB;
lenB = tempL;
//调转节点
ListNode tempN = curA;
curA = curB;
curB = tempN;
}
//计算gap,并让curA和curB在同一起点
int gap = lenA - lenB;
while(gap-- > 0){
curA = curA.next;
}
while(curA != null){
if(curA == curB){
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
双指针解法
如果他们相交, 可以发现, 他们走完之后互换位置到c的距离是相等的
1.先判断这两个head是否为null
2.定义两个指针, 如果其中一个为null了(指到最后一个了), 就切换到另一个节点, 如果不是就继续往后走
3.当他们两个相等时, 就直接return, 就算不相交, 也是相等的,会return null
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null)
return null;
ListNode A = headA;
ListNode B = headB;
while(A != B){
A = A == null? headB : A.next;
B = B == null? headA : B.next;
}
return A;
}
}
================================================================================================================================================================================
接下来是链表的最后一题
环形链表II
判断链表是否有环: 利用双指针判断, 如果快慢指针相遇了, 说明有个环
快指针一次移动两个节点
慢指针一次移动一个节点
找到环的入口:
slow = x + y
fast = x +y + n(y+z)
得出x = z, 也就是说他们总会在入口处相遇,所以可以定义index1=fast, index2=head;
细节注意:
while循环是包括了中间的大块代码的, 如果while遍历完没有执行中间的, 说明没有环
1.建立快慢指针
2.利用while循环, 来让他们以不同速度移动, 直到fast 和 fast.next为null
3. 判断是否slow = fast, 如果是, 就继续执行index的循环, 当index相遇, 那个点就是环入口
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
//快指针走在前面, 所以判断不为空, next也要因为他是两步一跳
while(fast != null && fast.next != head){
fast = fast.next.next;
slow = slow.next;
//如果两个相遇了, 说明有个环
if(slow == fast){
//继续定义index, 来找到入口
ListNode index1 = fast;
ListNode index2 = head;
//因为肯定会相交, 所以循环结束直接return
while(index2 != index1){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
//如果这个大的循环没有相遇, 说明没有环
return null;
}
}