随想录DAY4|力扣24. 两两交换链表中的节点、19. 删除链表的倒数第 N 个结点面试题、 02.07. 链表相交、142. 环形链表 II、链表的难点及总结

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

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

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

思路:

在完成这一题时首先考虑的应该是要怎么进行链表节点操作的,具体要操作哪几个节点

想要完成这一操作,应当要操作三个节点,交换的节点有两个,而两个节点的前驱cur有一个,合在一起三个,完成这一操作,最好是把指针节点给到两个操作节点的前驱cur,这样操作与判断起来思路会更加清晰,在此借用卡哥的图进行说明

除此之外,还要注意链表最后剩的是单个节点还是双数节点,单个节点的话cur指针会落在最后节点的前一位,循环终止条件为cur.next.next == null,而双数节点的话cur节点会落在最后一个节点,终止条件为cur.next ==null,所以在使用while循坏时一定要使用&&的方式将两个条件并在一起判断

下面是代码:

public static ListNode swapPairs(ListNode head) {
        if(head == null||head.next ==null){
            return head;
        }
        //定义一个虚拟头结点
        ListNode virtualHead = new ListNode();
        virtualHead.next = head;
        ListNode cur = virtualHead;//指针所处位置
        ListNode latter1 = head;//指针的后驱
        ListNode latter2;//指针的后后继
        //循环条件很重要
        while(cur.next != null&&cur.next.next != null){
            //记录下节点的后继
            //交换过程
            latter1 = cur.next;
            latter2 = cur.next.next;
            cur.next = latter2;
            latter1.next = latter2.next;
            latter2.next = latter1;
            //换到下一个节点进行操作
            cur = cur.next.next;


        }
        return virtualHead.next;
    }

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

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

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

思路:

本题目的操作很简单,只要用删除节点的前一位pre进行pre.next = pre.next.next的操作即可,难点在于怎么快速找到这个删除的节点,在此也是使用双指针的办法实现

题目说的是删除倒数第n个节点,那么就可以确定删除节点的前一个节点pre到链表的末尾的空节点的距离差为n+1,根据这一点设置一个快指针探查链表的结尾,一个慢指针定位删除节点的前驱pre,快指针比慢指针先走n+1步即可实现这个方法,代码如下

//本题目采用了快慢指针的思想
    //快指针:探测到链表的末尾
    //慢指针:在快指针探测到末尾后正好指向目标节点的前一位,实现删除操作
    //要想实现这个操作,只需要快指针比慢指针多走n+1位就可以
    public ListNode removeNthFromEnd(ListNode head, int n) {

        ListNode virtualHead = new ListNode();
        virtualHead.next = head;
        ListNode fast = virtualHead;
        ListNode slow = virtualHead;
        for(int i =0;i<n+1;i++){
            fast = fast.next;
        }
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return virtualHead.next;
    }

面试题 02.07. 链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

我觉的这个问题有点der,题目说的意思都不太清楚,不想回顾了,直接贴上大佬的链接,可以去看看

代码随想录 (programmercarl.com)

142. 环形链表 II

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

在此单方面宣布这是链表算法题最有意思的一道,不接受反驳~

思路:

本题的难点主要有两个

1.怎么找出链表中有环

2.怎么找出环的入口位置

(ps:这里面涉及到了数学的方法,可以通过数学知识不用记下链表环的每一个节点从而求出入口的位置)
解法:
1.用一快一慢的两个指针,快指针一次走两步,慢指针一次走一步,如果能在链表中相遇说明有环
2.思路1:用数组记下环内所有的节点,然后让数组从头开始遍历,检测到之后返回结果
  思路2:用数学找出链表起点与入口点及指针相交点的关系,根据这个关系写代码找出入口*/

用数学算出两段距离关系的视频在这里我也给上大佬的链接,感兴趣可以去看看

把环形链表讲清楚!| LeetCode:142.环形链表II (opens new window)

代码如下:

public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //找出是否存在环
        while(true){
            if(fast==null||fast.next==null){
                return  null;
            }
            fast = fast.next.next;
            slow = slow.next;
            //说明存在环,记录点位退出循环
            if (fast == slow){

                break;
            }
        }
        /*
        设x为链表起点到循环入口的距离
        设y为入口到交点的距离
        设z为交点到入口的距离
        n为快指针在环里循环的次数
        可以算出x = (n - 1) (y + z) + z
        所以相交点处的指针走过了z之后便处于入口处
        在相交点及链表起点位置同时放一个指针向前进行遍历,两个指针相交点便是入口的位置*/
        ListNode star = head;
        while(star != slow){
            star = star.next;
            slow = slow.next;
        }
        return slow;

    }

对链表算法的总结:

链表的算法中,对于节点的操作是一个难点,思路捋清楚之后很简单,但是没有想清楚的话就容易犯操作空指针的错误,所以对于链表的增删改查这些基本的操作步骤要有个清晰的认识。

还有便是对于节点的判断,没有想出各种可能的话循环的条件可能会写错,这些感觉还是需要去积累的,做的题多了对于各种条件下的节点也会有一个更为清晰的认识

其他的便是判断链表是否有环的骚操作了,思路很简单,但是能不能想出来是个问题,多碰一下就会了

链表章的总结到此结束,感谢观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值