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

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

题目链接:24.两两交换链表中的节点

文档讲解:代码随想录/两两交换链表中的节点

视频讲解:视频讲解-交换链表节点

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 如果节点个数是奇数个该怎么处理?不太清楚,不管了先写再说,还是创建虚拟头结点,分别设定一个前节点和后节点记录变化之前的需要交换的节点的位置。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function(head) {
    const dummyHead = new ListNode(0,head);//定义一个虚拟头结点
    let cur = dummyHead;//当前节点从虚拟头结点开始
    while(cur.next  && cur.next.next ){
        let pre = cur.next,after = cur.next.next;//pre是前节点,after是后节点
        pre.next = after.next;//让后节点的next节点和前节点相连
        after.next = pre;//后节点的next是前节点
        cur.next = after;//虚拟头结点的next是后节点
        cur = pre;//当前节点移动到已经变换过位置的前节点(现在在后节点的next位置)
    }
    return dummyHead.next;
};

运行、提交都成功,那么看看代码随想录以及奇数个是否在最后一个节点的地方不需要调换。

看完代码随想录之后的想法 

奇数个在最后一个节点的地方确实不需要调换,那就没问题。像这种单向链表我觉得调换顺序是有一定规律的,就是得先定义变量存储后面的节点。需要注意的是while中要先对cur.next判断再对cur.next.next判断,防止出现空指针。 

总结

这道题总体思路和讲解基本一致,今天做任务之前二刷Day03的任务还是有用的,虚拟头结点确实很好用。


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

题目链接:19.删除链表的倒数第N个节点

文档讲解:代码随想录/删除链表的倒数第N个节点

视频讲解:视频讲解-删除链表的倒数第N个节点

状态:已完成(1遍)

解题过程  

看到题目的第一想法

想了一会,不知道怎么去找倒数第n个节点,我想的是把链表反转过来,找正数第n个,把他删了,再把链表反转回去。。。

 看完代码随想录之后的想法 

原来这里可以用快慢指针!!先让快指针走n步,然后快慢指针一起往后走,直到快指针的值是null,此时慢指针就指向倒数第n个节点。真妙,不服不行。

看了视频讲解之后手搓一版:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
    const dummyHead = new ListNode(0,head);
    let cur = dummyHead;
    let fast = cur,slow = cur;
    while(n--) fast = fast.next;//快指针往前走n步
    while(fast.next){//快慢指针一起往前走到快指针走到尾节点
        fast = fast.next;//往后移
        slow = slow.next;
    }
    slow.next = slow.next.next;//删除节点
    return dummyHead.next;
};

 发现和文字讲解版区别不大,完美。

总结

通过这道题认识了快慢指针在链表里的应用,解决了查找倒数第n个节点的难题。


 02.07链表相交

题目链接:02.07链表相交

文档讲解:代码随想录/链表相交

视频讲解:无

状态:已完成(1遍)

解题过程  

看到题目的第一想法

如果两个链表相交,那么它们倒数的某几个节点肯定是一样的,那用上一道题的找到倒数节点的方法去试试,将两个节点倒着对齐。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
 var getLength = function(head){
        let length = 0,cur = head;
        while(cur){
            length++;
            cur=cur.next;
        }
        return length;
    }
var getIntersectionNode = function(headA, headB) {
    let curA = headA,curB=headB;
    let lenthA = getLength(headA);
    let lenthB = getLength(headB);
    if(lenthA>lenthB){//如果A更长,调换一下
    [curA, curB] = [curB, curA];
    [lenthA, lenthB] = [lenthB, lenthA];//还是变量交换起来方便--
    }
    //现在最长的都是B了,B比A长多少,就把指针往后移多少
    let lengthDiff = lenthB - lenthA;
    while(lengthDiff--){
        curB = curB.next
    }
    while(curA !== curB){
        curA = curA.next;
        curB = curB.next;
    }
    return curA;
};

做完了我有个疑问,难道不会出现只是其中某一个节点相同,之后的节点又不同的情况吗?这样的情况我好像判断不出来。 

 看完代码随想录之后的想法 

最后一个判断里我还少了一个对curA的判断,但提交竟然成功了,想了一下,如果只相交一个节点不相交完也算相交,有交点,我可能多虑了。

总结

倒数第N个节点的思路对这道题还是很有启发的。


142.环形链表

题目链接:142.环形链表

文档讲解:代码随想录/环形链表

视频讲解:视频讲解-环形链表

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 明天起床再来看第一想法,哥们先滚回宿舍了。

起床了,这道题我的看法是难点在找环的入口,我想了一会对于这个问题没有想法。

看完代码随想录之后的想法 

跑圈的类比太精妙了,一个人跑得快一个人跑得慢,只有跑道是圈的情况下两人才会相遇。而在圈里,快指针每次走一个节点,慢指针每次走一个节点,那么单位时间内每次快指针就比慢指针多走一个节点,一定会相遇,不会跳过。

只要找到了快慢指针的相遇节点,此时慢指针走了入环前的x+入环后的y,快指针走了入环前的x+入环后的y+n(z+y),而又因为设置的快指针速度是慢指针两倍,所以得出等式:

2(x+y) = x+y+n(y+z)

解出:

x = (n-1)(y+z)+z

等式左边是入环前的路程,等式右边是数个圈加上相遇点到入环处的路程,理解一下也就是说,如果有两个指针,A从起点出发,B从相遇处出发,以相同的速度往前走,此时A指针走过了x,到达了入环处,B指针走过了数圈加上了相遇点到入环处的路程,两者在入环处相遇,那么此时相遇的点就是入环处的位置。

看完视频手搓一版:

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function (head) {
    if(!head || !head.next) return null;//节点数不大于1的话就没环
    let fast = head.next.next, slow = head.next;
        while (fast && fast.next&&fast !== slow) {//跑到相遇为止,防止对空指针进行操作
            fast = fast.next.next;
            slow = slow.next;
        }
        let naruto = head, sasuke = fast;
        while (naruto !== sasuke) {
            naruto = naruto.next;
            sasuke = sasuke.next;
        }
        return naruto;
};

提交发现有错 ,例子是

想了一会,问题出在,如果第一个while循环是因为快节点空值跳出循环,没有if来进行判断。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function (head) {
    if(!head || !head.next) return null;//节点数不大于1的话就没环
    let fast = head.next.next, slow = head.next;
        while (fast && fast.next&&fast !== slow) {//跑到相遇为止,防止对空指针进行操作
            fast = fast.next.next;
            slow = slow.next;
        }
        if(!fast||!fast.next) return null;//以防是快指针空指针
        let naruto = head, sasuke = fast;
        while (naruto !== sasuke) {
            naruto = naruto.next;
            sasuke = sasuke.next;
        }
        return naruto;
};

总结

这道题和数形结合甚至解方程都联系起来了,令本小前端深深体会到了算法的魅力,继续加油。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值