链表面试题2(高频)

链表作为数据结构的重要知识点,通常作为大厂们笔试面试题,这里我写了两篇博客来解决,一共10道题,此篇为后五道题

上篇博客: 前五道题

目录

1. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。

2.链表的回文结构。

3.输入两个链表,找出它们的第一个公共结点。

4.给定一个链表,判断链表中是否有环。思路:

5.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NU


1. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
 

public ListNode partition(ListNode head,int x) {
        ListNode cur = head;
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;
        while (cur != null) {
            if (cur.val < x) {
                if (bs == null) {
                    bs = cur;
                    be = cur;
                } else {
                    be.next = cur;
                    be = be.next;
                }
            } else {
                if (as == null) {
                    as = cur;
                    ae = cur;
                } else {
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        if (bs == null) {
            return as;
        }
        be.next = as;
        if (as != null) {
            ae.next = null;
        }
        return bs;
    }

要用x分割链表,首先我们要定义5个节点,cur用来便利原来链表,剩下的我们把分割的先划分为两部分,小于x的在前,用bs做头be便利,大于x的放在后面,as做头ae便利。接着就进入循环进行便利,对cur的val值与x比较,小的接在be后,大的接在ae后,最后将两部分相连就成。注意,判断大小时,还要判断是否为第一次,如果为第一次bs,be都应为cur。最后在将ae.next也就是最后一个节点的next值设为null。


2.链表的回文结构。

public boolean chkPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            return true;
        }
        //1、找到链表的中间节点
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        //2、翻转
        ListNode cur = slow;
        ListNode curNext = cur.next;
        while (curNext != null) {
            slow = curNext;
            curNext = curNext.next;
            slow.next = cur;
            cur = slow;
        }

        //3、开始一个从头走,一个从尾巴走,直到相遇
        while (head != slow) {
            if (head.val != slow.val) {
                return false;
            }
            if (head.next == slow) {
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;
    }

要判断链表是否回文我们分三步,第一,找到最中间节点,第二,从中间节点开始翻转,第三,一个从头走,一个从尾巴走,比较每个值是否相同,找中间值我们定义快慢节点即可,翻转刚才也讲到,最后直接比较即可。


3.输入两个链表,找出它们的第一个公共结点。

 

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) {
            return null;
        }
        ListNode pl = headA;//指向长的链表
        ListNode ps = headB;//指向短的链表
        //1、分别求长度
        int lenA = 0;
        int lenB = 0;
        while (pl != null) {
            lenA++;
            pl = pl.next;
        }

        while (ps != null) {
            lenB++;
            ps = ps.next;
        }
        //需要重新修改指向
        pl = headA;
        ps = headB;

        //2、已经知道两个链表的长度了
        int len = lenA-lenB;
        if(len < 0) {
            pl = headB;
            ps = headA;
            len = lenB - lenA;
        }
        //1、求长度    2、pl永远指向 最长的那个链表   ps永远指向最短的那个链表

        //3、就是让最长的链表走len步
            while(len>0){
                pl=pl.next;
                len--;
            }
        //4、一人一步走 直到相遇
            while(pl!=ps){
                pl=pl.next;
                ps=ps.next;
            }

        //5、是不是两个都是null-》没有相交
        if(pl==null){
            return null;
        }
        return pl;
    }

求两个链表的交点,首先设一个pl和ps节点,pl指向长的,ps指向短的。接着我们分别求两个链表的长度,分别为lenA和lenB,如果两个链表相交,则长的减短的就为长的多余的部分,因此,我们设len为lenA,lenB的差值,接着判断如果len小于0,则是B链表长,我们要修改pl和ps的指向,到这里,ps永远指向短的,pl永远指向长的,多了len个节点,所以,长的,先走len步,接着两者同时走,知道他们相遇,就为他们的交点。注意,最后我们要对他们判断,如果都为null则说明不想交,返回null。


4.给定一个链表,判断链表中是否有环。

思路:

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。

 

public boolean hasCycle(ListNode head) {
        if (head == null) {
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                break;
            }
        }
        if (fast == null || fast.next == null) {
            return false;
        } else {
            return true;
        }   
    }

还是定义两个快慢指针,fast走两步,slow走一步,如果相遇就跳出循环,接着进行判断,如果fast或者fast。next为空,则说明他不是环否则为环。


5.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NUL

public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                break;
            }
        }
        if (fast != null && fast.next != null) {
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        } else {
            return null;
        }

我们至于要在上题判断完成环后再让一个节点回到head从头开始走,直到相遇就为入环点。

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿拉蕾wjh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值