代码随想录算法营DAY4 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 02.07. 链表相交 142.环形链表II

代码随想录算法营DAY4 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 02.07. 链表相交 142.环形链表II

  • 24. 两两交换链表中的节点
  • 19.删除链表的倒数第N个节点
  • 160.链表相交(面试题)
  • 142. 环形链表 II
  • 关于虚拟头结点
  • 感想总结

24. 两两交换链表中的节点

题目链接: 24. 两两交换链表中的节点
思路:
如图,其实不是这个顺序也可以,但要注意指针和元素之间的关系。

代码随想录算法营DAY4 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 02.07. 链表相交 142.环形链表II_第1张图片

代码:

var swapPairs = function (head) {
    let ret=new ListNode(0,head),tmp=ret;//这里定义ret是为了方便返回头结点。
    while(tmp.next&&tmp.next.next){
        let pre=tmp.next,cur=tmp.next.next;
        tmp.next=cur;
        pre.next=cur.next;
        cur.next=pre;
        tmp=pre;//注意这里,pre和cur已经交换了节点,所以要更新到pre
    }
    return ret.next;
};

复杂度分析:
时间复杂度:O(n)

19.删除链表的倒数第N个节点

题目链接: 19.删除链表的倒数第N个节点
思路:
1.两遍扫描 先看看有多少元素,然后算出sum-n得到往前遍历的次数,再删除。
2.双指针法 只需要一遍扫描

  • 定义虚拟头结点方便删除头结点的逻辑(这里不用虚头也行,但需要分类讨论,麻烦)
    代码随想录算法营DAY4 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 02.07. 链表相交 142.环形链表II_第2张图片
  • 先让fast移动n+1步(为了让slow移动到删除节点的前一个节点) 然后fast和slow一起移动,直到fast=null 执行删除操作

代码:

var removeNthFromEnd = function(head, n) {
    let dummyhead=new ListNode(0,head);
    let fast=slow=dummyhead;
    let count=n+1;
    while(count--){
        fast=fast.next;
    }
    while(fast){
        fast=fast.next;
        slow=slow.next;
    }
    slow.next=slow.next.next;
    return dummyhead.next;
};

复杂度分析:
时间复杂度:O(n)

160.链表相交(面试题)

题目链接: 160.链表相交
思路:
1.求两个链表长度(可以定义一个求长度函数)
2.算出长度差值move,并设置curA的指针移动move个单位(末尾元素对齐)
3.curA curB一起移动并且比较值的大小,若相等,则返回节点,遍历完了curA等于null说明没找到也可以直接返回。

代码:

var getlength= function(head){
    let cur=head;
    let length=0;
    while(cur){
        cur=cur.next;
        length++;
    }
    return length;
}
var getIntersectionNode = function(headA, headB) {
    let curA=headA,curB=headB,
    lengthA=getlength(headA),
    lengthB=getlength(headB);
    if(lengthA<lengthB){
        // 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
        // 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
        [curA, curB] = [curB, curA];
        [lengthA, lengthB] = [lengthB, lengthA];
    }
    let move=lengthA-lengthB;
    while(move--){
        curA=curA.next;
    }
    while(curA&&curA!=curB){
        // if(curA===curB) return curA;
        curA=curA.next;
        curB=curB.next;
    }
    return curA;
};

问题:
语法问题:为什么代码里面有的函数有;,有的函数结束后不用写;?
还有js的分号问题,中间这个变量交换还不太懂为什么:
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]

复杂度分析:
时间复杂度:O(n + m)
空间复杂度:O(1)

142. 环形链表 II

题目链接: 142. 环形链表 II
思路:
1.判断有没有环
双指针法,让F每次移动2,S每次移动1,相当于产生一个F追S的相对运动(每次相对运动1),如果有环一定会相遇。
2.判断环的入口在哪
代码随想录算法营DAY4 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 02.07. 链表相交 142.环形链表II_第3张图片
代码:

var detectCycle = function(head) {
    if(!head || !head.next) return null;//一个或者0个元素没有环
    let slow =head.next, fast = head.next.next;
    while(fast && fast.next && fast!== slow) {//因为fast每次移动两个所以需要判断fast和fast.next都不为空,不然fast.next.next就没意义了
        slow = slow.next;
        fast = fast.next.next; 
    }
    if(!fast || !fast.next ) return null;
    slow = head;
    while (fast !== slow) {//js的不等于号是这样写的吗
        slow = slow.next;
        fast = fast.next;
    }
    return fast;
};

关于虚拟头结点

涉及到删除头结点,或者是头结点位置变化的操作的时候,设置虚拟头结点可以比较方便的统一处理,而不用去分类讨论(lc24 19)

感想总结

1.两两交换链表中的节点,用虚拟头结点可以方便返回头结点(因为后来头结点换位置了),其他的注意记录三个节点tmp,pre,cur,还有指针改变的逻辑和顺序。
2.删除节点,可以用双指针,F先走n+1,然后再一起走,最后F等于null时候删除。
3.循环链表,推导有点难,但是第二遍基本上背下来思路了。先判断有没有环再判断入口点。

你可能感兴趣的:(链表,算法,数据结构)