单链表常见算法问题(系列二)

前言

    在这之前,已经给大家分享了几个关于单链表算法问题的求解(思路+过程演示+代码实现):

    有关单链表常见几个算法问题解决

    今天继续给大家分享几个单链表的算法问题~

目录

1.链表分割

1.1 题目展示及写题链接

1.2 解决思路+过程展示

1.3 实现代码

1.4 运行测试

2.相交链表

2.1 题目展示及写题链接

2.2 解决思路+过程展示

2.3 实现代码

2.4 运行测试

3.环形链表

3.1 题目展示及写题链接

3.2 解决思路+过程展示

3.3 实现代码

3.4 运行测试

4.环形链表||

4.1 题目展示及写题链接

4.2 解决思路+过程展示

4.3 实现代码

4.4 运行测试


1.链表分割

1.1 题目展示及写题链接

        ● 题目展示

        ● 写题链接:链表分割

1.2 解决思路+过程展示

        ● 解决思路

           1)准备两个链表,一个链表存值小于x的结点(aHead首结点),另一个链表值存大于x的结点(bHead首结点)。

           注:为方便最后将两个链表链接所以要保存两个链表的首结点,而尾结点是为了便于尾插。

           2)对原始链表进行遍历,通过判断游标值的大小,分别对两个子链表进行尾插。

           3)遍历完毕后,分为三种情况返回:

                 ① 情况一:原始链表中所有结点都大于x → 返回bHead

                 ② 情况二:原始链表中所有结点都小于x → 返回aHead

                 ③ 情况三:原始链表中既有小于x的结点也有大于x的结点 → 与bHead链接后,返回aHead。

           注:当原始链表中最后一个结点值小于x时,那么bHead链表最后一个结点的next就会不为空,那么链接到aTail后,形成的链表就为环形链表,所以不管原始链表中最后一个结点值是否小于x,我们都要将bTail(最后一个结点).next域赋空。

        ● 过程展示

1.3 实现代码

public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        // write code here
        //1.准备要分割的俩个区间的头和尾
        ListNode aHead = null,aTail = null; //小于x的结点子链表的头和尾
        ListNode bHead = null,bTail = null; //大于x的结点子链表的头和尾

        //2.遍历整个链表进行两个子链表的尾插(不会改变原来的数据顺序)
        ListNode cur = pHead; //游标结点
        while(cur != null) {
            if(cur.val < x) {
                if(aHead == null) { //子链表为空游标结点则直接等于其首结点
                    aHead = cur;
                    aTail = cur;
                }else {
                    aTail.next = cur; //尾插
                    aTail = aTail.next;
                }
            }else {
                if(bHead == null) { //子链表为空游标结点则直接等于其首结点
                    bHead = cur;
                    bTail = cur;
                }else {
                    bTail.next = cur; //尾插
                    bTail = bTail.next;
                }
            }
            cur = cur.next;
        }

        //3.如果两个子链表都不为空则将两个子链表进行链接
        if(aTail == null) return bHead; //特殊情况一:pHead链表中所有结点均大于x

        //链接(普通情况:pHead链表中有大于也有小于x的结点 
        //和特殊情况二:所有结点都小于x皆返回aHead)
        //注:如果pHead链表中最后一个结点如果小于x的话,一定要将bTail.next置空不然会成为环形链表
        if(bHead != null) bTail.next = null; 
        aTail.next = bHead; 
        return aHead;
    }
}

1.4 运行测试


2.相交链表

2.1 题目展示及写题链接

        ● 题目展示 

        ● 写题链接:相交链表

2.2 解决思路+过程展示

        ● 解决思路

           1)因为两个原始链表不可改动,所以我们使用两个游标结点遍历它们,求出它们的长度。

           注:遍历完毕后一定要恢复两个游标结点,方便最后重新进行遍历。

           2)求出它们之间的长度差值,让链表长度较大的那个链表先走差值步。

           3)最后让两个游标结点同时走,直到它们相等,那么它们所在的结点就是两个链表的相交结点,返回它们中任意一个都可以。

        ● 过程展示

2.3 实现代码

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //1.准备遍历headA和headB的游标结点
        ListNode curA = headA,curB = headB;

        //2.在相交之前,让两个链表的结点个数一样
        int lenA = 0,lenB = 0;
        while(curA != null) {
            lenA++;
            curA = curA.next;
        }

        while(curB != null) {
            lenB++;
            curB = curB.next;
        }

        //恢复两个游标结点
        curA = headA;
        curB = headB;

        int len = lenA - lenB;
        if(len < 0) {
            curA = headB;//让curA一直都是存链表长度较大的那个链表
            curB = headA;//让curB一直都是存链表长度较小的那个链表
            len = lenB - lenA; //len一直大于或等于0
        }

        //3.让链表长度较大的那个链表先走len步,让它和链表长度较小的链表同步起来
        while(len != 0) {
            curA = curA.next;
            len--;
        }

        //4.同时走直到到相交结点
        while(curA != curB) {
            curA = curA.next;
            curB = curB.next;
        }
        return curA;
    }
}

2.4 运行测试


3.环形链表

3.1 题目展示及写题链接

        ● 题目展示

        ● 写题链接:环形链表

3.2 解决思路+过程展示

        ● 解决思路

           快慢指针:慢指针走一步,快指针走两步。

           如果快指针和慢指针最后相遇,则链表中存在环,反之,则不存在。

           注:快指针走的速度是慢指针走的速度的两倍,如果链表中有环的话,进入环之后,它们的距离是一定的(最大为环的长度),那么慢指针和快指针的距离会随着它们的不断移动,距离会慢慢缩小,直到它们两相遇,则能链表中有环。

        ● 过程展示

3.3 实现代码

public class Solution {
    public boolean hasCycle(ListNode head) {
       ListNode slow = head,fast = head;

       while(fast != null && fast.next != null) {
           slow = slow.next; //走一步
           fast = fast.next.next; //走两步
           if(slow.equals(fast)) return true; //是否相遇
       }
       return false; //没有相遇
    }
}

3.4 运行测试


4.环形链表||

4.1 题目展示及写题链接

        ● 题目展示

        ● 写题链接:环形链表||

4.2 解决思路+过程展示

        ● 解决思路

           快慢指针:慢指针走一步,快指针走两步。

           如果快指针和慢指针最后相遇,则链表中存在环,不存在环直接返回null,将慢指针恢复到原始链表的头,fast在链表环中它们的相遇点,两个指针同时(慢指针和快指针都一步一步地走)行走,再次相遇点就是链表开始入环的第一个节点。

        ● 过程展示

4.3 实现代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null) return null;
        //1.先判断链表是否有环(快慢指针)
        ListNode slow = head,fast = head;
        boolean flag = false;
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if(slow.equals(fast)) {
                flag = true;
                break;
            }
        }

        if(flag) {
            //2.再同时走直到相遇
            slow = head;//恢复慢指针
            while(!slow.equals(fast)) { //同时走(都一步一步的走)
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }else {
            return null;
        }
    }
}

4.4 运行测试


分享完毕~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值