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

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

/**
 * 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) {
    
    if(head===null||head.next===null){ //用于[],[1]的情况
        return head;
    }
    let pre=head;    //图1,设置虚拟头结点
    let cur=head.next;
    let nhead=new ListNode(0,head)

    nhead.next=cur   //图2,不改变节点内的值的前提下,交换节点2和节点1,并且交换二者的指向
    pre.next=cur.next
    cur.next=pre
    
    head=cur//记录头结点,所以在while循环外先进行第一次交换

    while(cur!==null){
        if(pre.next===null||pre.next.next===null)  //判断结束,图1(2、3)和图4两种状态,并解决了undefined的问题
          break   //退出
        else{   //到图3的状态,因为之前先判断了一次,所以先变换位置
            nhead=pre
            pre=pre.next
            cur=pre.next
          }
        nhead.next=cur  //和上面第一轮一样,此次把前面的【2,1】节点接住
        pre.next=cur.next
        cur.next=pre
    }
    return head
};

/*
//随想录的简洁版,思路差不多,他解决了我的返回head的问题,他在while内部定义pre,他的temp相当于我的uhead
var swapPairs = function (head) {
  let ret = new ListNode(0, head), temp = ret;
  while (temp.next && temp.next.next) {
    let cur = temp.next.next, pre = temp.next;
    pre.next = cur.next;
    cur.next = pre;
    temp.next = cur;
    temp = pre;
  }
  return ret.next;
};
*/

第一想法

不能变节点的val,就只能变节点的next了

思路

结合此图和注释
如注释


困难

  • 无返回值

在while外做一轮,记录head

  • 最后只有[4,3]——虚拟头节点的作用

图三,nhead.next=cur,把前面一轮的成果接住了

  • 先做

此类问题终于懂了~,如图一,4后面是有一个null的,所以可以用于head.next===null判断之类的,但比如我把pre赋值到了最后一个null节点,null节点就没有val也没有next节点了,所以null或undefined

if(pre.next=== null || pre.next.next = ==null) 这个判断,节点4后面是null或者4的后面的后面是null


收获

  • 对链表的理解

链表是一个一个节点构成的

谈谈理解,例如
let cur=head.next; //next指向的也是一个节点,也可以理解为next就是一个节点,不过是我家后面的家,cur指向head的节点,cur是这个val=2节点的别名,这个节点可以有很多名字,但我可以调用他的val和next,但并不是新造一个节点
let nhead=new ListNode(0,head) //新造一个节点,val是0,next是head
nhead.next=cur //nhead这个家带地皮一整个搬到cur前面去了,节点还是那个节点,那个节点还是叫nhead,不过搬家了
nhead=pre,pre代表的节点又有了一个名字nhead,两者就是一个节点




19.删除链表的倒数第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) {
  //快慢节点,就可以之遍历一次
    let f=head;
    let m=new ListNode(-1,head)

    for(let i=1;i<=n;i++) //2次
        f=f.next
    while(f){ 
        f=f.next;
        m=m.next
   }
 
    if(m.val===-1)
        return m.next.next
 
    m.next=m.next.next;
    return head
};


第一想法

快慢指针

思路

如图
在这里插入图片描述


困难

  • 开始把m.val设置为0,结果有正常val的也是0

设为-1

  • while和for的边界

画一遍图理解思路和加一个虚拟节点就很容易解决

  • head =[1],n =1的例子

因为只是m.next=m.next.next;,没有吧原先的m.next=null消除.

if(m.val===-1)
return m.next.next//我的(m)是可以动的,没有一个可以直接
或者学代码随想录专门设置一个数来记录虚拟头结点


收获

  • 我的(m)是可以动的,以后专门设置一个数来记录虚拟头结点





面试题 02.07. 链表相交

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),
        lenB = getListLen(headB);
    if(lenA < lenB) {
        // 下面交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
        // 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
        [curA, curB] = [curB, curA];
        [lenA, lenB] = [lenB, lenA];
    }
    let i = lenA - lenB;
    while(i-- > 0) {
        curA = curA.next;
    }
    while(curA && curA !== curB) {
        curA = curA.next;
        curB = curB.next;
    }
    return curA;
};


//双指针
var getIntersectionNode = function(headA, headB) {
    let A = headA
    let B = headB
    while(A !== B){
        A = A !== null ? A.next : headB
        B = B !== null ? B.next : headA
    }
    return A
};



第一想法

看不懂题,直接看代码

思想

普通:看代码

双指针:
在这里插入图片描述
最后一定重合

收获

  • 交换

let a = 123,
b = 456;
[a,b] = [b,a];
console.log(a, b);

[curA, curB] = [curB, curA];
[lenA, lenB] = [lenB, lenA];






141. 环形链表

// 两种循环实现方式
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
// 先判断是否是环形链表
var detectCycle = function(head) {
    if(!head || !head.next) return null;
    let slow =head.next, fast = head.next.next;
    while(fast && fast.next && fast!== slow) {
        slow = slow.next;
        fast = fast.next.next; 
    }
    if(!fast || !fast.next ) return null;
    slow = head;
    while (fast !== slow) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
};

var detectCycle = function(head) {
    if(!head || !head.next) return null;
    let slow =head.next, fast = head.next.next;
    while(fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if(fast == slow) {
            slow = head;
            while (fast !== slow) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
    }
    return null;
};


第一想法

for+while,暴力

困难

  • 1.理解为什么一定会相遇

相对,fast相对slow走一步

  • x怎么找到

x = (n - 1) (y + z) + z,具体看代码随想录文档


收获

Floyd判圈算法(龟兔赛跑算法)


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值