24. 两两交换链表中的节点
独立写时候,没有考虑到 每第二次交换后,需要调整原来的第二个节点指向,也就没想到需要利用虚拟头指针。
错误代码:
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode fakeHead = new ListNode(-1,head);
ListNode cur = head, curnext = head.next;
ListNode temp = curnext;
while(curnext != null && cur != null){
//交换
curnext.next = cur;
cur.next = temp.next;
cur = temp.next;
curnext = cur.next;
temp = curnext;
}
return fakeHead.next;
}
}
问题:未想清楚依照什么作为循环判断,
AC代码:
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyhead= new ListNode(-1,head);
ListNode cur = dummyhead;
ListNode first,second;
ListNode temp;
while(cur.next != null && cur.next.next != null){
temp = cur.next.next.next;
first = cur.next;
second = cur.next.next;
cur.next = first.next;
second.next = first;
first.next = temp;
cur = first;
}
return dummyhead.next;
}
}
交换需要保存四个位置才能保证位置交换的正确性。
19.删除链表的倒数第N个节点
首次做题想到的思路为:先遍历一遍找到链表的size,然后根据size与n 可以定位到欲删除节点的前一个节点,此时有部分用例不过,发现是因为删除节点为头节点,此时与常规情况不一致,遂想到利用dummyhead;成功AC:
dummyhead解法:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode cur = head;
ListNode dummyhead = new ListNode(-1,head);
int size = 1;
while (cur.next != null) {
size++;
cur = cur.next;
}
cur = dummyhead;
for(int i=0;i<size-n;i++){
cur = cur.next;
}
//此时cur为删除节点前一个;
cur.next = cur.next.next;
return dummyhead.next;
}
}
小结:删除链表元素 首先要想到虚拟头节点用于处理链表头
双指针解法:
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummynode = new ListNode(-1,head);
ListNode fast = dummynode,slow = dummynode;
for(int i=0; i<n; i++){
fast = fast.next;
}
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
//此时slow为删除节点的前一个
slow.next = slow.next.next;
return dummynode.next;
}
}
这里fast移动n步,因为while的判断 fast会停在链表尾节点,此时slow为尾结点的往前数n个对应节点,即为待删除节点的前一个。 录中移动了n+1,因为fast最终会在尾节点的下一个(null)代码随想录 (programmercarl.com)
面试题 02.07. 链表相交
面试题 02.07. 链表相交 - 力扣(LeetCode)
O(n+m):
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;
}
curA = headA;
curB = headB;
if(lenA < lenB){
curA = headB;
curB = headA;
int temp = lenA;
lenA = lenB;
lenB = temp;
}
//此时curA为更长的那个链表头
for(int i=0;i<lenA-lenB;i++){
curA = curA.next;
}
while(curA != null){
if(curA == curB){
System.out.println("Intersected at \'"+curA.val+"\'");
return curA;
}
curA = curA.next;
curB = curB.next;
}
System.out.println("Intersected at \'"+"0"+"\'");
return null;
}
}
也可选择不输出,不输出同样ac,且耗时为1ms
O(nm):
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
while(curA != null){
curB = headB;
while(curB != null){
if(curA == curB){
System.out.println("Intersected at \'"+curA.val+"\'");
return curA;
}
curB = curB.next;
}
curA = curA.next;
}
System.out.println("Intersected at \'0\'");
return null;
}
}
142.环形链表II
依旧是双指针的思路,快慢指针。
对于寻找环的入口,数学推导及证明见代码随想录 (programmercarl.com)
总结就是 快慢指针,若相遇则一定有环;从头节点、相遇节点分别出发 所相遇的节点即为环入口
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head,slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(slow == fast){//相遇 说明一定有环
ListNode findEntrance = head;
while(findEntrance != slow){
findEntrance = findEntrance.next;
slow = slow.next;
}
return slow;
}
}
return null;
}
}