算法训练营DAY4_两两交换链表中的节点、删除链表的倒数第N个节点、链表相交、环形链表II

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

题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

24.两两交换链表中的节点https://leetcode.cn/problems/swap-nodes-in-pairs/

思考

  • 本以为只用交换节点中的值,实际上是需要交换节点本身;
  • 没有想到该如何交换,因为总会互相覆盖,还是看了视频讲解;

题解

var swapPairs = function (head) {
    // 定义一个虚拟头节点
    let virtualHead = new ListNode();
    virtualHead.next = head;

    // 定义指针
    let cur = virtualHead

    // 进行交换(奇数时,cur.next.next为null,偶数和链表为空时cur.next为null)
    while (cur.next && cur.next.next) { // 注意空指针异常!!!判断的顺序很重要
        let temp1 = cur.next;
        let temp2 = cur.next.next.next;
        // 第一步
        cur.next = cur.next.next;
        // 第三步(2、3步骤可以交换)
        temp1.next = temp2;      
        // 第二步
        cur.next.next = temp1;
 
        // 小心别被绕晕!虽然原本的cur.next.next已经变为了cur.next,但是我们需要的只是cur.next.next,与原本被换走的节点无关,只是需要将指针移动到cur.next.next位置
        cur = cur.next.next
    }
    return virtualHead.next
};

LeetCode | 24.删除链表的倒数第N个节点

题目:给你一个链表,删除链表的倒数第n个结点,并且返回链表的头结点。

19.删除链表的倒数第N个节点https://leetcode.cn/problems/swap-nodes-in-pairs/

思考

  • 自己做题时,用的是暴力破解的方法:先获得链表长度,然后遍历到length-n的节点位置,就可以删除倒数第n个节点了;
  • 题解使用了双指针法,定义了快慢两个指针,快指针先走n+1步,然后慢指针跟快指针一起走,当快指针走完整个链表时,慢指针刚好比快指针少走n+1步,即慢指针位于倒数第n个元素的前一个元素;

题解

var removeNthFromEnd = function (head, n) {
    // 虚拟头节点
    let dummyHead = new ListNode(0, head)
    // 定义快、慢指针
    let fast = dummyHead, slow = dummyHead;

    // 快指针先走n + 1步
    n++;
    while(n-- && fast){
        fast = fast.next;
    }
    // 然后,慢指针跟快指针一起走
    while(fast != null){
        fast = fast.next;
        slow = slow.next
    }

    // 删除节点
    slow.next = slow.next.next;
    
    return dummyHead.next
};

LeetCode | 160.链表相交

题目

给你两个单链表的头节点headA和headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回null。

图示两个链表在节点c1开始相交:

算法训练营DAY4_两两交换链表中的节点、删除链表的倒数第N个节点、链表相交、环形链表II_第1张图片

题目数据保证整个链式结构中不存在环。

注意,函数返回结果后,链表必须保持其原始结构 。

160.链表相交https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

思考

  • 暴力破解,但是写的代码太繁琐了;
  • 题解运用了ES6的语法,让A链表一直保持为最长的链表,更方便;

题解

var getListLen = function(head) {
    let len = 0, cur = head;
    while(cur) {
       len++;
       cur = cur.next;
    }
    return len;
}
var getIntersectionNode = function(headA, headB) {
    let curA = headA,curB = headB,
        lenA = getListLen(headA),   // 求链表A的长度
        lenB = getListLen(headB);  
    if(lenA < lenB) {       // 让curA为最长链表的头,lenA为其长度
    
        // 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
        // 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
        
        [curA, curB] = [curB, curA];
        [lenA, lenB] = [lenB, lenA];
    }
    let i = lenA - lenB;   // 求长度差
    while(i-- > 0) {       // 让curA和curB在同一起点上(末尾位置对齐)
        curA = curA.next;
    }
    while(curA && curA !== curB) {  // 遍历curA 和 curB,遇到相同则直接返回
        curA = curA.next;
        curB = curB.next;
    }
    return curA;
};

LeetCode | 142.环形链表II

题目

给定一个链表的头节点 head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。

如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos是 -1,则在该链表中没有环。注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改链表

142.环形链表IIhttps://leetcode.cn/problems/remove-nth-node-from-end-of-list/

思考

  • 第一次做这种题,没有思路,看了视频讲解后觉得很巧妙,用追及问题讲清楚了环形链表以及相遇条件;

题解

var detectCycle = function(head) {
    // 定义一快一慢两个指针
    let fast = head, slow = head;
    // 快指针比慢指针的移动速度快一
    while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
        // 如果快指针与慢指针能够相遇,则能够说明链表有环
        if(fast == slow){
            // 保存相遇点
            let index1 = fast;
            // 创建出发点
            let index2 = head;
            while(index1 != index2){
                index1 = index1.next;
                index2 = index2.next;
            }
            return index1
        }
    }
    return null
};

链表思路总结

  • 链表章节结束,其中要注意的是理解链表结构,以及多画图分析;

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