- 两两交换链表中的节点
用虚拟头结点,这样会方便很多。
本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
本题关键:
举个栗子
cur
, 进行交换, 再让cur
指向接下来需要交换的两个节点前的一个节点.temp1
和temp2
保存1,3节点 ListNode temp1 = cur.next;
ListNode temp2 = cur.next.next.next;
图中cur
指向2, 会丢掉1, 所以要temp1
保存1
cur.next = temp1.next;
cur.next.next = temp1;
temp1.next = temp2;
因为要交换3和4, 要让cur
到如图的位置也就是之前temp1
的位置
cur.next != null
cur.next.next != null
cur.next != null
再写 cur.next.next != null
, 不然如果cur.next
是null的话, 先判断cur.next.next
就会出现空指针异常了最终代码如下
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode cur = dummyNode;
while (cur.next != null && cur.next.next != null) {
ListNode temp1 = cur.next;
ListNode temp2 = cur.next.next.next;
cur.next = temp1.next;
cur.next.next = temp1;
temp1.next = temp2;
cur = temp1;
}
return dummyNode.next;
}
}
第一印象:
我觉得倒腾链表节点的题不难,这道题我自己做也做出来了,感觉是要三个指针一起倒腾。
看完题解的思路:
我发现题解是上面那种思路,但我自己做的时候却是
思路是一致的,但是对节点的选取是不一样的。pre 先指向 temp,cur 再指向 temp.next (也就是3 号节点),最后 temp 再指向 cur。这样就不会弄丢 3 号节点,和上面的的区别也只是顺序发生了一个变化。
实现中的困难:
这道题也没啥困难,判断循环终止条件需要注意一下,我这样写的话需要在移动temp节点之前判断一下 cur 是不是null。 temp = cur.next;
附上代码,成功了就完事了:
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null) {return null;}
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode pre = dummyNode;
ListNode cur = head;
ListNode temp = cur.next;
while (temp != null) {
pre.next = temp;
cur.next = temp.next;
temp.next = cur;
pre = cur;
cur = pre.next;
if (cur == null) {
break;
}
temp = cur.next;
}
return dummyNode.next;
}
}
双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html
本题关键:
思路:
这道题比较简单, 仍然要虚拟头结点
代码如下:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode fast = dummyNode;
ListNode slow = dummyNode;
n++;
while (n-- != 0 && fast != null) {
fast = fast.next;
}
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
`
slow.next = slow.next.next;
return dummyNode.next;
}
}
看完题解的思路:
我的方法是走一遍链表记录长度,从删除倒数变成删除正数,比较容易想,但比题解的麻烦,但我ac了,附上代码:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode pre = new ListNode();
ListNode cur = dummyNode;
int length = 0;
while (cur.next != null) {
cur = cur.next;
length++;
}
if (n > length) {
return null;
}
//有五个,倒数第二个就是正数第四个,就是5-2+1
int size = length - n + 1;
cur = dummyNode;
pre.next = cur;
while (size-- > 0) {
cur = cur.next;
pre = pre.next;
}
pre.next = cur.next;
return dummyNode.next;
}
}
本题关键:
思路:
怎么找到第一个相交的节点?
要让链表尾对齐, 以短的那条长度n为标准, 只看长链表的后n个节点.
这里只需要注意一件事情: 相交的链表直接比较指针相等, 只要有一处相等后续就相等, 而不是考虑节点的值.
也就是说对于指针curA 和 curB 可以有语句 if (curA == curB) {…} 去判断节点是否相等。
第一次做的时候忘记附上代码了,题目实现过程不难,我不会的地方在于我觉得ListNode对象不能直接判断 是否相等 。
附上代码:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = new ListNode();
ListNode curB = new ListNode();
int lengthA = 0;
int lengthB = 0;
curA = headA;
curB = headB;
while (curA != null) {
lengthA++;
curA = curA.next;
}
while (curB != null) {
lengthB++;
curB = curB.next;
}
int sub = Math.abs(lengthA - lengthB);
curA = headA;
curB = headB;
if (lengthA > lengthB) {
while (sub-- != 0) {
curA = curA.next;
}
} else {
while (sub-- != 0) {
curB = curB.next;
}
}
while (curA != null) {
if (curA == curB) {
return curA;
} else {
curA = curA.next;
curB = curB.next;
}
}
return null;
}
}
142.环形链表II
算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
本题关键
思路
index1
从head
出发, index2
从相遇点出发, 每次都走一个单位, 就会相遇在环的入口. 这个公式推导的时候注意slow
在环内走不满一圈的时候就会和fast
相遇, 不用考虑slow
走了几圈之后再相遇, 因为fast
的速度是slow
的2倍, 如果slow
走了1圈, fast
就走了2圈了, 他们一定有一点相遇过. 我觉得想象成,我和你去操场跑圈,你跑一圈的时间我能跑两圈,那我一定套你也一圈 追上过你一次啊,换成生活里的感觉就好理解了。代码如下 :
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = new ListNode();
ListNode slow = new ListNode();
fast = head;
slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast) {
ListNode index1 = new ListNode();
ListNode index2 = new ListNode();
index1 = head;
index2 = fast;
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
第一印象:
我就记得当初这道题很折磨,需要找数学规律,现在再看也是不会,直接看视频讲解了。
看完题解的思路:
茅塞顿开了又,懒得实现一遍了,思路确实值得学习啊。