【链表专题】百度真题:环形链表分成三等份

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

要求:

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

参考代码

下面是一个完整的代码,包括测试,你们可以直接粘贴运行。

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 getThreeListNode(ListNode head){
        //只有一个节点
        if(head.next==head){
            List list = new ArrayList<>();
            head.next = null;//防止返回一个环形链表
            list.add(head);
            list.add(null);
            list.add(null);
            return list;
        }
        // 只有两个节点
        if(head.next.next == head){
            List 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 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 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;
        }
    }
}

共以下 18 个回答

  • YULONG 永久会员 2024年11月30日 下午2:58
    public class SplitLinkedList {
        /**
         * 获取链表长度cnt
         * 1. 如果链表长度为1返回[l1, null, null]
         * 2. 如果链表长度为2返回[l1, l2, null]
         * 3. 如果链表长度>=3返回[l1, l2, l3],
         *    其中l1.length == cnt / 3, l2.length == cnt / 3,  l3.length == (cnt / 3 + cnt % 3)
         *    依次按数量截取子链表即可
         * 时间复杂度 O(N)
         * @param node
         * @return
         */
    
        public static List split(ListNode node){
            if (node == null){
                return null;
            }
    
            List res = new ArrayList<>(3);
            if (node.next == node){
                node.next = null;
                res.add(node);
                res.add(null);
                res.add(null);
                return res;
            }
    
            if (node.next.next == node){
                ListNode second = node.next;
                second.next = null;
                node.next = null;
                res.add(node);
                res.add(second);
                res.add(null);
                return res;
            }
    
            int cnt = 1;
            ListNode p = node.next;
            while (p != node){
                p = p.next;
                cnt++;
            }
    
    
            List subCnt = new ArrayList<>();
            int a = cnt / 3;
            int b = cnt % 3;
            subCnt.add(a);
            subCnt.add(a);
            subCnt.add(a + b);
    
            ListNode dummy = new ListNode(-1, node);
            for (Integer sCnt: subCnt){
                ListNode e = dummy;
                for (int i = 0; i < sCnt; i++){
                    e = e.next;
                }
                ListNode nxt = e.next;
                e.next = null;
                res.add(dummy.next);
                dummy.next = nxt;
            }
    
            return res;
    
        }
    
        public static void printListNode(ListNode node){
            List ans = new ArrayList<>();
            while (node != null){
                ans.add(node.val);
                node = node.next;
            }
            System.out.println(ans);
        }
    
        static class ListNode{
            int val;
            ListNode next;
            public ListNode(int val){
                this.val = val;
            }
    
            public ListNode(int val, ListNode next){
                this.val = val;
                this.next = next;
            }
        }
    
        public static void main(String[] args) {
    //        int len = 17;
            int len = 2;
            ListNode head = new ListNode(1);
            ListNode p = head;
            for (int i = 2; i <= len; i++) {
                p.next = new ListNode(i);
                p = p.next;
            }
            p.next = head;
    
            List res = split(head);
            for (ListNode node: res) {
                printListNode(node);
            }
    
        }
    
    }
    
    0 赞同 0 条回复
  • 陆狗陆狗 普通 2024年11月28日 上午12:35
    /**
         * 三等分
         * @param head 头结点
         * @return
         */
        public static List splitList(ListNode head) {
            List result = new ArrayList<>();
            // 没有节点
            if (head == null) {
                return result;
            }
            // 只有一个节点 A->A
            ListNode l1 = new ListNode(0);
            ListNode l2 = new ListNode(0);
            ListNode l3 = new ListNode(0);
            if (head.next == head) {
                // 防止成环,无法进行打印
                l1.next = head;
                head.next = null;
    
                l2.next = null;
                l3.next = null;
    
            } else if (head.next.next == head) {
                // 只有两个节点 A->B->A
                // 拆分节点
                head.next.next = null;
                l2.next = head.next;
    
                head.next = null;
                l1.next = head;
    
                l3.next = null;
            } else {
                // 2个节点以上了
                // 获取节点长度(初始长度为1)
                ListNode tmpt = head.next;
                int length = 1;
                while (tmpt != head) {
                    length++;
                    tmpt = tmpt.next;
                }
                // 开始进行拆分(多余的都给第三个联表)
                int everyLength = length / 3;
                int allocateLength = 0;
                while (allocateLength < length) {
                    if (allocateLength == 0) {
                        // 分配给l1,分配之后其余情况就空转即可
                        l1.next = tmpt;
                    } else if (allocateLength == everyLength) {
                        // 分配给l2
                        l2.next = tmpt;
                    } else if (allocateLength == everyLength * 2) {
                        // 分配给l3
                        l3.next = tmpt;
                    }
                    if (everyLength - allocateLength == 1 || everyLength * 2 - allocateLength == 1 || length - allocateLength == 1) {
                        // 尾节点要置空
                        ListNode pre = tmpt;
                        tmpt = tmpt.next;
                        pre.next = null;
                    } else {
                        // 【错误点:不需要处理的其他情形也需要迭代】
                        tmpt = tmpt.next;
                    }
                    allocateLength++;
                }
            }
            // 添加节点
            result.add(l1.next);
            result.add(l2.next);
            result.add(l3.next);
    
            return result;
        }
    

    测试demo

    public static void main(String[] args) {
            ListNode source = ListNodeUtil.of(1, 2, 3, 4, 5, 6);
            ListNode tmpt = source;
            while (tmpt.next != null) {
                tmpt = tmpt.next;
            }
            tmpt.next = source;
    
    
    <pre><code>    List<ListNode> listNodes = splitList(source);
        listNodes.forEach(ListNodeUtil::print);
    }
    </code></pre>
    
    
    

    结果:
    打印开始----------------------》
    1 -> 2
    打印结束----------------------》
    打印开始----------------------》
    3 -> 4
    打印结束----------------------》
    打印开始----------------------》
    5 -> 6
    打印结束----------------------》

    0 赞同 0 条回复
  • hjx 普通 2024年11月26日 下午8:17

    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 getThreeListNode(ListNode head){
    //只有一个节点
    if(head.nexthead){
    List list = new ArrayList<>();
    head.next = null;//防止返回一个环形链表
    list.add(head);
    list.add(null);
    list.add(null);
    return list;
    }
    // 只有两个节点
    if(head.next.next
    head){
    List 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 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 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;
        }
    }
    

    }

    0 赞同 0 条回复
  • Pendulumpal 普通 2024年11月25日 下午4:00

    用三个指针遍历链表,拆分环

    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);
            ListNode l6 = new ListNode(6);
            ListNode l7 = new ListNode(7);
            ListNode l8 = new ListNode(8);
            ListNode l9 = new ListNode(9);
            ListNode l10 = new ListNode(10);
            ListNode l11 = new ListNode(11);
            l1.next = l2;
            l2.next = l3;
            l3.next = l4;
            l4.next = l5;
            l5.next = l6;
            l6.next = l7;
            l7.next = l8;
            l8.next = l9;
            l9.next = l10;
            l10.next = l11;
            l11.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;
        }
    
        public static class ListNode{
            int val;
            ListNode next;
            public ListNode(int x){
                this.val = x;
            }
        }
    }
    
    0 赞同 0 条回复
  • 生活在经验里 普通 2024年11月25日 下午12:39
    type ListNode struct {
        val  int
        next *ListNode
    }
    
    // go代码实现,包含测试用例
    //思路:分别找到3个链表的尾节点,再进行分割
    func getThreeListNode(head *ListNode) []*ListNode {
        if head.next == head {
            head.next = nil
            return []*ListNode{head, nil, nil}
        }
    
        if head.next.next == head {
            temp := head.next
            temp.next = nil
            head.next = nil
            return []*ListNode{head, temp, nil}
        }
    
        l1 := head
        l2 := head.next
        l3 := head.next.next
        count := 1
        temp := head
    
        for head.next != temp {
            count++
            head = head.next
        }
    
        var list []*ListNode
        if count%3 == 0 {
            for l3.next != temp {
                l3 = l3.next.next.next
                l2 = l2.next.next
                l1 = l1.next
            }
            a1 := l3.next
            a2 := l1.next
            a3 := l2.next
            l1.next = nil
            l2.next = nil
            l3.next = nil
            list = append(list, a1, a2, a3)
        } else {
            amount := int(float64(count)/3.0 + 0.5) // 不完全均等分配节点时, 前2个链表应包含的节点数
            k := amount - 1 // 分割点索引位置
            for k != 0 {
                l2 = l2.next.next
                l1 = l1.next
                k--
            }
            for l3.next != temp {
                l3 = l3.next
            }
            a1 := l3.next
            a2 := l2.next
            a3 := l1.next
            l1.next = nil
            l2.next = nil
            l3.next = nil
            list = append(list, a1, a3, a2)
        }
    
        return list
    }
    
    func main() {
        // 1个节点
        l1 := &ListNode{val: 0}
        l1.next = l1 // Creating a cycle for demonstration
    
        // 2个节点
        ll1 := &ListNode{val: 0}
        ll2 := &ListNode{val: 1}
        ll1.next = ll2
        ll2.next = ll1 // Creating a cycle for demonstration
    
        // 3的倍数节点
        lll1 := &ListNode{val: 0}
        lll2 := &ListNode{val: 1}
        lll3 := &ListNode{val: 2}
        lll4 := &ListNode{val: 3}
        lll5 := &ListNode{val: 4}
        lll6 := &ListNode{val: 5}
        lll1.next = lll2
        lll2.next = lll3
        lll3.next = lll4
        lll4.next = lll5
        lll5.next = lll6
        lll6.next = lll1 // Creating a cycle for demonstration
    
        // 非3倍数节点
        llll1 := &ListNode{val: 0}
        llll2 := &ListNode{val: 1}
        llll3 := &ListNode{val: 2}
        llll4 := &ListNode{val: 3}
        llll5 := &ListNode{val: 4}
        llll6 := &ListNode{val: 5}
        llll7 := &ListNode{val: 6}
        llll1.next = llll2
        llll2.next = llll3
        llll3.next = llll4
        llll4.next = llll5
        llll5.next = llll6
        llll6.next = llll7
        llll7.next = llll1 // Creating a cycle for demonstration
    
        //threeListNode := getThreeListNode(l1)
        //threeListNode := getThreeListNode(ll1)
        //threeListNode := getThreeListNode(lll1)
        threeListNode := getThreeListNode(llll1)
    
        // 打印
        for i, head := range threeListNode {
            fmt.Printf("\n链表%d\n", i+1)
            for head != nil {
                fmt.Printf("%d ", head.val)
                head = head.next
            }
        }
    }
    
    0 赞同 0 条回复
  • Poetry and distance 永久会员 2024年11月25日 上午1:01
    思路:分别对空环,一个节点的环,二个节点的环,三个以及以上的环,三个以及以上的又分为 能不能被3整除的,能被3整除的刚刚好,不能被3整除的,用四舍五入判断,如果2/3有那么,前面二个拆分的环拥有相同的节点数,让第三个拆分的环少一个节点,如果1/3则让最后的那个节点多一个节点
    /**
     * Definition for singly-linked list.
     * class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) {
     *         val = x;
     *         next = null;
     *     }
     * }
     */
    public class Solution {
        public int getCount(ListNode head){
            int res=0;
            ListNode temp=head;
            while(temp!=null){
                res++;
                temp=temp.next;
            }
            return res;
        }
        public List getThreeListNode(ListNode head) {
            List res=new ArrayList<>();
            if(head==null)
                return res;
            else if(head.next==head){
                head.next=null;
                res.add(head);
                res.add(null);
                res.add(null);
            }
            else if(head.next.next==head){
                head.next.next=null;
                ListNode temp=head.next;
                head.next=null;
                res.add(head);
                res.add(temp);
                res.add(null);
            }
            else{
                int count=getCount(head);
                if(count%3==0){
                    ListNode l1=head;
                    ListNode l2=head.next;
                    ListNode l3=head.next.next;
                    while(l3!=head){
                        l1=l1.next;
                        l2=l2.next.next;
                        l3=l3.next.next.next;
                    }
                    ListNode temp1=l1.next;
                    ListNode temp2=l2.next;
                    ListNode temp3=l3.next;
                    l1.next=null;
                    l2.next=null;
                    l3.next=null
                    res.add(temp3);
                    res.add(temp1);
                    res.add(temp2);
                }
                else{
                    ListNode l1=head;
                    ListNode l2=head.next;
                    ListNode l3=head.next.next;
                    int step=(int)Math.round(count*1.0/3.0)-1;
                    while(step>0){
                        l1=l1.next;
                        l2=l2.next.next;
                        step--;
                    }
                    while(l3.next!=head){
                        l3=l3.next;
                    }
                    ListNode temp1=l1.next;
                    ListNode temp2=l2.next;
                    ListNode temp3=l3.next;
                    l1.next=null;
                    l2.next=null;
                    l3.next=null
                    res.add(temp3);
                    res.add(temp1);
                    res.add(temp2);
                }
            }
            return res;
        }
    }
    时间复杂度:O(n)
    空间复杂度:O(1)
    
    0 赞同 0 条回复
  • Renasc 普通 2024年11月23日 下午8:27

    待理解…

    import java.util.ArrayList;
    import java.util.List;
    
    public class GetThreeListNode {
        // 核心方法
        public static List<ListNode> getThreeListNode(ListNode head) {
            List<ListNode> result = new ArrayList<>();
            if (head == null) {
                result.add(null);
                result.add(null);
                result.add(null);
                return result;
            }
    
            // 统计节点个数
            int count = 1;
            ListNode temp = head;
            while (temp.next != head) {
                count++;
                temp = temp.next;
            }
    
            // 计算每段的大小
            int size1 = count / 3;
            int size2 = count / 3;
            int size3 = count - size1 - size2;
    
            // 三等分链表
            ListNode part1 = splitList(head, size1);
            ListNode part2 = splitList(part1, size2);
    
            result.add(head); // 第一部分的起点
            result.add(part1); // 第二部分的起点
            result.add(part2); // 第三部分的起点
    
            return result;
        }
    
        // 辅助方法:分割链表,返回新部分的起点
        private static ListNode splitList(ListNode head, int size) {
            if (head == null || size == 0) return head;
    
            ListNode temp = head;
            for (int i = 1; i < size; i++) {
                temp = temp.next;
            }
    
            ListNode nextHead = temp.next; // 新部分的起点
            temp.next = null;              // 断开当前链表
    
            return nextHead;
        }
    
        // ListNode 内部类
        public static class ListNode {
            int val;
            ListNode next;
    
            public ListNode(int x) {
                this.val = x;
            }
        }
    }
    
    0 赞同 0 条回复
  • Xiang. 永久会员 2024年11月23日 下午4:16
    
    //感觉只要在纸上画一下三指针的动态流程就会了。
    public class threeFenLinkedlist {
        public static void main(String[] args) {
       //四个结点的循环链的第三组的测试
            ListNode head1=new ListNode(1,new ListNode(2,new ListNode(3,new ListNode(4,null))));
            ListNode tmp=head1;
            while (tmp.next!=null){
                tmp=tmp.next;
            }
            tmp.next=head1;
            List res=threeFenLinkedlist.getThreeListNode(head1);
            tmp=(ListNode) res.get(2);
            while (tmp!=null){
                System.out.println(tmp.val);
                tmp=tmp.next;
            }
        }
        public static List getThreeListNode(ListNode head){
            List list=new ArrayList<>();
            //首先边界处理对于不足3个结点的环形链表
            if(head.next==head){
                head.next=null;
                list.add(head);
                list.add(null);
                list.add(null);
                return list;
            }
            else if(head.next.next==head){
                ListNode tmp=head.next;
                head.next=null;
                tmp.next=null;
                list.add(head);
                list.add(tmp);
                list.add(null);
                return list;
            }
            else {
                ListNode cur=head;
                int count=1;
                while (cur.next!=head){
                    count++;
                    cur=cur.next;
                }
                ListNode l1=head;
                ListNode l2=head.next;
                ListNode l3=head.next.next;
                //均等分和非均等分的区别就是第三组的数量,所以前两组的思路都一样
                if(count%3==0){
                    while(l3.next!=head){
                        l1=l1.next;
                        l2=l2.next.next;
                        l3=l3.next.next.next;
                    }
                }else{
                    int step=(int)(Math.round(count/3.0)-1);  //起始位置相当于已经进了一步,所以要减一。
                    while(step!=0){
                        l1=l1.next;
                        l2=l2.next.next;
                    }
                    while (l3.next!=head){
                        l3=l3.next;
                    }
    
                }
                ListNode newHead1=l3.next;
                ListNode newHead2=l1.next;
                ListNode newHead3=l2.next;
                l1.next=null;
                l2.next=null;
                l3.next=null;
                list.add(newHead1);
                list.add(newHead2);
                list.add(newHead3);
                return list;
            }
    
        }
    
    
    }
    时间复杂度O(n)
    空间复杂度O(1)
    
    0 赞同 0 条回复
  • 月下足迹 普通 2024年11月23日 下午2:41

    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; }
    }

    public ListNode[] splitCircularList(ListNode head) {
    if (head null) return new ListNode[3];
    //计算链表长度
    int n = 1;
    ListNode cur = head;
    while(cur.next != head) {
    cur = cur.next;
    n++;
    }

        //打破环形链表
        cur.next = null;
    
        //计算每段长度
        int partSize = n / 3;
        int remainder = n % 3; //多余的分配到前几段
    
        ListNode [] resurt = new ListNode[3];
        cur = head;
    
        //分割链表
        for (int i = 0; i < 3; i++) {
            resurt[i] = cur;
            int curPartSize = partSize + (i <= remainder? 1 : 0 );
            for (int j = 0; j < curPartSize; j++) {
                cur = cur.next;
            }
            ListNode nextPart = cur.next; // 保存下一段的头节点
            cur.next = null;
            cur = nextPart;
        }
        return resurt;
    }
    
    0 赞同 0 条回复
  • Kisara 普通 2024年11月23日 下午1:16

    ““java
    帅地的看不太懂,看了评论区的一个答案完全看懂了
    主要看不懂的就是那个count/3-1,现在明白就是为了尽可能均分三个链表的长度,非常感谢

    package com.sky.annotation;

    import java.util.ArrayList;
    import java.util.List;

    public class GetThreeListNode {

    public static class ListNode{
        int val;
        ListNode next;
    
    
        public ListNode(int val) {
            this.val = val;
        }
    
        public ListNode() {
        }
    }
    
    public List<ListNode> getThreeList(ListNode head){
        List<ListNode> result=new ArrayList<>();
        //统计个数
        int count=0;
        ListNode temp=head;
        while(temp.next!=head){
            count++;
            temp=temp.next;
        }
    
        //计算分割各段大小
        int size1=count/3;
        int size2=count/3;
        int size3=count-size1-size2;
        //三等分
        //返回的是切下来的新部分的起点
        //三段,一段head,一段part1,一段part2
        ListNode part1=splitlist(head,size1);
        ListNode part2=splitlist(part1,size2);
    
        result.add(head);
        result.add(part1);
        result.add(part2);
        return result;
    }
    
    //分割方法
    public ListNode splitlist(ListNode head,int size){
        if(head ==null||size==0) return head;
        ListNode p=head;
        for(int i=1;i<size;i++){
            p=p.next;
        }
        ListNode next=p.next;
        p.next=null;
        return next;
    }
    

    }

    0 赞同 0 条回复
  • Kisara 普通 2024年11月23日 下午1:16

    ““java
    帅地的看不太懂,看了评论区的一个答案完全看懂了
    主要看不懂的就是那个count/3-1,现在明白就是为了尽可能均分三个链表的长度,非常感谢

    package com.sky.annotation;

    import java.util.ArrayList;
    import java.util.List;

    public class GetThreeListNode {

    public static class ListNode{
        int val;
        ListNode next;
    
    
        public ListNode(int val) {
            this.val = val;
        }
    
        public ListNode() {
        }
    }
    
    public List<ListNode> getThreeList(ListNode head){
        List<ListNode> result=new ArrayList<>();
        //统计个数
        int count=0;
        ListNode temp=head;
        while(temp.next!=head){
            count++;
            temp=temp.next;
        }
    
        //计算分割各段大小
        int size1=count/3;
        int size2=count/3;
        int size3=count-size1-size2;
        //三等分
        //返回的是切下来的新部分的起点
        //三段,一段head,一段part1,一段part2
        ListNode part1=splitlist(head,size1);
        ListNode part2=splitlist(part1,size2);
    
        result.add(head);
        result.add(part1);
        result.add(part2);
        return result;
    }
    
    //分割方法
    public ListNode splitlist(ListNode head,int size){
        if(head ==null||size==0) return head;
        ListNode p=head;
        for(int i=1;i<size;i++){
            p=p.next;
        }
        ListNode next=p.next;
        p.next=null;
        return next;
    }
    

    }

    0 赞同 0 条回复
  • zing 普通 2024年11月23日 上午10:45

    待理解

    def split_linked_list(head):
        # Helper function to find the length of the linked list
        def get_length(node):
            length = 0
            while node:
                length += 1
                node = node.next
            return length
    
        # Get the length of the linked list
        length = get_length(head)
        part_size = length // 3  # Base size of each part
        extra = length % 3  # Remaining nodes to distribute
    
        # Initialize the result list to hold the three parts
        result = []
    
        current = head
        for i in range(3):
            part_head = current
            part_length = part_size + (1 if i < extra else 0)  # Add an extra node to the first few parts if necessary
    
            # Traverse the current part
            prev = None
            for _ in range(part_length):
                prev = current
                if current:
                    current = current.next
    
            # Detach the current part from the rest of the list
            if prev:
                prev.next = None
    
            # Add the current part to the result
            result.append(part_head)
    
        return result
    
    0 赞同 0 条回复
  • jaron 普通 2024年11月23日 上午10:29

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

    import java.util.ArrayList;
    import java.util.List;
    
    public class GetThreeListNode {
        // 核心方法
        public static List<ListNode> getThreeListNode(ListNode head) {
            List<ListNode> result = new ArrayList<>();
            if (head == null) {
                result.add(null);
                result.add(null);
                result.add(null);
                return result;
            }
    
            // 统计节点个数
            int count = 1;
            ListNode temp = head;
            while (temp.next != head) {
                count++;
                temp = temp.next;
            }
    
            // 计算每段的大小
            int size1 = count / 3;
            int size2 = count / 3;
            int size3 = count - size1 - size2;
    
            // 三等分链表
            ListNode part1 = splitList(head, size1);
            ListNode part2 = splitList(part1, size2);
    
            result.add(head); // 第一部分的起点
            result.add(part1); // 第二部分的起点
            result.add(part2); // 第三部分的起点
    
            return result;
        }
    
        // 辅助方法:分割链表,返回新部分的起点
        private static ListNode splitList(ListNode head, int size) {
            if (head == null || size == 0) return head;
    
            ListNode temp = head;
            for (int i = 1; i < size; i++) {
                temp = temp.next;
            }
    
            ListNode nextHead = temp.next; // 新部分的起点
            temp.next = null;              // 断开当前链表
    
            return nextHead;
        }
    
        // ListNode 内部类
        public static class ListNode {
            int val;
            ListNode next;
    
            public ListNode(int x) {
                this.val = x;
            }
        }
    }
    
    0 赞同 0 条回复
  • Tom Yuan 普通 2024年11月23日 上午4:59

    这个题目说实话光这么一行字很难体现全部要求 比如不能被整除的时候结果要怎么分配
    这里以7 —> (2, 2, 3)为例

    思路:计量长度,然后整除3取得前两list的长度,然后分割。思路是这样 细节也不少 需要回顾加深理解。

    def split_linked_list(head):
        # Helper function to find the length of the linked list
        def get_length(node):
            length = 0
            while node:
                length += 1
                node = node.next
            return length
    
        # Get the length of the linked list
        length = get_length(head)
        part_size = length // 3  # Base size of each part
        extra = length % 3  # Remaining nodes to distribute
    
        # Initialize the result list to hold the three parts
        result = []
    
        current = head
        for i in range(3):
            part_head = current
            part_length = part_size + (1 if i < extra else 0)  # Add an extra node to the first few parts if necessary
    
            # Traverse the current part
            prev = None
            for _ in range(part_length):
                prev = current
                if current:
                    current = current.next
    
            # Detach the current part from the rest of the list
            if prev:
                prev.next = None
    
            # Add the current part to the result
            result.append(part_head)
    
        return result
    

    time O(n) space O(n)

    0 赞同 0 条回复
  • 休一 普通 2024年11月22日 下午10:36
    class Solution {
    public:
        vector<ListNode*> splitCircularList(ListNode* head) {
            if (!head) return {}; // 空链表直接返回
    
            // Step 1: 计算链表长度
            int length = 1;
            ListNode* current = head;
            while (current->next != head) {
                current = current->next;
                length++;
            }
    
            // Step 2: 判断是否能分成三等份
            if (length % 3 != 0) {
                throw std::invalid_argument("链表长度不能被3整除,无法等分");
            }
            int partSize = length / 3;
    
            // Step 3: 分割链表
            vector<ListNode*> parts(3, nullptr);
            ListNode* prev = nullptr;
            current = head;
            for (int i = 0; i < 3; i++) {
                parts[i] = current; // 当前部分的头节点
                for (int j = 0; j < partSize; j++) {
                    prev = current;
                    current = current->next;
                }
                prev->next = nullptr; // 将当前部分形成链表,其最后一个节点为nullptr
            }
    
            return parts; // 返回三部分的头节点
        }
    };
    
    
    0 赞同 0 条回复
  • lQl 永久会员 2024年11月22日 下午10:32

    思路

    1. 计算链表长度:
      • 遍历链表,计算链表长度 n。
    2. 确定每部分的节点数:
      • 如果 n 能被 3 整除,每部分的长度是 len=n/3len = n / 3len=n/3。
      • 如果不能被 3 整除,则第三部分多出剩余的节点:
        • 第一部分长度:len1=n/3len1 = n / 3len1=n/3
        • 第二部分长度:len2=n/3len2 = n / 3len2=n/3
        • 第三部分长度:len3=n−len1−len2len3 = n – len1 – len2len3=n−len1−len2
    3. 拆分链表:
      • 遍历链表,将节点分配到三部分。
      • 每部分最后一个节点指向该部分的头节点,形成独立的环形链表。
    public class Solution {
        public ListNode[] splitCircularLinkedList(ListNode head) {
            if (head == null) {
                return new ListNode[]{null, null, null};
            }
    
            // 计算链表长度
            int length = 1;
            ListNode current = head;
            while (current.next != head) {
                current = current.next;
                length++;
            }
    
            // 确定每部分的长度
            int len1 = length / 3;
            int len2 = length / 3;
            int len3 = length - len1 - len2;
    
            // 分割链表
            ListNode[] result = new ListNode[3];
            current = head;
            ListNode prev = null;
    
            int[] lengths = {len1, len2, len3};
            for (int i = 0; i < 3; i++) {
                result[i] = current; // 每部分的头节点
                for (int j = 0; j < lengths[i]; j++) {
                    prev = current;
                    current = current.next;
                }
            }
    
            return result;
        }
    }
    

    复杂度分析

    • 时间复杂度

      遍历链表计算长度 O(n),分配节点 O(n),总复杂度为 O(n)。

    • 空间复杂度

      只使用了固定数量的指针,空间复杂度为 O(1)。

    0 赞同 0 条回复
  • WYX 普通 2024年11月22日 下午8:52

    思路: 首先统计节点数量,若小于3个 则直接返回每个结点。 若大于3个结点,则设置三个链表,cueernt1 = head; current2 = head.next; current3 = head.next.next; 每次移动 三步。 首先移动 3的整数轮,最后剩余节点一定小于3, 依次加入 current1 和 current2 即可

    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 getThreeListNode(ListNode head){
    
            // 统计链表长度 
            int count =1;
            ListNode headRem = head;
            head = head.next;
            // 统计节点个数
            while (head != headRem){
                count++;
                head = head.next;
            }
    
    
            switch(count){
                // 只有一个结点 
                case 1:{
                    List<ListNode> ans = new ArrayList<>();
                    ans.add(head);
    
                    return ans;
    
                }
                // 只有两个结点 
                case 2:{
                    List<ListNode> ans = new ArrayList<>();
                    ans.add(head, head.next);
    
                    return ans;             
    
                }
    
                // 有 三个及以上 结点 
                default:{
                    ListNode ans1 = new ListNode(-1);
                    ListNode ans2 = new ListNode(-1);
                    ListNode ans3 = new ListNode(-1);
                    ListNode current1 = head;
                    ListNode current2 = head.next;
                    ListNode current3 = head.next.next;
    
                    while(count % 3 == 0){
                        // 首先安组记录
                        ListNode temp = current1.next.next.next;
                        current1.next = ans1.next;
                        ans1.next = current1;
                        current1 = temp;
    
                        temp = current2.next.next.next;
                        current2.next = ans2.next;
                        ans2.next = current2;
                        current2 = temp;
    
                        temp = current3.next.next.next;
                        current3.next = ans3.next;
                        ans3.next = current3;
                        current3 = temp;
    
                        count -= 3;
    
                    }
    
                    // 剩余结点 小于3
                    if(count == 2){
                        current1.next = ans1.next;
                        ans1.next = current1;
    
                    }else if(count == 1){
                        current2.next = ans2.next;
                        ans2.next = current2;
                    }
    
                    List<ListNode> ans = new ArrayList<>();
                    ans.add(ans1);
                    ans.add(ans2);
                    ans.add(ans3);
    
                    return ans;
                }
    
            }
        }
    
    }
    
    0 赞同 0 条回复
  • 迢迢星野 普通 2024年11月22日 下午8:45
    class Solution {
        public List<ListNode> getThreeListNode(ListNode head, int k) {
            // 默认环形链表是其中最后一个节点的 next 指针指向链表的第一个节点,形成一个闭环。
            List<ListNode> list = new ArrayList<>();
            // 边界条件,如果环形链表的节点个数 < 3,如果是一个节点的环形链表;如果是两个节点的环形链表
            if (head == null) {
                return list;
            }
            // 1. 计算环形链表的长度
            ListNode cur = head;
            int len = 1;
            while (cur.next != head) {
                len++;
                cur = cur.next;
            }
            if (len == 1) {
                list.add(head);
                list.add(null);
                list.add(null);
                return list;
            }
            if (len == 2) {
                ListNode secondList = head.next;
                // 断开连接第二个链表和第三个链表之间的连接
                secondList.next = null;
                // 断开第一个链表和第二个链表之间的连接
                head.next = null;
                list.add(head);
                list.add(secondList);
                list.add(null);
                return list;
            }
    
            // 2. 按照每组有 len / 3 个节点进行划分(最后一个分组为剩下的所有元素),并将每一个分组的头节点添加到 list 中
            int groupSize = len / k;
            cur = head;
            // 用于记录下一组的链表的头节点
            ListNode nextGroupHead = head;
            // 先划分前 k - 1 组的链表内容,且每组的大小为 groupSize
            for (int i = 0; i < k - 1; i++) {
                ListNode groupHead = cur;
                ListNode groupTail = cur;
    
                for (int j = 0; j < groupSize; j++) {
                    groupTail = groupTail.next;
                }
    
                // [groupHead, groupTail] 之间的节点就是分割后的一组链表
                nextGroupHead = groupTail.next;
                // 断开当前链表和下一个分组链表的连接
                groupTail.next = null;
                list.add(groupHead);
                cur = nextGroupHead;
            }
            // 此时,nextGroupHead 就是第 k 个分组的链表的头节点,将其添加到 list 中
            list.add(nextGroupHead);
            return list;
        }
    }
    

    思路:本题所指的环形链表是最后一个节点的 next 指针指向链表的第一个节点,形成一个闭环的链表。从一个环形链表中 k 等份,即将该链表分解成 k 个子链表,每个子链表的长度尽可能等长,如果链表长度不能被 k 整除,最后一个子链表就会包含剩余的所有节点。
    ① 计算环形链表的长度,并对边界条件进行处理。
    ② 划分链表,计算每个子链表的长度为 groupSize = len / k,这样能够保证只有最后一个子链表长度不同,其他的子链表长度等长。先对前 k - 1 个子链表进行划分,长度为 groupSize,并将每个子链表的头节点添加至 list 中,并且每个子链表之间并不存在连接关系。nextGroupHead 最后指向的就是最后一个子链表的头节点,最后一个子链表包含剩余的所有节点,将其头节点添加至 list 中。
    时间复杂度:O(n),遍历整个链表一次,划分链表时也遍历了一次。
    空间复杂度:O(k),使用了一个 ArrayList 来存储每个子链表的头节点。

    0 赞同 0 条回复

# 回答此问题

后才能回答