【算法】代码随想录训练营Day4打卡,24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

【算法】代码随想录训练营Day4打卡,24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

链表

代码随想录算法训练营Day4任务。

  1. leetcode24. 两两交换链表中的节点
  2. leetcode707. 设计链表
  3. leetcode206. 反转链表

两两交换链表中的节点

力扣链接:https://leetcode.cn/problems/swap-nodes-in-pairs/submissions/
这一道题的意思就是交换两个相邻的节点,并且以两个节点为一组;
这样我们就按照题例来思考,这道题要求我们返回一个链表,那么我们最好的做法就是创建一条新的链表,所以我们首先要穿件一个新的头部节点 newHead;
其次我们需要两个指针,一个cur指向我们每一次要操作的节点组(从头节点开始两个节点为一组)的第一个节点
这时候我们就要思考了,只有每一组有两个节点我们才会进行反转操作,如果只有一个节点直接将这个节点拼到新链表之后就可以
那么接下来我们就通过两个指针进行反转操作,实际细节如下图
在这里插入图片描述

C语言版本

虚拟头节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    struct ListNode newHead = {0,NULL};
    struct ListNode* cur = head;
    struct ListNode* pre = &newHead;
    while(cur){
        if(cur->next){ //说明有一对要交换的
            pre->next = cur->next;
            struct ListNode* node = pre->next;
            pre = cur;
            cur=cur->next->next;
            node->next = pre;
            pre->next = NULL;
        }else{
            pre->next = cur;
            cur= cur->next;
        }
    }
    return newHead.next;
}

JS版本

方法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) {
    let newHead = new ListNode();
    let cur = head;
    let pre = newHead;
    while(cur){
        if(cur.next){ //说明有一对要交换的
            pre.next = cur.next;
            let node = pre.next
            pre = cur;
            cur=cur.next.next;
            node.next = pre;
            pre.next = null;
        }else{
            pre.next = cur;
            cur= cur.next;
        }
    }
    return newHead.next;
};

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

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
这道题的要求是删除链表的倒数第n个节点,会传入一个数值n
这道题的话会有一点反向思路的感觉,其实实际上我们只需要两个指针,一个快指针,一个慢指针,快指针先走n步,之后快指针再和慢指针同步走,当快指针走到链表尽头时,慢指针所指向的节点就是倒数第n个节点
我们先画一个图理解一下
在这里插入图片描述
这里我们找到了倒数第n个节点了,但是注意题目,我们要的是删除倒数第n个节点
既然是删除节点,那么我们要找到的是这个节点的前一个节点才能删除,
所以我们只需要小小的修改一下就行了,我们要让slot少走1步,那么我们就让fast多走一步就可以了

如图
在这里插入图片描述
这时候我们只需要把slot.next 指向 slot.next.next就可以了

C语言版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeNthFromEnd(struct ListNode* head, int n){

    struct ListNode* fast = head;
    struct ListNode* slot = head;
    while(n>0){
        fast = fast->next;
        n--;
    }
    if(fast == NULL) return head->next;
    fast = fast->next;
    while(fast){
        fast = fast->next;
        slot = slot->next;
    }
   
        slot->next = slot->next->next;

 
    return head;
}

JS版本

/**
 * 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) {
    let fast = head;
    let slot = head;
    while(n>0){
        fast = fast.next;
        n--
    }
    if(fast == null) return head.next;//如果这时候fast已经走到头了 就直接删除头结点就好了
    fast = fast.next; // 多走一步
    while(fast){
        fast = fast.next;
        slot = slot.next;
    }
   
        slot.next = slot.next.next;

 
    return head;
};

LeetCode 面试题 02.07. 链表相交

链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/

如图
在这里插入图片描述
所以我们首先要做的是求出两个链表的长度,然后再进行求差异
然后把长度长的链表的指针移动差异值个位置,然后两个指针对比每个节点的地址是否一致

JS解法

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

 let getLength = (head)=>{
     let len = 0;
     while(head){
         head=head.next;
         len++;
     }
     return len
 }

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    let lenA = getLength(headA);
    let lenB = getLength(headB);
    let sub;
    sub = lenA-lenB;
    if(sub>0){
        while(sub--){
            headA = headA.next;
        }
    }
    else{
        let loop = Math.abs(sub) // 注意 这时候sub是<0的 最好取一下绝对值
         while(loop--){
            headB = headB.next;
        }
    }
    while(headA !== headB){
        headA = headA.next;
        headB = headB.next;
    }
    return headA;
};

142.环形链表II

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

这道题就是判断链表是否有环,并返回入口的节点,
其实判断链表是否有环很简单,我们做一个快慢指针,快指针一次走两步 慢指针一次走一步,不停的循环下去,若快指针走到null,则证明链表无环,若是当快指针和慢指针相遇,那么就证明链表有环
这个时候 我们的 慢指针走了k步 而快指针走了 2k步
而这个时候我们拆解 k 走了什么 k = 头结点到入口节点 m + 入口节点到相遇节点 n;
而快指针其实也走了这一段 k+m 但是快指针是走了2k的 所以快指针走了两个 k+m
所以 2*(n+m) = n+m + (环内走的距离)
所以环内走的这一段距离也是n+m;
而 n是入口节点到相遇节点的距离
n+m 又是环内的距离
那么剩下的 相遇节点到入口节点的距离 就是 m
所以我们将慢指针再从头开始走 快指针从相遇节点开始走 一次走一步,当 两个指针相遇的时候,他们都走了m步; 就是入口节点的位置
在这里插入图片描述

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


/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
      // 快慢指针初始化指向 head
  let slow = head;
  let fast = head;
  // 快指针走到末尾时停止
  while (fast && fast.next) {
    // 慢指针走一步,快指针走两步
    slow = slow.next;
    fast = fast.next.next;
    // 快慢指针相遇,说明含有环
    if (slow == fast) {
      // 任一一节点指向头节点
      fast = head;
      // 同步向前进
      while (fast != slow) {
        fast = fast.next;
        slow = slow.next;
      }
      // 返回入口节点
      return fast;
    }
  }
  // 不包含环
  return null;   
};

今日心得

今天做题+写文章一共4小时30分钟,环形链表2这道题是在环形链表上的一个提升,但难度会比光求环形链表要难上不少,你得想得通为什么第二次他们相遇就是入口节点这个问题。也是第一次做这一道题,在这里卡了不少时间,但是做算法,画图真的是最有助于理解的工具,让我们可以快速的梳理思路,所以尽量在做题的时候画图。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值