代码随想录训练营第四天 第二章 链表part02

两两交换链表中的节点

题目描述:

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

我的解题思路:

首先定义一个虚拟头结点,便于统一对节点的操作。

      ListNode virtualHead = new ListNode(0);
      virtualHead.next = head;

要实现两个节点的交换,我需要创建两个节点,用来帮我实现交换。(不用纠结为什么叫slowNode, fastNode)

      ListNode slowNode, fastNode;

我们第一步创建的virtualHead是不参与中间过程的,所以还需要创建一个节点,用来在链表中移动。

      ListNode cur = virtualHead;

接下来就是两两交换节点的过程
在交换两个节点的位置之前,一定要保存第三个节点,不然他就丢失了。

      ListNode temp = cur.next.next.next;

交换两个节点的方法很简单,就是改变他的next域。

 		slowNode = cur.next;
        fastNode = cur.next.next;
        fastNode.next = slowNode;
        slowNode.next = temp;

交换完两个节点之后,我们需要修改cur的next域,以及重新赋值cur节点。

        cur.next = fastNode;
        cur = slowNode;

接下来就是循环上面的过程,那么循环的条件是什么呢?
cur指向的是待交换的节点的前一个位置。如果他的后两个节点存在,那么就需要进入循环;如果不足两个节点,那么就不喜欢交换节点,也就不需要进入循环。可知,循环条件是

	while(cur.next != null && cur.next.next!= null)

交换完之后,就返回头节点。注意头结点不是head,经过交换后,head已经是第二个节点了。头结点是virtualHead.next
所以返回语句是

	return virtualHead.next;

完整代码如下:

 public ListNode swapPairs(ListNode head) {
      ListNode virtualHead = new ListNode(0);
      virtualHead.next = head;
      ListNode slowNode,ListNode fastNode;
      ListNode cur = virtualHead;
      while(cur.next != null && cur.next.next!= null){
        ListNode temp = cur.next.next.next;
        slowNode = cur.next;
        fastNode = cur.next.next;
        fastNode.next = slowNode;
        slowNode.next = temp;
        cur.next = fastNode;
        cur = slowNode;
      }
      return virtualHead.next;
    }
删除链表的倒数第N个节点

题目描述:

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

我的解题思路:

这道题比较简单,看到倒数n个节点,就能想到可以用快慢指针的方法,两个指针之间相差n个位置。当快指针的next域为空的时候,慢指针的next域就是要删除的节点。这个知识点记住就行。
首先是常规步骤,定义一个虚拟头结点。

 ListNode virtualHead = new ListNode(0);
 virtualHead.next = head;

然后定义快慢指针

        ListNode slow = virtualHead;
        ListNode fast = virtualHead;

接着让快指针移动n步

        for(int i = 0; i < n;i++){
            fast = fast.next;
        }

然后同时移动快慢指针,让快指针的next域为空

        while(fast.next != null){
            slow = slow.next;
            fast = fast.next;
        }

然后是删除指定节点

        slow.next = slow.next.next;

完整代码如下:

    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode virtualHead = new ListNode(0);
        virtualHead.next = head;
        ListNode slow = virtualHead;
        ListNode fast = virtualHead;
        for(int i = 0; i < n;i++){
            fast = fast.next;
        }
        while(fast.next != null){
            slow = slow.next;
            fast = fast.next;
        }
        slow.next = slow.next.next;
        return virtualHead.next;
    }
链表相交

题目描述:

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

我的解题思路:

如果链表相交的话,说明,节点是一样的。那么我们就可以用==来判断两个链表的节点是否一样。
但是这两个链表的长度不一定是相同的,于是我们就要先求出这两个链表的长度。求链表的长度很简单,直接遍历就好了。

    int lenA = 0, lenB = 0;
    ListNode temp = headA;
    while (temp != null) {
        lenA++;
        temp = temp.next;
    }
    temp = headB;
    while (temp != null) {
        lenB++;
        temp = temp.next;
    }

现在我们知道了这两个链表的长度。为了对齐链表的节点,我们需要移动其中一个链表。我们假设链表A更长,如果链表A的长度比链表B短,那么我们就交换这两个链表。

    if(lenB > lenA){
        temp = headB;
        headB = headA;
        headA = temp;
        int temp2 = lenB;
        lenB = lenA;
        lenA =temp2;
        // 犯了一个错。下面两行在第一次提交代码的时候没有写。
        // 交换完链表A跟链表B后,相应的虚拟头节点也要做修改
        virtualHeadA.next = headA;
        virtualHeadB.next = headB;
    }

为啥要做交换链表这个操作,我不交换可以吗?
答案是当然可以。但是下面这段移动链表A的位置的代码就不能直接这样写了

    ListNode curA = virtualHeadA;
    for(int i = 0; i < count;i++){
        curA = curA.next;
    }

因为如果链表B更长的话,这里移动的应该是链表B。我加了交换链表的逻辑后,移动链表的代码就可以统一写成链表A了。
最后是判断两个链表的节点是否是相同的节点。这一段逻辑很简单。

  while(curA != null && curB != null){
        if(curA == curB){
            return curA;
        }else{
            curA = curA.next;
            curB = curB.next;
        }
    }

完整代码如下:

public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    int lenA = 0, lenB = 0;
    ListNode temp = headA;
    ListNode virtualHeadA = new ListNode(0);
    ListNode virtualHeadB = new ListNode(0);
    virtualHeadA.next = headA;
    virtualHeadB.next = headB;
    while (temp != null) {
        lenA++;
        temp = temp.next;
    }
    temp = headB;
    while (temp != null) {
        lenB++;
        temp = temp.next;
    }
    //交换过后,a是长的,b是短的
    if(lenB > lenA){
        temp = headB;
        headB = headA;
        headA = temp;
        int temp2 = lenB;
        lenB = lenA;
        lenA =temp2;
        // 犯了一个错。下面两行在第一次提交代码的时候没有写。
        // 交换完链表A跟链表B后,相应的虚拟头节点也要做修改
        virtualHeadA.next = headA;
        virtualHeadB.next = headB;
    }
    int count = lenA-lenB;
    ListNode curA = virtualHeadA;
    for(int i = 0; i < count;i++){
        curA = curA.next;
    }
    //此时链表a跟链表b的剩余个数是一样的
    ListNode curB = virtualHeadB;
    while(curA != null && curB != null){
        if(curA == curB){
            return curA;
        }else{
            curA = curA.next;
            curB = curB.next;
        }
    }
    return null;
环形链表2

题目描述:

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

我的解题思路:

未完待续…

参考链接:

代码随想录-链表-5.两两交换链表中的节点
代码随想录-链表-6.删除链表的倒数第N个节点
代码随想录-链表-7.链表相交
代码随想录-链表-8.环形链表

代码随想录八股文第四版pdf》是一本关于编程的指南,旨在帮助读者提高编程技能和优化代码。本书内容丰富全面,适合广大程序员和编程爱好者阅读。 首先,本书分为多个章节,每个章节涵盖了不同的编程主题。比如,第一章讲解了基础的编程概念和语法,包括变量、循环和函数等。第二章介绍了面向对象编程(OOP)的概念和原则,如封装、继承和多态等。接下来的章节逐步介绍了数据结构和算法,如数组、链表、栈和队列,以及排序和搜索算法等。此外,本书还对常见的编程问题进行了详细分析和解答,帮助读者培养解决问题的思维方式。 其次,本书的特色之一是通过八股文的形式呈现编程知识。作者以简练明了的语言,将复杂的编程概念和技巧概括成几句话,大大提高了读者的理解和记忆效果。例如,对于OOP的解释可以是:“封装数据和行为,继承通用特性,多态表现灵活性。”这种精炼的表述使得读者能够快速抓住核心要点,方便理解和运用。 此外,本书还提供了大量的实例代码和练习题,帮助读者巩固所学知识和提高编码能力。每个章节都附带了相关的代码示例,读者可以通过阅读代码和运行实验,加深对理论知识的理解。此外,练习题既可以作为学习过程中的自测工具,又可以作为深入学习和巩固知识的手段。 综上所述,《代码随想录八股文第四版pdf》是一本内容全面、形式独特的编程指南。通过阅读本书,读者可以系统学习编程知识和技巧,提高编码能力,为日后的编程工作打下坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值