【体验面试】百度真题:环形链表分成三等份

本问题对应课程链接:剑指offer刷题第二期

要求:
1、请打卡你的解题代码,如果能简单说一下思路则简单说一下思路。
2、给出你代码所用的时间复杂度和空间复杂度

核心模式做就行,这里我给一个统一的方法题,注意返回值是一个容器哦,里面放三个链表的节点。

public List< ListNode > getThreeListNode(ListNode head){

}

条件说明:
1、你可以当作它存在节点,并且节点个数是3的倍数。
2、你也可以当作它存在节点,但是节点的个数不一定是 3 的倍数,如果不是,则前面分出来的链表节点多一些来处理

参考代码

代码来自于 @西西弗斯的石头 同学(稍作一些修改),当不是 3 的倍数时,还是比较麻烦滴。下面是一个完整的代码,包括测试,你们可以直接粘贴运行。

import java.util.*;

public class GetThreeListNode {
    // 核心方法
    // 当节点是 3 的倍数,则均分,当不为3的倍数,比如 1 2 3 4 5 6 7,则分成
    // l1:1 2   l2:3 4   l3:5 6 7
    public static List<ListNode> getThreeListNode(ListNode head){
        //只有一个节点
        if(head.next==head){
            List<ListNode> list = new ArrayList<>();
            head.next = null;//防止返回一个环形链表
            list.add(head);
            list.add(null);
            list.add(null);
            return list;
        }
        // 只有两个节点
        if(head.next.next == head){
            List<ListNode> list = new ArrayList<>();
            ListNode temp =head.next;
            temp.next = null;
            list.add(temp);
            head.next = null;
            list.add(head);
            list.add(null);
            return list;
        }
        ListNode l1 = head;
        ListNode l2 = head.next;
        ListNode l3 = head.next.next;
        int count =1;
        ListNode temp = head;
        // 统计节点个数
        while (head.next!=temp){
            count++;
            head = head.next;
        }
       // System.out.println(count);
        List<ListNode> list= new ArrayList<>();
        // 节点是3的倍数,三个指针,走一步,走两步,走三步来进行切分
        if((count%3)==0){
            while(l3.next!=temp){
                l3 = l3.next.next.next;
                l2 = l2.next.next;
                l1 = l1.next;
            }
            ListNode a1 = l3.next;
            ListNode a2 = l2.next;
            ListNode a3 = l1.next;
            l1.next = null;
            l2.next = null;
            l3.next = null;
            list.add(a1);
            list.add(a2);
            list.add(a3);
        }else{
            int k = (int) Math.round(count*1.0/3)-1;
            while (k!=0){
                l2 = l2.next.next;
                l1 = l1.next;
                k--;
            }
            while(l3.next!=temp){
                l3 = l3.next;
            }
            ListNode a1 = l3.next;
            ListNode a2 = l2.next;
            ListNode a3 = l1.next;
            l1.next = null;
            l2.next = null;
            l3.next = null;
            list.add(a1);
            list.add(a3);
            list.add(a2);
        }


        return list;
    }



    // 测试
    public static void main(String[] args) {
        ListNode l1 = new ListNode(0);
        ListNode l2 = new ListNode(1);
        ListNode l3 = new ListNode(2);
        ListNode l4 = new ListNode(3);
        ListNode l5 = new ListNode(4);
        ListNode l6 = new ListNode(5);
        ListNode l7 = new ListNode(6);
        l1.next = l1;
        //l2.next = l1;
//        l3.next = l4;
//        l4.next = l1;
//        l5.next = l6;
//        l6.next = l7;
//        l7.next = l1;
        List<ListNode> threeListNode = getThreeListNode(l1);
        // 打印
        for(int i = 0; i < threeListNode.size(); i++){
            ListNode head = threeListNode.get(i);
            System.out.println("链表 i = " + i);
            while(head != null){
                System.out.println(head.val);
                head = head.next;
            }
        }
    }

    // ListNode 内部类,用来演示需要
    public static class ListNode{
        int val;
        ListNode next;
        public ListNode(int x){
            this.val = x;
        }
    }
}

共以下 38 个回答

  • lucca 普通 2022年12月31日 上午3:25
        public List<ListNode> getThreeListNode(ListNode head) {
            List<ListNode> ans = new ArrayList<>(3);
            ListNode l1 = head, l2 = head.next, l3 = head.next.next;
            ans.add(l1);
            ans.add(l2 == head ? null : l2);
            ans.add(l3 == head ? null : l3);
            // 如果不够三个元素,直接返回
            if (l1 == l2 || l1 == l3) return ans;
    
            // 如果还有三个没有加入list的节点
            while (l3.next != head && l3.next.next != head && l3.next.next.next != head) {
                l1.next = l3.next;
                l1 = l1.next;
    
                l2.next = l1.next;
                l2 = l2.next;
    
                l3.next = l2.next;
                l3 = l3.next;
            }
    
            // 如果全部用完
            if (l3.next == head) {
                l1.next = l2.next = l3.next = null;
                return ans;
            }
    
            // 如果还剩一个
            if (l3.next.next == head) {
                l1.next = l3.next;
                l1 = l1.next;
                l1.next = l2.next = l3.next = null;
                return ans;
            }
    
            // 如果还剩两个
            if (l3.next.next.next == head) {
                l1.next = l3.next;
                l1 = l1.next;
                l2.next = l1.next;
                l2 = l2.next;
                l1.next = l2.next = l3.next = null;
                return ans;
            }
            return ans;
        }
    
    0 赞同 0 条回复
  • mpweixin用户 永久会员 2022年12月9日 上午9:09

    在只要求三等分的情况下,是否可以建立 3 个表头
    然后遍历原链表,依次将节点加入这 3 个链表上
    最后返回

     public static List<ListNode> getThreeListNode(ListNode head){
            ListNode h1=new ListNode(0),h2=new ListNode(0),h3=new ListNode(0);
            ListNode p=head;
            int cnt=0;
            while(p!=null){
                if(cnt%3==0){
                    ListNode cur=new ListNode(p.val);
                    p=p.next;
                    cur.next=h1.next;
                    h1.next=cur;
                }else if(cnt%3==1){
                    ListNode cur=new ListNode(p.val);
                    p=p.next;
                    cur.next=h2.next;
                    h2.next=cur;
                }else{
                    // 2
                    ListNode cur=new ListNode(p.val);
                    p=p.next;
                    cur.next=h3.next;
                    h3.next=cur;
                }
            }
            List<ListNode> res= new ArrayList<>();
            if(h1.next!=null){
                res.add(h1.next);
            }
            if(h2.next!=null){
                res.add(h2.next);
            }
            if(h3.next!=null){
                res.add(h3.next);
            }
            return  res;
        }
    
    0 赞同 0 条回复
  • 糖鑫 普通 2022年12月4日 下午11:10
    import java.util.ArrayList;
    import java.util.List;
    
    public class test{
        public static void main(String[] args){
            test t=new test();
            int num[]= {1,2,3,4,5,6,7,8,9};
            ListNode head=new ListNode();
            ListNode prev=head;
            for(int i=0;i<num.length;i++) {
                prev.next=new ListNode(num[i]);
                prev=prev.next;
            }
            prev.next=head.next;
            List<ListNode> list=t.getThreeListNode(head.next);
            for(int i=0;i<list.size();i++) {
                ListNode cur=list.get(i);
                while(cur!=null) {
                    System.out.print(cur.val);
                    cur=cur.next;
                }
                System.out.println();
            }
        }
    
        public List< ListNode > getThreeListNode(ListNode head){
            if(head==null) return null;
            int length=1;
            ListNode cur=head.next;
            while(cur!=head) {
                length++;
                cur=cur.next;
            }
            ListNode l1,l2,l3;
            List<ListNode> list=new ArrayList<>();
            if(length==1) {
                head.next=null;
                l1=head;
                l2=null;
                l3=null;
            }else if(length==2) {
                l1=head;
                l2=head.next;
                l3=null;
                l1.next=null;
                l2.next=null;
            }else {
                int remainder=length%3;
                l1=head;l2=head;l3=head;
                ListNode tmp;
                if(remainder==0) {
                    while(l1.next.next.next!=head) {
                        l2=l2.next;
                        l3=l3.next.next;
                        l1=l1.next.next.next;
                    }
                    l1=l1.next.next;
                    l3=l3.next;
                    l1.next=null;
                    l1=head;
                    tmp=l2.next;
                    l2.next=null;
                    l2=tmp;
                    tmp=l3.next;
                    l3.next=null;
                    l3=tmp;
                }else {
                while(remainder-1>0) {//少走一步以便于将上一部分的尾部断开
                    l2=l2.next;
                    l3=l3.next;
                    l1=l1.next;
                    remainder--;
                }
                while(l1.next!=head) {
                    l2=l2.next;
                    l3=l3.next.next;
                    l1=l1.next.next.next;
                }
                l1.next=null;
                l1=head;
                tmp=l2.next;
                l2.next=null;
                l2=tmp;
                tmp=l3.next;
                l3.next=null;
                l3=tmp;
                }
            }
            list.add(l1);list.add(l2);list.add(l3);
            return list;
        }
    
    }
    
    0 赞同 0 条回复
  • 你有点可爱喔 普通 2022年12月1日 下午3:21
    package com.mos.yygh.structData;
    
    import java.util.*;
    
    /** 分情况考虑*/
    public class GetThreeListNode {
        // 1:当节点是 3 的倍数,则均分,
        // 2:当不为3的倍数,比如 1 2 3 4 5 6 7,则分成
        // l1:1 2   l2:3 4   l3:5 6 7
        public static List<ListNode> getThreeListNode(ListNode head){
            //只有一个节点
            if(head.next==head){
                List<ListNode> list = new ArrayList<>();
                head.next = null;//防止返回一个环形链表
                list.add(head);
                list.add(null);
                list.add(null);
                return list;
            }
            // 只有两个节点
            if(head.next.next == head){
                List<ListNode> list = new ArrayList<>();
                ListNode temp =head.next;
                temp.next = null;
                list.add(temp);
                head.next = null;
                list.add(head);
                list.add(null);
                return list;
            }
            ListNode l1 = head;
            ListNode l2 = head.next;
            ListNode l3 = head.next.next;
            int count =1;
            ListNode temp = head;
            // 统计节点个数
            while (head.next!=temp){
                count++;
                head = head.next;
            }
            List<ListNode> list= new ArrayList<>();
            // 节点是3的倍数,三个指针,走一步,走两步,走三步来进行切分
            if((count%3)==0){
                while(l3.next!=temp){
                    l3 = l3.next.next.next;
                    l2 = l2.next.next;
                    l1 = l1.next;
                }
                ListNode a1 = l3.next;
                ListNode a2 = l2.next;
                ListNode a3 = l1.next;
                l1.next = null;
                l2.next = null;
                l3.next = null;
                list.add(a1);
                list.add(a2);
                list.add(a3);
            }else{
                int k = (int) Math.round(count*1.0/3)-1;
                while (k!=0){
                    l2 = l2.next.next;
                    l1 = l1.next;
                    k--;
                }
                while(l3.next!=temp){
                    l3 = l3.next;
                }
                ListNode a1 = l3.next;
                ListNode a2 = l2.next;
                ListNode a3 = l1.next;
                l1.next = null;
                l2.next = null;
                l3.next = null;
                list.add(a1);
                list.add(a3);
                list.add(a2);
            }
    
    
            return list;
        }
    
    
        // ListNode 内部类,用来演示需要
        public static class ListNode{
            int val;
            ListNode next;
            public ListNode(int x){
                this.val = x;
            }
        }
    }
    
    
    0 赞同 0 条回复
  • PatNick 普通 2022年11月20日 上午10:34
    def getThreeListNode(head:Node):
        result_list = []
        # 只有一个节点时
        if head.next == head:
            # 将自身的环解开
            head.next = None
            result_list.append(head)
            result_list.append(None)
            result_list.append(None)
            return result_list
    
        # 如果有两个节点
        if head.next.next == head:
            # 从后往前断掉两个节点的next(如果从前往后断将找不到后面的节点)
            tem = head.next
            tem.next = None
            result_list.append(tem)
            head.next = None
            result_list.append(head)
            result_list.append(None)
            return result_list
    
        # 超过两个节点,计算节点的个数
        cur = head
        count = 0
        while(cur.next != head):
            count += 1
            cur = cur.next
    
    
        '''
        需要三个指针p1,p2,p3,起始位置分别位于head,head.next,head.next.next
        p1步幅为1,p2步幅为2,p3步幅为3,当p3.next == head时停止,此时p1.next、p2.next、p3.next三个节点就是均分的起始点
        【三个指针的起始位置相当于对三个节点进行了三等份的均分,走一次后,第一个指针向后走了一个,此时前两个节点都属于均分后的第一份,
        第二个指针如果想使第一个指针走一步后的位置后到第二个指针走一步后的位置之间为均分后的第二个部分,第二个指针就必须走两个节点,因为此时第一个指针已经向后走了一个,基于这个第二个指针首先要走一个节点,
        同时还要自己再走一步作为自己这一份的扩展,同理第三个指针首先要走两个节点(因为前两个指针都往后走了一步),再走一步作为自己的扩展】
        虽然每次走的步幅不同,但每走一次都使自己都一份多了一个节点
        '''
        p1 = head
        p2 = head.next
        p3 = head.next.next
    
        # 如果节点是3的倍数
        if count % 3 == 0:
    
    
            while(p3.next != head):
                p1 = p1.next
                p2 = p2.next.next
                p3 = p3.next.next.next
    
    
            # 此时p1、p2、p3的位置分别为均分后每一份的最后一个节点
            # a1、a2、a3为均分后每份的头节点
            a1 = p3.next
            a2 = p1.next
            a3 = p2.next
    
            # 在放入list中前,将每一份之间的next断掉
            p1.next = None
            p2.next = None
            p3.next = None
    
            result_list.append(a1)
            result_list.append(a2)
            result_list.append(a3)
            return result_list
        else:
            # 如果节点不是3的倍数,则不能均分,如:1,2,3,4,5,6,7分为1,2;3,4;5,6,7
            '''
            这种情况就不能让第三个指针同时与第一第二指针一起走(步幅为3)了。因为此时虽然不能均分3份,但是还是可以保证有两个份是均分的,第三份会多一个节点或少一个节点
            所以第一和第二个指针还是使用原来的方式前进,但前进的步数为int(count / 3 + 0.5)-1【count / 3为小数,在python中为了能四舍五入,加0。5后用int截断整数,
            也就是说如果忽略掉第三份多出来或者少的情况,均分后每一份应该是2个节点,此时三个指针已经占用了一个节点,
            所以需要在走(节点总数/3-1)次】,当第一、二个指针走完后,剩下的就是第三份)
            '''
            count_ = int(count / 3 + 0.5)-1
            while(count_ != 0):
                # 前两个指针先走
                p1 = p1.next
                p2 = p2.next.next
                count_ -= 1
    
            while(p3.next != head):
                # 前两个指针走完后,剩下的就是第三份,第三个指针一个一步步走到边界
                p3 = p3.next
    
                # a1、a2、a3为均分后每份的头节点
                a1 = p3.next
                a2 = p1.next
                a3 = p2.next
    
                # 在放入list中前,将每一份之间的next断掉
                p1.next = None
                p2.next = None
                p3.next = None
    
                result_list.append(a1)
                result_list.append(a2)
                result_list.append(a3)
                return result_list
    
    
    
    0 赞同 0 条回复
  • 追 普通 2022年11月9日 下午4:51

    打卡,学习一下思路

    0 赞同 0 条回复
  • 如梦似歌 普通 2022年11月8日 下午10:50

    打卡,学习一下解题思路。

    0 赞同 0 条回复
  • 潜行1 我是火车王! 普通 2022年10月28日 上午11:19

    代码大概看得懂,核心是对节点数不是3的情况下的处理
    代码就不写了,调试起来费时间

    0 赞同 0 条回复
  • 狗蛋儿 普通 2022年10月27日 下午3:43

    一点点思路,没有很明白,请教一下身边的人再来看1

    0 赞同 0 条回复
  • lobort 普通 2022年10月27日 下午2:25

    有点思路 但是没太明白

    0 赞同 0 条回复
  • symbol 普通 2022年10月26日 下午8:01

    看完方法打个卡

    0 赞同 0 条回复
  • cxxz 普通 2022年10月26日 下午7:18

    默认存在节点。当节点数为一,直接返回一个头。其他情况统一,采用步长为3轮流取节点(不知道这样算不算等分呢?)。这样也不需要考虑链表长度是不是3的倍数。几种情况测试均通过。

    vector<ListNode *> getThreeListNode(ListNode* head){
            if ( head->next == nullptr)
                return vector <ListNode *>{head, nullptr, nullptr};
            ListNode *new0 = head, *new1, *new2, *cur = head->next, *entry = head;
            new1 = new ListNode(0);
            new2 = new ListNode(0);
            ListNode *newh0 = new0, *newh1 = new1, *newh2 = new2;
            int idx = 0;
            while ( cur != entry) {
                idx ++;
                if (idx % 3 == 0)
                {
                    new0->next = cur;
                    new0 = new0->next;
                }    
                else if (idx % 3 == 1) {
                    new1->next = cur;
                    new1 = new1->next;
                }
                else if (idx % 3 == 2) {
                    new2->next = cur;
                    new2 = new2->next;
                }
                cur = cur->next;
            }
            new0->next = nullptr;
            new1->next = nullptr;
            new2->next = nullptr;
    
            vector <ListNode *> ret;
            ret.push_back(newh0);
            ret.push_back(newh1->next);
            ret.push_back(newh2->next);
            return ret;
        }
    
    int main()
    {
        ListNode* n1 = new ListNode(0);
        // ListNode* n2 = new ListNode(1);
        // ListNode* n3 = new ListNode(2);
        // ListNode* n4 = new ListNode(3);
        // ListNode* m1 = new ListNode(4);
        // ListNode* m2 = new ListNode(5);
        // ListNode* m3 = new ListNode(6);
        // ListNode* m4 = new ListNode(7);
        // ListNode* m5 = new ListNode(8);
        // ListNode* m6 = new ListNode(9);
    
        // n1->next = n2;
        // n2->next = n1;
        // n3->next = n4;
        // n4->next = m1;
        // m1->next = m2;
        // m2->next = m3;
        // m3->next = m4;
        // m4->next = m5;
        // m5->next = m6;
        // m4->next = n1;
    
        Solution sl;
        vector<ListNode *> ret1 = sl.getThreeListNode(n1);
        for ( auto x : ret1) {
            ListNode *y = x;
            while ( y != nullptr ) {
                cout << y->val << " -> ";
                y = y->next;
            }
            cout << endl;
        }
    }
    

    时间复杂度O(n)
    空间复杂度O(1)

    0 赞同 0 条回复
  • Tolkien 永久会员 2022年10月26日 下午3:18

    三指针
    1. 时间复杂度:O(n)
    2. 空间复杂度:O(1)
    3. 代码

    public List<ListNode> getThreeListNode(ListNode head) {
            if (head == null) {
                return null;
            }
    
            // 1. 求环形链表的大小
            ListNode temp = head.next;
            int size = 1;
            while (temp != null) {
                size++;
                temp = temp.next;
            }
    
            if (size < 3) {
                return null;
            }
    
            // 2. 通过大小三等分设置快慢指针
            ListNode firstPoint = head;
            ListNode secondPoint = head;
            ListNode thirdPoint = head;
            for (int i = 0; i < size/3-1 ; i++) {
                firstPoint = firstPoint.next;
            }
            for (int i = 0; i < 2*size/3-1; i++) {
                secondPoint = secondPoint.next;
            }
    
            for (int i = 0; i < 3*size/3-1; i++) {
                thirdPoint = thirdPoint.next;
            }
    
            // 3. 分割
            ArrayList<ListNode> results = new ArrayList<>();
            thirdPoint.next = null;
            ListNode thirdList = secondPoint.next;
    
            secondPoint.next = null;
            ListNode secondList = firstPoint.next;
    
            firstPoint.next = null;
            results.add(head);
            results.add(secondList);
            results.add(thirdList);
    
            return results;
        }
    
    0 赞同 0 条回复
  • 刺猬 普通 2022年10月26日 上午11:52

    悄悄打个卡

    0 赞同 0 条回复
  • 浅夏的无奈 普通 2022年10月26日 上午11:36

    大概方法理解了,就不写了
    上面的代码还是有一点问题,3的倍数余1的话,链表长度会出现问题

    0 赞同 0 条回复
  • @ 普通 2022年10月26日 上午10:09

    打个卡,这个就先不做了。

    0 赞同 0 条回复
  • 马啸天 永久会员 2022年10月26日 上午8:42
      public List<ListNode> getThreeListNode(ListNode head) {
    
            List<ListNode> list = new ArrayList<>();
            ListNode h1 = null, h2 = null, h3 = null;
            ListNode l1 = null, l2 = null, l3 = null;
            boolean key = false;
            ListNode cur = head;
    
            while (true) {
    
                //没有节点
                if (head == null) {
                    list.add(null);
                    list.add(null);
                    list.add(null);
                    break;
                } else {
                    //有节点
                    //头结点问题
                    if (cur != head || !key) {
                        if (h1 == null) {
                            h1 = cur;l1 = cur;key = true;
                        } else {
                            l1.next = cur;
                            l1=l1.next;
                        }
                        cur = cur.next;
                    }
    
                    //第二个节点
                    if (cur != head) {
                        if (h2 == null) {
                            h2 = cur;l2 = cur;
                        } else {
                            l2.next = cur;
                            l2=l2.next;
                        }
                        cur = cur.next;
                    }
                    //第三个节点
                    if (cur != head) {
                        if (h3 == null) {
                            h3 = cur;l3 = cur;
                        } else {
                            l3.next = cur;
                            l3=l3.next;
                        }
                        cur = cur.next;
                    }
    
                    if (cur == head) {
                        //环形链表构造
    //                    if (h1 != null)
    //                        l1.next = h1;
    //                    if (h2 != null)
    //                        l2.next = h2;
    //                    if (h3 != null)
    //                        l3.next = h3;
    
                        if (h1 != null)
                            l1.next = null;
                        if (h2 != null)
                            l2.next = null;
                        if (h3 != null)
                            l3.next = null;
    
                        list.add(h1);
                        list.add(h2);
                        list.add(h3);
                        break;
                    }
                }
    
            }
            return list;
        }
    
    0 赞同 0 条回复
  • 天然 普通 2022年10月25日 下午9:42

    统计表长,如果不是三的倍数,让指针移动到3倍数的开始,移动步长为(num-num%3)/3 记录pre结点,完成分割,不晓得对不对 时间复杂度O(n) 空间复杂度O(1)

    class Solution(object):
        def getKthFromEnd(self, head, k):
            """
            :type head: ListNode
            :type k: int
            :rtype: ListNode
            """
            num =0
            T1 = head
            while T1.next!=head:
                num+=1
                T1 = T1.next
            T1.next = None
            if num<3:
                return None
            T1 = head
            if num%3 ! = 0:
                 k = num//3
                 while k:
                    T1 = T1.next
                    k-= 1    
            T2 = T1
            k = num-(num%3)/3
            num1 = k  
            pre1 =None      
            while k!=0:
                pre1 = T2
                T2 = T2.next
                k-=1
            pre1.next =None
            T3 = T2
            while num!=0:
                pre1 = T3
                T3 = T3.next
                num-=1
            pre1.next =None
    
            return head,T2,T3
    
    0 赞同 0 条回复
  • Asphyxia 普通 2022年10月25日 下午5:19

    快慢指针,用三个指针分别处理
    (话说leetcode上没找到具体题目呀,有无指路~)

    0 赞同 0 条回复
  • 宁 永久会员 2022年10月25日 下午4:27

    刚好是三的倍数的思路。

    public static List<ListNode> getThreeListNode(ListNode head){
            List<ListNode> list = new ArrayList<>();
            if (head.next.next.next == head){
                ListNode h1 = head;
                ListNode h2 = head.next;
                ListNode h3 = head.next.next;
                h1.next = null;
                h2.next = null;
                h3.next = null;
                list.add(h1);
                list.add(h2);
                list.add(h3);
                return list;
            }
            ListNode h1 = head.next, h2 = head.next.next, h3 = head.next.next.next;
            ListNode prev1 = null, prev2 = null, prev3 = null;
            while (h3 != head){
                prev1 = h1;
                h1 = h1.next;
                prev2 = h2.next;
                h2 = h2.next.next;
                prev3 = h3.next.next;
                h3 = h3.next.next.next;
            }
            prev1.next = null;
            prev2.next = null;
            prev3.next = null;
            list.add(h1);
            list.add(h2);
            list.add(h3);
            return list;
        }
    
    0 赞同 2 条回复
  • 猫猫真可爱 普通 2022年10月25日 下午3:55

    先遍历一遍看看有多少个结点,然后计算每一段一个分几个,模3运算三种情况分别处理,最后返回三个结点。

    0 赞同 0 条回复
  • 西西弗斯的石头 永久会员 2022年10月25日 下午3:47

    时间复杂度为O(n),空间复杂度为O(1),三指针法

    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    
    public class GetThreeListNode {
        public static void main(String[] args) {
            ListNode l1 = new ListNode(1);
            ListNode l2 = new ListNode(2);
            ListNode l3 = new ListNode(3);
            ListNode l4 = new ListNode(4);
            ListNode l5 = new ListNode(5);
            l1.next = l2;
            l2.next = l3;
            l3.next = l4;
            l4.next = l5;
            l5.next = l1;
            List<ListNode> threeListNode = getThreeListNode(l1);
    
            // 打印
            for(int i = 0; i < threeListNode.size(); i++){
                ListNode head = threeListNode.get(i);
                System.out.println("链表 i = " + i);
                while(head != null){
                    System.out.println(head.val);
                    head = head.next;
                }
            }
        }
        public static List<ListNode> getThreeListNode(ListNode head){
            if(head==null){
                List<ListNode> list = new ArrayList<>();
                list.add(null);
                list.add(null);
                list.add(null);
                return list;
            }
            ListNode l1 = head;
            ListNode l2 = head.next;
            ListNode l3 = head.next.next;
            int count =1;
            ListNode temp = head;
            while (head.next!=temp){
                count++;
                head = head.next;
            }
            if (count==1){
                List<ListNode> list = new ArrayList<>();
                temp.next = null;
                list.add(temp);
                list.add(null);
                list.add(null);
                return list;
            }
            if(count == 2){
                List<ListNode> list = new ArrayList<>();
                ListNode a =temp.next;
                temp.next = null;
                list.add(temp);
                a.next = null;
                list.add(a);
                list.add(null);
                return list;
            }
            System.out.println(count);
            List<ListNode> list= new ArrayList<>();
            if((count%3)==0){
                while(l3.next!=temp){
                    l3 = l3.next.next.next;
                    l2 = l2.next.next;
                    l1 = l1.next;
                }
                ListNode a1 = l3.next;
                ListNode a2 = l2.next;
                ListNode a3 = l1.next;
                l1.next = null;
                l2.next = null;
                l3.next = null;
                list.add(a1);
                list.add(a2);
                list.add(a3);
            }else{
                int k = (int) Math.round(count*1.0/3)-1;
                while (k!=0){
                    l2 = l2.next.next;
                    l1 = l1.next;
                    k--;
                }
                while(l3.next!=temp){
                    l3 = l3.next;
                }
                ListNode a1 = l3.next;
                ListNode a2 = l2.next;
                ListNode a3 = l1.next;
                l1.next = null;
                l2.next = null;
                l3.next = null;
                list.add(a1);
                list.add(a3);
                list.add(a2);
            }
    
    
            return list;
        }
    }
    
    0 赞同 1 条回复
  • 派大星 普通 2022年10月25日 下午2:00
    public List<ListNode> getThreeListNode(ListNode head) {
    //先确定环形链表的实际节点个数,然后再判断是否是3的倍数,分类讨论
    //时间复杂度O(n^2)
    //空间复杂度O(1)
            if (head == null) {
                return null;
            }
            ListNode temp = head.next;
            int i = 0;
            while (temp != head && temp!=null) {
                i++;
                temp = temp.next;
            }
            i++;
            ListNode temp1 = head;
            List<ListNode> nodes = new ArrayList<>();
            if (i % 3 == 0) {
                int num = i / 3;
                for (int j = 0; j < 3; j++) {
                    ListNode ln = temp1;
                    nodes.add(ln);
                    for (int k = 0; k < (num-1); k++) {        //123   456  789
                        temp1 = temp1.next;
                    }
                    ListNode l = temp1.next;
                    temp1.next = null;
                    temp1 = l;
                    ln = temp1;
                }
            } else {
                int num = i / 3;
                int el = i % 3;
                if (num == 0) {
                    if (i % 3 == 1) {
                        nodes.add(head);
                        head.next = null;
                    }
                    if (i % 3 == 2) {
                        nodes.add(head);
                        temp1 = head.next;
                        head.next = null;
                        nodes.add(temp1);
                        temp1.next = null;
                    }
                } else {
                    int[] leng = new int[0];
                    if (el == 1) {
                        leng = new int[]{num+1, num, num};
                    }
                    if (el == 2) {
                        leng = new int[]{num+1, num+1, num};
                    }
                    for (int j = 0; j < 3; j++) {
                        ListNode ln = temp1;
                        nodes.add(ln);
                        for (int k = 0; k < (leng[j]-1); k++) {
                            temp1 = temp1.next;
                        }
                        ListNode l = temp1.next;
                        temp1.next = null;
                        temp1 = l;
                        ln = temp1;
                    }
                }
            }
            return nodes;
        }
    }
    
    0 赞同 0 条回复
  • 鸿渐 普通 2022年10月25日 下午1:59

    用3个指针,第一个每次next一次,第二个两次,第三个三次。
    当第三个到达链表尾时,第一个正好在1/3处,第二个在2/3处

    0 赞同 0 条回复
  • 小肸 永久会员 2022年10月25日 下午1:36

    思路:定义三个指针p1、p2、p3,p1一次走一步,p2一次走两步,p3一次走三步,如果环的长度正好为3的倍数,那[head, p1]就是第一段,[p1.next, p2]就是第二段, [p2.next, p3]就是第三段。如果环的长度不为3的倍数,要么多出来一个节点,要么多出来两个节点。对于多出来的一个节点,把它分给第三段,而对于多出来的两个节点,均分给第二段和第三段。时间复杂度O(N),空间复杂度O(1)。

    public class Solution {
        public List getThreeListNode(ListNode head){
            if (head == null || head.next == null || head.next.next == null) {
                return null;
            }
            Set set = new HashSet<>();
            ListNode p1 = head, p2 = head.next, p3 = head.next.next;
            set.addAll(new ArrayList<>(Arrays.asList(new ListNode[]{p1, p2, p3})));
            while (!set.contains(p3.next.next.next)) {
                p1 = p1.next;
                p2 = p2.next.next;
                p3 = p3.next.next.next;
                set.addAll(new ArrayList<>(Arrays.asList(new ListNode[]{p1, p2, p3})));
            }
            // 如果多出来两个个节点,分给第二段和第三段
            if (!set.contains(p3.next.next)) {
                p3 = p3.next.next;
                p2 = p2.next;
            }
            // 如果多出来一个节点,分给第三段
            else if(!set.contains(p3.next)) {
                p3 = p3.next;
            }
            return new ArrayList<>(Arrays.asList(p1, p2, p3));
        }
    }
    

    之前测试了下,但没放测试代码(节点数少于三个没有特殊处理,我是直接返回null),现在补上去。

    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class ListNode {
        int val;
        ListNode next;
        public ListNode(Integer val) {
            this.val = val;
        }
        public static ListNode constructListNode (int[] nums) {
            List res = nums.length == 0 ? null : new ArrayList<>(nums.length);
            for (int i = 0; i < nums.length; i ++) {
                ListNode node = new ListNode(nums[i]);
                res.add(node);
            }
            for (int i = 0; i < nums.length; i ++) {
                if (i != res.size() - 1) {
                    res.get(i).next = res.get(i + 1);
                }
            }
            return res == null ? null : res.get(0);
        }
        public static ListNode toLoopList(ListNode head) {
            ListNode cur = head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = head;
            return head;
        }
        public static void printLoopList(ListNode head) {
            Set set =  new HashSet<>();
            StringBuilder res = new StringBuilder();
            ListNode cur = head;
            while (!set.contains(cur)) {
                res.append(cur.val + "->");
                set.add(cur);
                cur = cur.next;
            }
            System.out.println(res.toString());
        }
        public static void printListNode(ListNode head) {
            StringBuilder res = new StringBuilder();
            while (head != null) {
                res.append(head.val + "->");
                head = head.next;
            }
            res.append("null");
            System.out.println(res.toString());
        }
    }
    
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) {
    //        int[] num1 = {9,1};
    //        int[] num2 = {1,9};
    //        ListNode head1 = ListNode.constructListNode(num1);
    //        ListNode head2 = ListNode.constructListNode(num2);
    //        ListNode.printListNode(head1);
    //        ListNode.printListNode(head2);
    //        ListNode.printListNode(new Solution().linkedListNode(head1, head2));
            int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
            ListNode head = ListNode.constructListNode(nums);
            head = ListNode.toLoopList(head);
            List res = new Solution().getThreeListNode(head);
    //打印三个用来分割的节点值,
            System.out.println(res.get(0).val + " " + res.get(1).val + " " + res.get(2).val);
    //打印第一段
            printPartVal(head, res.get(0));
    //打印第二段
            printPartVal(res.get(0).next, res.get(1));
    //打印第三段
            printPartVal(res.get(1).next, res.get(2));
        }
        private static void printPartVal(ListNode start, ListNode end) {
            StringBuilder res = new StringBuilder();
            while (start != end) {
                res.append(start.val + "->");
                start = start.next;
            }
            res.append(start.val);
            System.out.println(res);
        }
    }
    
    0 赞同 0 条回复
  • yanshuojune 普通 2022年10月25日 上午9:50

    解题思路:认为节点数量为3的整数倍,对于少于3个节点的情况,返回None,定义3个指针,第一个每次next一次,第二个两次,第三个三次。当第三个指针的next指向head时,第一个停在1/3处,第二个停在2/3处。
    时间复杂度:O(n)
    空间复杂度:O(3)

    class Solution:
        def getThreeListNode(self, head: Optional[ListNode]):
            res = []
            p1 = head
            p2 = head.next
            p3 = head.next.next
            if p1 == p2 or p1 == p3:
                return None        
            while p3.next != head:
                p1 = p1.next
                p2 = p2.next.next
                p3 = p3.next.next.next
            res.append(p1)
            res.append(p2)
            res.append(p3)
            return res
    
    0 赞同 0 条回复
  • Ruby🗽 普通 2022年10月25日 上午12:53

    如果是三的倍数就快慢指针,三种步长,1,2,3;
    如果不是三的倍数,但允许第一个多分一点,则遍历整个链表,得到size,除3得到平均长度,size取3的余数,是前面节点多的节点数

    0 赞同 0 条回复
  • 黎昕 普通 2022年10月25日 上午12:09

    不是十分确定这道题的意思:是需要mod 3余数为0、1、2的序号分别拆出来,还是只需要分三段就行。
    如果是后者,条件更加宽松,存在以下解法:
    1. 快慢指针:定义三个指针,第一个走一步时,第二个走两步,第三个走三步,当三号指针重新到达头部时分割
    2. 遍历计数后分割。

    0 赞同 1 条回复
  • 青木 普通 2022年10月24日 下午11:17
    // 思路就是循环一遍记录节点数,再进行拆分,这里写的条件是节点数为3的倍数
    // 写的比较丑,不知道对不对
    // 时间复杂度O(n)
    // 空间复杂度O(1)
    public List<ListNode> getThreeListNode(ListNode head){
        ListNode p1 = head, p2 = new ListNode(), p3 = new ListNode();
        int n = 1, use2 = 0, use3 = 0;
        head = head.next
        while(head != p1){
            n += 1;
            head = head.next;
        }
        int time = 3;
    
        while(time != 0){
            int slice = n / 3 - 1;
            while(slice != 0){
                slice -= 1;
                head = head.next;
            }
            if(use2 == 0){
                p2 = head.next;
                head.next = null;
                head = p2;
                use2 = 1;
            }
            else if(use3 == 0){
                p3 = head.next;
                head.next = null;
                head = p3;
                use3 = 1;
            }
            else{
                head.next = null;
            }
            time -= 1;
        }
        List<ListNode> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
    
        return list;
    }
    
    0 赞同 0 条回复
  • T 普通 2022年10月24日 下午11:11

    下面代码

    public class Day3Q2 {
      public List<ListNode> getThreeListNode(ListNode head){
        //如果默认节点数大于等3
        ListNode cur = head.next;
        int len = 1;
        //循环统计节点个数,遍历到同一个节点说明循环结束。
        while(cur != head) {
          cur = cur.next;
          len++;
        }
        //如果rem等于0则是3的倍数否则不是。
        int rem = len % 3;
        //计算每段多长
        int subLen = len / 3;
    
        List<ListNode> list = new ArrayList<>();
    
        //循环三次,分成三段
        for (int i = 0; i < 3; i++) {
          // 用来标记遍历到每一段的第几个节点
          int tmpLen = 0;
          int sumLen;
          // 如果是第一段则最长应该是平均每段+多出来的节点数
          if(i == 0) {
             sumLen = rem != 0 ? subLen + rem : subLen;
          } else {
            sumLen = subLen;
          }
          // 定义一个哑结点,连接head节点。
          ListNode dummy = new ListNode(-1);
          dummy.next = head;
          cur = head;
          // 如果tmpLen小于总的长度,说明还没遍历结束
          while(tmpLen < sumLen) {
            tmpLen++;
            //当tmpLen等于长度,说明当前节点已经是最后一个节点,将head节点赋值成当前节点的下一个。
            // 将当前节点的下一个赋值成null。然后跳出循环。
            if(tmpLen == sumLen) {
              head = cur.next;
              cur.next = null;
              break;
            }
            cur = cur.next;
          }
          //将节点加入数组
          list.add(dummy.next);
        }
        return list;
      }
    }
    
    0 赞同 0 条回复
  • Gg 普通 2022年10月24日 下午10:44
    public List<ListNode> getThreeListNode(ListNode head){
            ListNode p1=head;
            ListNode p2=head.next;
            ListNode p3=head.next.next;
    
            //没有足够的三个节点形成环形链表
            if(p1==p2||p1==p3) {
                return null;
            }
            while(p3.next!=head){
                p1=p1.next;
                p2=p2.next.next;
                p3=p3.next.next.next;
            }
            ArrayList<ListNode> list = new ArrayList<>();
            list.add(p1);
            list.add(p2);
            return list;
    
        }
    
    0 赞同 0 条回复
  • 波波_1936 普通 2022年10月24日 下午10:10
    /**
         * 环形链表平分
         *
         * @param head
         * @return
         */
        public List<ListNode> getThreeListNode(ListNode head) {
            List<ListNode> res = new ArrayList<>();
            if (head == null) return res;
            //先找出环 断开,再平分
            ListNode fast = head;
            ListNode slow = head;
    
            while (fast.next != null) {
                slow = slow.next;
                fast = fast.next.next;
                if (slow.val == fast.val) {
                    //找到环  slow 是断开环的最后一个节点 ,
                    // 下一个节点就是重复的节点了,从此处断开
                    slow.next = null;
                    break;
                }
            }
            ListNode node1 = new ListNode(-1);
            ListNode node2 = new ListNode(-1);
            ListNode node3 = new ListNode(-1);
            ListNode cu1 = node1, cu2 = node2, cu3 = node3;
    
            //分割方式1:分段分割 1,2,3,4,5,6=>(1,2)(3,4)(5,6)ListNode
    
            /**
            ListNode count = head;
            int size = 0;
            while (count != null) {
                size++;
                count = count.next;
            }
            int step = 3;
            int perCount = size / 3;
            ListNode cut = head;
            while (step > 0) {
                int index = perCount;
                while (index > 0) {
                    if (step == 3) {
                        cu1.next = cut;
                        cu1 = cu1.next;
                        cut = cut.next;
                    }
                    if (cu1 != null) {
                        cu1.next = null;
                    }
                    if (step == 2) {
                        cu2.next = cut;
                        cu2 = cu2.next;
                        if (cut != null) {
                            cut = cut.next;
                        }
                    }
                    if (cu2 != null) {
                        cu2.next = null;
                    }
                    if (step == 1) {
                        cu3.next = cut;
                        cu3 = cu3.next;
                        if (cut != null) {
                            cut = cut.next;
                        }
                    }
                    if (cu3 != null) {
                        cu3.next = null;
                    }
                    index--;
                }
                step--;
            }
            if (cu1 != null && cut != null) {
                //平分不均匀的剩下的给第一个
                cu1.next = cut;
            }
            res.add(node1.next);
            res.add(node2.next);
            res.add(node3.next);
    
            **/
    
            //分割方式2: 循环分割 1,2,3,4,5,6=>(1,4)(2,5)(3,6)
            ListNode pre = head;
            while (pre != null) {
                cu1.next = pre;
                cu1 = cu1.next;
                pre = pre.next;
    
                cu2.next = pre;
                cu2 = cu2.next;
                if (pre != null) {
                    pre = pre.next;
                }
                cu3.next = pre;
                cu3 = cu3.next;
                if (pre != null) {
                    pre = pre.next;
                }
            }
            res.add(node1.next);
            res.add(node2.next);
            res.add(node3.next);
            return res;
        }
    
    
    

    时间复杂度O(n)
    空间复杂度O(1)
    //平分链表那块使用了两种平分方法 一种是一段一段 一种是挨个一个一个的,这块写的不是很好,请各位大佬review

    0 赞同 0 条回复
  • 🚲南下 普通 2022年10月24日 下午10:00
    class Solution { //拆分
    public:
        ListNode* splitToThree(ListNode* head) {
            if(head==nullptr) return nullptr;
            ListNode* cur = head;
            ListNode* f = new ListNode(-1);
            ListNode* s = new ListNode(-1);
            ListNode* t = new ListNode(-1);
    
            ListNode* cur1 = f;
            ListNode* cur2 = s;
            ListNode* cur3 = t;
    
            cur1->next = new ListNode(head->val);
            cur1 = cur1->next;
            int count = 1;
            cur = head->next;
            while(cur!=nullptr){
                if(count%3==0){
                    cur1-next = new ListNode(cur->val);
                    cur1 = cur1->next;
                }else if(count%3 = 1){
                    cur2->next = new ListNode(cur->val);
                    cur2 = cur2->next;
                }else{
                    cur3->next = new ListNode(cur->val);
                    cur3 = cur3->next;
                }
                count++;
                cur = cur->next;
            }
            return fi->next,f2->next,f3->next;
        }
    };
    
    0 赞同 0 条回复
  • So 普通 2022年10月24日 下午9:18

    节点个数是3的倍数

    public List<ListNode> getThreeListNode(ListNode head) {
            ListNode p1 = head;
            ListNode p2 = head.next;
            ListNode p3 = head.next.next;
            if (p1 == p2 || p1 == p3) return null;
            while (p3.next != head) {
                p1 = p1.next;
                p2 = p2.next.next;
                p3 = p3.next.next.next;
            }
            List<ListNode> list;
            list.add(p1);
            list.add(p2);
            list.add(p3);
            return list;
        }
    
    0 赞同 0 条回复
  • 绍熙 普通 2022年10月24日 下午9:16

    思路:用3个指针,第一个每次next一次,第二个两次,第三个三次。
    当第三个到达链表尾时,第一个正好在1/3处,第二个在2/3处

    public List<ListNode> getThreeListNode(ListNode head){
            ListNode p1=head;
            ListNode p2=head.next;
            ListNode p3=head.next.next;
    
            if(p1==p2||p1==p3) return null;//没有足够的三个节点形成环形链表
    
            while(p3.next!=head){
                p1=p1.next;
                p2=p2.next.next;
                p3=p3.next.next.next;
            }
            //此时,当p3运行到head的上一个节点
            //三个就形成了三等分的链表
    
    }
    
    0 赞同 0 条回复
  • 訁訁訁訁訁 普通 2022年10月24日 下午9:02

    //环形链表分成三等份。
    public class Solution6 {
    public static class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
    val = x;
    }
    }

    public static void main(String[] args) {
        ListNode l1 = new ListNode(1);
        ListNode cur = l1;
        for(int i = 0;i <= 10;i++){
            cur.next = new ListNode(i);
            cur = cur.next;
        }
        cur.next = l1;
        ListNode listNode = new Solution6().splitToThree(l1);
        System.out.print(l1.val+"->");
        cur = l1.next;
        while(cur != l1){
            if(cur.next == l1) System.out.print(cur.val);
            else
            System.out.print(cur.val + "->");
            cur = cur.next;
        }
        System.out.println();
        while(listNode != null){
            if(listNode.next != null)
            System.out.print(listNode.val + "->");
            else
                System.out.println(listNode.val);
            listNode = listNode.next;
        }
    }
    /*
    1->0->1->2->3->4->5->6->7->8->9->10
    l1: 1->2->5->8
     */
    public  ListNode splitToThree(ListNode head){
        if(head == null) return null;
        ListNode cur = head;
        int len = 0;
        ListNode fi = new ListNode(0);//第一条链表的头结点
        ListNode se = new ListNode(0);//第二条填表的头节点
        ListNode th = new ListNode(0);//第三条链表的头结点
        ListNode cur1 = fi;
        ListNode cur2 = se;
        ListNode cur3 = th;
        cur1.next =  new ListNode(head.val);
        cur1 = cur1.next;
        int count = 1;
        cur = head.next;
        while(cur != head){
            if(count % 3 == 0){
                cur1.next = new ListNode((cur.val));
                cur1 = cur1.next;
            }else if(count % 3 == 1){
                cur2.next = new ListNode(cur.val);
                cur2 = cur2.next;
            }else{
                cur3.next = new ListNode((cur.val));
                cur3 = cur3.next;
            }
            count++;
            cur = cur.next;
        }
        return fi.next;//返回第一条测试
    }
    

    }

    0 赞同 0 条回复
  • Y7n05h 普通 2022年10月24日 下午7:35

    环形链表是尾节点的 next 指向 head 的链表。可以通过检测 next head 判断链表结尾。因此本题可转化为普通链表3等分的题目。

    对于普通的链表3等分,我们可参考快慢指针取链表中点的方法。
    我们只讨论节点个数恰好为 3 的倍数的情况,其他情况无非是边界处理的问题。

    我们使用 快、中、慢 三个指针完成对链表的遍历。
    快指针每次遍历3个节点,中指针每次遍历2个节点,慢指针每次遍历一个节点。
    由速度关系可知,当快指针遍历至头节点(注意这是环形链表!!!)时,可知中指针在链表 2/3,慢指针在 1/3 处。
    时间复杂度:O(n)
    空间复杂度:O(1)

    方法二:
    建立 HashMap<int,Node*> 的哈希表,
    计数,计算切割 1/3 和 2/3 的位置,分割链表。
    时间复杂度 O(n)
    空间复杂度 O(n)

    P.S. 我要吐槽一下,我对「方法一比方法二更好」持怀疑态度。毕竟链表可是离散存储的结构!反复遍历链表造成的 Cache Missing 怎么说啊。很难说快指针遍历完一个节点后,等慢指针和中指针再次遍历到这个节点的时候这个节点还在不在 L1/L2/L3 Cache 里。要是这个节点已经不在 Cache 里了,那又要触发一次 Cache Missing 了,这种方法要是造成缓存行抖动,那和消耗的 O(n) 的空间来存哈希表的方案二就没任何的可比性了。

    0 赞同 0 条回复
  • just 普通 2022年10月24日 下午6:22

    可以先遍历一遍环形链表,然后求出长度,然后确定每一段的长度,再次遍历链表,进行三等分
    或者直接遍历一次链表,每次拆下一个节点将其加入结果中,这个时间会更快一下。

    0 赞同 0 条回复

# 回答此问题

后才能回答