首页 > 其他分享 >代码随想录第四天|链表part02--24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II

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

时间:2024-11-04 18:16:50浏览次数:5  
标签:结点 ListNode val 随想录 next 链表 null 节点

资源引用:

leetcode题目:

24.两两交换链表中的节点(24. 两两交换链表中的节点 - 力扣(LeetCode)

19.删除链表的倒数第N个结点(19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

面试题02.07.链表相交(面试题 02.07. 链表相交 - 力扣(LeetCode)

142.环形链表Ⅱ(142. 环形链表 II - 力扣(LeetCode)

第一自然周总结:

        第一周的训练营告一段落了,数组和链表的内容掌握的都很不错,尤其是链表的内容,今天一天完成,中等题目基本上都能思路非常清晰的解出,有好几道题都是一遍过,当然也遇到了一些出错的时候,能够很及时的用debug解决问题。尽管对边界条件的考虑有所提升,但仍然有提高空间,今天后两题不知道是太晚疲惫了还是什么原因,bug都是出在边界条件的设置上,希望自己能够更加小心谨慎!

        回过神来的时候已经错过了S14决赛的第一场,很开心BLG赢了,现在是第二把,很焦灼,虽然来晚了,但我会陪着他们走到最后,加油!

24.两两交换链表中的节点(24. 两两交换链表中的节点 - 力扣(LeetCode)

题目分析:

首先处理边界情况,即链表为空、链表仅有1个节点时直接返回。然后是按照链表长度为偶和为奇进行分类讨论(可能有双指针?):若为偶,直接从头到尾两两交换;若为奇,末尾指针不变。为便于交换,设计虚拟头节点dumpy。

先设计dumpy节点指向原本的头节点head;

完整思路:

设计前缀节点pre,作为将要交换的node1(pre.next=node1)和node2(node1.next=node2)的前缀,若node1和node2均不为空,则进行交换。先将pre指向node2,然后将node1指向node2.next,最后将node2指向node1则完成交换,将pre置为pre.next.next移动2个结点。

总结:

第一次一遍写对中等题,有点小成就感,临时前缀是个好东西!

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dumpy=new ListNode();
        dumpy.next = head;
        if(head == null || head.next == null){
            return head;
        }
        ListNode pre = dumpy;
        ListNode node1,node2;
        while(pre.next !=null && pre.next.next !=null){
            node1=pre.next;
            node2=pre.next.next;
            pre.next=node2;
            node1.next=node2.next;
            node2.next=node1;
            pre=pre.next.next;
        }
        return dumpy.next;
    }
}

19.删除链表的倒数第N个结点(19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

题目分析:

注意双指针的使用,要删除倒数第N个节点,则需要将指针指向其前缀节点,考虑结合虚拟头结点使用。

左指针从dumpy开始,右指针从dumpy后的第N个结点开始。

注意判断边界条件,如果不合则不删除直接返回。

最终返回dumpy.next

总结:

注意使用dumpy.next进行返回

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dumpy = new ListNode();
        if(head == null){
            return head;
        }
        dumpy.next = head;
        ListNode left = dumpy;
        ListNode right = dumpy;
        int index=0;
        while(index<n && right.next != null){
            right=right.next;
            index++;
        }
        if(right == null){
            return head;
        }
        index=0;
        while(right.next != null){
            left=left.next;
            right=right.next;
        }
        left.next=left.next.next;
        return dumpy.next;
    }
}

面试题02.07.链表相交(面试题 02.07. 链表相交 - 力扣(LeetCode)):

题目分析:

注意不可通过值相同来判断结点是否相同。

注意处理头结点为空的边界条件。

已知不存在环。

此题使用的是单链表。

仍然考虑使用双指针解决问题,首先通过遍历两个单链表,确定两个链表的长度只差x。

然后将快指针分配给较长的链表,慢指针分配给较短的链表,快指针从第x个结点开始(下标记录从x-1开始),慢指针从头结点开始(下标记录从0开始),循环比较二者是否相同,若相同则退出循环并返回该结点;若不相同,则二者一起向下移动1个结点。

反思:

需要注意,遍历链表必须使用curA和curB指针用于遍历,不能改变头结点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lengthA=0,lengthB=0,x=0;
        ListNode curA = headA;
        ListNode curB = headB;
        if(headA == null || headB == null){
            return null;
        }
        do{
            lengthA++;
            curA=curA.next;
        }while(curA != null);
        do{
            lengthB++;
            curB=curB.next;
        }while(curB != null);
        curA = headA;
        curB = headB;
        if(lengthA>lengthB){
            x = lengthA - lengthB;
            while(x-- > 0){
                curA = curA.next;
            }
        }else{
            x = lengthB - lengthA;
            while(x-- > 0){
                curB = curB.next;
            }
        }
        while(curA != curB && curA.next != null && curB.next != null){
            curA = curA.next;
            curB = curB.next;
        }
        if(curA == curB && curA.val != 0 && curB.val != 0){
            return curA;
        }else{
            return null;
        }
    }
}

142.环形链表Ⅱ(142. 环形链表 II - 力扣(LeetCode)

题目分析:

给出头结点,求解入环的第一个结点。环的大小未知,盲目进入可能会陷入死循环,判断是否为入环结点不可用值来判断,双指针能解决这个问题吗?

思路一:快慢指针法

考虑快慢指针,快指针一定会追上慢指针并在某个结点X,并且可以求出环的长度loop。此时从头结点再次出发,算出第一次遇到结点X的长度a。则入环结点i一定满足0≤i<a,且结点i向下走loop次后一定返回自身,从而确定i

快指针每走2步,慢指针走1步

注意index的边界条件!

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        int speed=0;
        ListNode fast = head;
        ListNode slow = head;
        //边界条件:链表为空直接返回null
        if(head == null || head.next == null){
            return null;
        }
        if(head.next == head){
            return head;
        }
        //边界条件:遍历过程中发现无环,退出循环并返回null
        while(fast.next != null && slow.next != null){
            fast=fast.next;
            slow=slow.next;
            //使fast指针的速度为slow指针的2倍,迟早会在某个结点X与slow指针相遇
            if(speed%2 == 0){
                //边界条件:如果遍历过程中发现无环,直接返回null
                if(fast.next == null || fast.next == fast){
                    return fast.next;
                }
                fast=fast.next;
                speed=0;
            }
            //快慢指针相遇即退出循环
            if(fast == slow){
                break;
            }
            speed++;
        }
        //判断相遇循环是否正常退出,若非正常退出,则直接返回null
        if(fast.next == null || slow.next == null){
            return null;
        }
        ListNode X = fast;//保存相遇结点X
        ListNode cur = head;//初始化寻址指针cur
        int head2X=0;//记录从头结点到结点X的距离
        int loop=0;//记录环的长度
        //求取从头结点到X的距离
        while(cur != X){
            cur = cur.next;
            head2X++;
        }
        //从相遇结点出发,求取环的长度
        do{
            cur = cur.next;
            loop++;
        }while(cur != X);
        int index=0;//寻找入环结点的尝试下标
        for(index=0;index<=head2X;index++){
            int i = index;
            cur = head;//重置cur指针
            while(i-- > 0){
                cur = cur.next;
            }
            ListNode indexNode = cur;
            i = loop;
            while(i-- > 0){
               cur = cur.next; 
            }
            if(cur == indexNode){
                return indexNode;
            }
        }
        return null;
    }
}

思路二:优化快慢指针(代码随想录 (programmercarl.com)

参考代码随想录的思路实现,仔细推理数量关系,能够简化寻找流程,感兴趣的可以阅读原文。

总结反思:要更加注意边界条件,遇到复杂的题目要大胆尝试推导数量关系!

标签:结点,ListNode,val,随想录,next,链表,null,节点
From: https://blog.csdn.net/csy031117/article/details/143458816

相关文章

  • ThingsBoard规则链节点:Message Count 节点详解
    引言1.MessageCount节点简介2.节点配置2.1基本配置示例3.使用场景3.1监控设备活跃度3.2检测异常情况3.3生成统计报告4.实际项目中的应用4.1项目背景4.2项目需求4.3实现步骤5.总结 ......
  • C语言链表深入解析:实现与应用
    ###标题:C语言链表深入解析:实现与应用---####正文:链表是计算机科学中重要的数据结构,因其灵活性和动态性而被广泛使用。本文将探讨链表的基本概念、实现方法以及一些常见的操作,帮助你全面掌握这一基础数据结构。---###一、链表概述链表由一系列节点组成,每个节点包含数据......
  • uniapp 页面导航条配置节点 navigation-bar
    navigation-bar页面导航条配置节点,用于指定导航栏的一些属性。只能是 page-meta 组件内的第一个节点,需要配合它一同使用。平台差异说明AppH5微信小程序支付宝小程序百度小程序抖音小程序、飞书小程序QQ小程序快手小程序京东小程序√2.6.3+2.6.3+√2.9.0+......
  • 代码随想录第十八天
    530.二叉搜索树的最小绝对差给你一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值。差值是一个正数,其数值等于两值之差的绝对值。示例1:输入:root=[4,2,6,1,3]输出:1示例2:输入:root=[1,0,48,null,null,12,49]输出:1提示:树中节点的数目范......
  • 代码随想录第十七天
    654.最大二叉树给定一个不重复的整数数组nums。最大二叉树可以用下面的算法从nums递归地构建:创建一个根节点,其值为nums中的最大值。递归地在最大值左边的子数组前缀上构建左子树。递归地在最大值右边的子数组后缀上构建右子树。返回nums构建的*最大......
  • 单链表OJ题(2):反转链表(三指针法)、找中间节点(快慢指针)
    目录1.反转链表反转链表总结:2.链表的中间节点(快慢指针法)快慢指针法总结1.反转链表在这道题中,我们需要把一个单链表反转它们的指向,这里,我们给出了一个好理解的简单解法,就是用三个指针去解决这道题。先给出完整的代码。/***Definitionforsingly-linkedlist.*......
  • 单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构
    目录 一、合并两个有序链表 二、链表分割三、链表的回文结构u解题的总体思路: 合并两个有序链表:首先创建新链表的头节点(哨兵位:本质上是占位子),为了减少一些判断情况,简化操作。然后我们再创建俩个指针分别指针两个单链表的头,然后遍历比较,将两个指针指向节点的最小值接......
  • 代码随想录算法训练营第十一天|leetcode150. 逆波兰表达式求值、leetcode239. 滑动窗
    1leetcode150.逆波兰表达式求值题目链接:150.逆波兰表达式求值-力扣(LeetCode)文章链接:代码随想录视频链接:栈的最后表演!|LeetCode:150.逆波兰表达式求值哔哩哔哩bilibili自己的思路:这是一道有思路,但是思路并不多的题目,就是我会觉得是先将数据进行添加,然后对于符号通过......