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

一、24 两两交换链表中的节点

  1. 题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/

  1. 思路:加入虚拟头结点,然后cur指针每次移动两格,将前后两个节点交换。很简单。时间复杂度O(n)

  1. 代码:

var swapPairs = function(head) {
    if (!head) {
        return head;
    }
    var preHead = new ListNode(-1, head);
    var cur = preHead;
    while (cur.next && cur.next.next) {
        var left = cur.next;
        var right = cur.next.next;
        var temp = right.next;
        cur.next = right;
        right.next = left;
        left.next = temp;
        cur = cur.next.next;
    }
    return preHead.next;
};

二、19 删除链表的倒数第N个结点

  1. 题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

  1. 思路:一开始想到的是先算一下一共有几个节点,然后再重新从头开始遍历,这是两趟扫描;第二种方法想到的是借助一个数组,将所有的遍历节点存进去,然后取出对应的哪一个节点数据;卡哥的算法思路是快慢指针法,让fast先走n+1步,然后再让slow和fast一起走,这样fast走到末尾时slow就在倒数第n个节点上了。

  1. 思路1代码:

var removeNthFromEnd = function(head, n) {
    var preHead = new ListNode(-1, head);
    var len = 0;
    var cur = preHead;
    while (cur.next) {
        len += 1;
        cur = cur.next;
    }
    var result = len - n;
    var pointer = preHead;
    for (result; result>0; result--) {
        pointer = pointer.next;
    }
    if (pointer.next) {
        pointer.next = pointer.next.next;
    }
    else {
        pointer.next = null;
    }
    return preHead.next;
};
  1. 思路2代码:

var removeNthFromEnd = function(head, n) {
    var preHead = new ListNode(-1, head);
    var stack = [];
    var cur = preHead;
    while (cur) {
        stack.push(cur);
        cur = cur.next;
    }
    var node = stack[stack.length - n - 1];
    if (node.next) {
        node.next = node.next.next;
    }
    else {
        node.next = null;
    }
    return preHead.next;
};
  1. 卡哥思路代码:

var removeNthFromEnd = function(head, n) {
    var preHead = new ListNode(-1, head);
    var fast = preHead;
    var slow = preHead;
    // 此处循环为n+1,是为了方便slow停在删除节点的前一个节点上
    for (let i = n+1; i > 0; i--) {
        fast = fast.next;
    }
    while (fast) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next ? slow.next.next : null;
    return preHead.next;
};

三、160 链表相交

  1. 题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/

  1. 思路:首先想到的是借助栈来做,将两个链表分别压入两个栈中,然后出栈,依次比较,直至不相同的地方,时间复杂度O(3m/2+3n/2),空间复杂度O(m+n),这种就不写了;其次还想到一种递归的方式,首先需要判断一个链表是否是另一个链表的子链表,如果是的话返回这一个链表,而如果不是的话递归这个链表的next和另外那个链表,不过可见时间复杂度会较高。但是题目要求时间复杂度O(m+n)、空间复杂度O(1),卡哥的方式是求出两个链表的长度,以及其差值,然后让curA移动到两个链表的尾部对齐的部位,再依次前进,直至相等。

  1. 递归代码:(未解决)

var getIntersectionNode = function(headA, headB) {
    if (isSonLink(headA, headB)) {
        return headA;
    }
    else {
        getIntersectionNode(headA.next, headB);
    }
};

// 求A是否为B的子链表
var isSonLink = function(A, B) {
    var cur = B;
    // 空指针是所有指针的子链表
    if (!A) {
        return true;
    }
    // B遍历到末尾,判断是否有一个指针会等于A
    while (cur) {
        if (cur === A) {
            return true;
        }
        cur = cur.next;
    }
    return false;
}
  1. 卡哥思路:

var getIntersectionNode = function(headA, headB) {
    var curA = headA;
    var curB = headB;
    var lenA = 0;
    var lenB = 0;
    while (curA) {
        lenA += 1;
        curA = curA.next;
    }
    while (curB) {
        lenB += 1;
        curB = curB.next;
    }
    curA = headA;
    curB = headB;
    if (lenA >= lenB) {
        for (let i=lenA-lenB; i>0; i--) {
            curA = curA.next;
        }
    }
    else {
        for (let i=lenB-lenA; i>0; i--) {
            curB = curB.next;
        }  
    }
    while (curA && curB) {
        if (curA == curB) {
            return curA;
        }
        curA = curA.next;
        curB = curB.next;
    }
    return null;
};
  1. 代码随想录:(还是有很多可以精简的地方)

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;
};

四、142 环形链表II

  1. 题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/

  1. 思路:这道题真是几遍都记不住,直接看提示吧。。。

  1. 文章链接:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html

  1. 代码:

var detectCycle = function(head) {
    // 快指针每次走两步,慢指针每次走一步
    var slow = head, fast = head;
    while (fast && fast.next) {
        fast = fast.next.next;
        slow = slow.next;
        // 快慢指针相遇
        if (fast == slow) {
            // 从相遇点和头部分别走,他俩相遇了就一定是环的入口
            var index1 = fast;
            var index2 = head;
            while (index1 != index2) {
                index1 = index1.next;
                index2 = index2.next;
            }
            return index1;
        }
    }
    return null;
};

今日学习时间:2h左右

总结:今天前两道题做的还是比较顺利的,但后两道题相对来讲比较难,不过我认为这两道题的泛用度也没有那么高,都是针对链表的特殊处理,因此没有太过深入研究,特别是142,除了记住我感觉别无他法。。。链表相交我用了一种递归的方式,但还没有看出问题在哪。下次再看的时候再来记一下142题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值