• [******] 链表问题:将单向链表按某值划分成左边小、中间相等、右边大的形式


    问题描述

    普通问题:
    给定一个单向链表的头节点head,节点的值类型是整数,再给定一个整数 pivot,实现一个调整链表的函数: 使得左半部分的值都是小于pivot的节点,中间部分都是等于pivot的节点,右边部分都是大于pivot的节点,对于左半部分、中间、右半部分内部的顺序没有要求。
    进阶问题:
    【要求】 调整后所有小于pivot的节点之间的相对顺序和调整前一样
    【要求】 调整后所有等于pivot的节点之间的相对顺序和调整前一样
    【要求】 调整后所有大于pivot的节点之间的相对顺序和调整前一样
    【要求】 时间复杂度请达到O(N), 额外空间复杂度请达到O(1)。

    思路描述

    普通问题:变成数组,数组上partition(快排),然后再返回链表。 时间O(N),空间O(N)
    进阶问题:想办法弄三个链表(小于,等于,大于),然后合并链表。时间O(N),空间O(1)

    代码

    普通问题

    public class Main{
        static class Node {
            int value;
            Node next;
            public Node(int value){
                this.value = value;
            }
        }
        /**************************普通问题******************/
         /**
         * 普通问题
         * 时间复杂度是 O(N),空间复杂度是 O(N)
         * 首先遍历一遍链表,得到链表的长度,将链表元素依次放到数组中,然后利用类似于快速排序中的partition 思想进行分割
         */
        public static Node listPartition(Node head, int pivot) {
            if (head == null) {
                return head;
            }
            //计算链表的长度
            Node cur = head;
            int len = 0;
            while (cur != null) {
                len++;
                cur = cur.next;
            }
            //将链表变成数组:将链表中的每个元素依次放入到数组中
            Node[] nodeArray = new Node[len];
            int i = 0;
            cur = head;
            for (i = 0; i != nodeArray.length; i++) {
                nodeArray[i] = cur;
                cur = cur.next;
            }
            //将数组进行分区: 进行类似快速排序的partition
            arrPartition(nodeArray, pivot);
            //将数组变成链表:重新连接各个链表节点
            for (i = 1; i != len; i++) {
                nodeArray[i - 1].next = nodeArray[i];
            }
            nodeArray[i - 1].next = null;
            //返回链表的head
            return nodeArray[0];
        }
        /**进行类似快速排序的partition(补充,如果要稳定性,可以考虑插入排序,冒泡排序或者归并排序)*/
        public static void arrPartition(Node[] nodeArray, int pivot) {
            int small = -1;
            int big = nodeArray.length;
            int index = 0;
            while (index != big) {
                if (nodeArray[index].value < pivot) {//如果小于p,
                    swap(nodeArray, ++small, index++);//首先交换small和index的位置,然后各自+1,表示
                } else if (nodeArray[index].value == pivot) {
                    index++;
                } else {
                    swap(nodeArray, --big, index);
                }
            }
        }
        /**交换两个数*/
        public static void swap(Node[] nodeArray, int a, int b) {
            Node tmp = nodeArray[a];
            nodeArray[a] = nodeArray[b];
            nodeArray[b] = tmp;
        }
        
        
        /***测试**/
        public static void main(String[] args) {
            int[] array = {2,3,4,6,7,1,2,4,8,9};
            int pivot = 4;
            Node head = new Node(array[0]);
            Node cur = head;
            for (int i = 1; i < array.length; i++) {
                cur.next = new Node(array[i]);
                cur=cur.next;
            }
            head = listPartition(head, pivot);
            cur = head;
            while(cur!=null){
                System.out.print(cur.value+" ");
                cur = cur.next;
            }
        }
    }

    进阶问题

    public class Main{
        static class Node {
            int value;
            Node next;
            public Node(int value){
                this.value = value;
            }
        }
        
        /**************************进阶问题******************/
        /**
         *  进阶问题: 保证各部分内部的顺序与原来链表中各个节点的顺序相同(稳定性)
         *  时间复杂度是 O(N),空间复杂度是 O(1)
         *  考察 利用有限的几个变量来调整链表的代码实现能力。
         *  具体思路如下:
         *  1.将链表分为三部分:small,equal,big
         *                 small:1->2->null
         *                 equal:5->5->null
         *                 big:9->8->null
         *  2.将small、equal、big三个链表重新串起来
         *  3.整个过程需要特别注意对null节点的判断和处理
         */
        public static Node listPartition2(Node head, int pivot){
    
            // 将链表分为small、equal、big
            Node sH = null;//small head
            Node sT = null;//small tail
            Node eH = null;//equal head
            Node eT = null;//equal tail
            Node bH = null;//big head
            Node bT = null;//big tail
            Node next = null;// 保存下一个节点
    
            //将所有的节点依次保存在三个链表中
            while (head != null){
                // 将head节点独立出来
                next = head.next;
                head.next = null;
    
                if (head.value < pivot){
                    if (sH == null){
                        sH = head;
                    }else {
                        sT.next = head;
                    }
                    sT = head;
                }else if (head.value == pivot){
                    if (eH == null){
                        eH = head;
                    }else {
                        eT.next = head;
                    }
                    eT = head;
                }else {
                    if (bH == null){
                        bH = head;
                    }else {
                        bT.next = head;
                    }
                    bT = head;
                }
                head = next;
            }
    
            // 小的和相等的重新连接
            if (sT != null){
                sT.next = eH;
                if(eT==null){
                    eT=sT;
                }
            }
            // 和大的重新连接
            if (eT != null){
                eT.next = bH;
            }
    
            // 判断头节点是否为空
            if(sH!=null){
                return sH;
            }else{
                if(eH!=null){
                    return eH;
                }else{
                    return bH;
                }
            }
        }
        
        /***测试**/
        public static void main(String[] args) {
            int[] array = {2,3,4,6,7,1,2,4,8,9};
            int pivot = 4;
            Node head = new Node(array[0]);
            Node cur = head;
            for (int i = 1; i < array.length; i++) {
                cur.next = new Node(array[i]);
                cur=cur.next;
            }
            head = listPartition2(head, pivot);
            cur = head;
            while(cur!=null){
                System.out.print(cur.value+" ");
                cur = cur.next;
            }
        }
    }

    整合

    public class Main{
        static class Node {
            int value;
            Node next;
            public Node(int value){
                this.value = value;
            }
        }
        /**************************普通问题******************/
         /**
         * 普通问题
         * 时间复杂度是 O(N),空间复杂度是 O(N)
         * 首先遍历一遍链表,得到链表的长度,将链表元素依次放到数组中,然后利用类似于快速排序中的partition 思想进行分割
         */
        public static Node listPartition(Node head, int pivot) {
            if (head == null) {
                return head;
            }
            //计算链表的长度
            Node cur = head;
            int len = 0;
            while (cur != null) {
                len++;
                cur = cur.next;
            }
            //将链表变成数组:将链表中的每个元素依次放入到数组中
            Node[] nodeArray = new Node[len];
            int i = 0;
            cur = head;
            for (i = 0; i != nodeArray.length; i++) {
                nodeArray[i] = cur;
                cur = cur.next;
            }
            //将数组进行分区: 进行类似快速排序的partition
            arrPartition(nodeArray, pivot);
            //将数组变成链表:重新连接各个链表节点
            for (i = 1; i != len; i++) {
                nodeArray[i - 1].next = nodeArray[i];
            }
            nodeArray[i - 1].next = null;
            //返回链表的head
            return nodeArray[0];
        }
        /**进行类似快速排序的partition(补充,如果要稳定性,可以考虑插入排序,冒泡排序或者归并排序)*/
        public static void arrPartition(Node[] nodeArray, int pivot) {
            int small = -1;
            int big = nodeArray.length;
            int index = 0;
            while (index != big) {
                if (nodeArray[index].value < pivot) {//如果小于p,
                    swap(nodeArray, ++small, index++);//首先交换small和index的位置,然后各自+1,表示
                } else if (nodeArray[index].value == pivot) {
                    index++;
                } else {
                    swap(nodeArray, --big, index);
                }
            }
        }
        /**交换两个数*/
        public static void swap(Node[] nodeArray, int a, int b) {
            Node tmp = nodeArray[a];
            nodeArray[a] = nodeArray[b];
            nodeArray[b] = tmp;
        }
        /**************************进阶问题******************/
        /**
         *  进阶问题: 保证各部分内部的顺序与原来链表中各个节点的顺序相同(稳定性)
         *  时间复杂度是 O(N),空间复杂度是 O(1)
         *  考察 利用有限的几个变量来调整链表的代码实现能力。
         *  具体思路如下:
         *  1.将链表分为三部分:small,equal,big
         *                 small:1->2->null
         *                 equal:5->5->null
         *                 big:9->8->null
         *  2.将small、equal、big三个链表重新串起来
         *  3.整个过程需要特别注意对null节点的判断和处理
         */
        public static Node listPartition2(Node head, int pivot){
    
            // 将链表分为small、equal、big
            Node sH = null;//small head
            Node sT = null;//small tail
            Node eH = null;//equal head
            Node eT = null;//equal tail
            Node bH = null;//big head
            Node bT = null;//big tail
            Node next = null;// 保存下一个节点
    
            //将所有的节点依次保存在三个链表中
            while (head != null){
                // 将head节点独立出来
                next = head.next;
                head.next = null;
    
                if (head.value < pivot){
                    if (sH == null){
                        sH = head;
                    }else {
                        sT.next = head;
                    }
                    sT = head;
                }else if (head.value == pivot){
                    if (eH == null){
                        eH = head;
                    }else {
                        eT.next = head;
                    }
                    eT = head;
                }else {
                    if (bH == null){
                        bH = head;
                    }else {
                        bT.next = head;
                    }
                    bT = head;
                }
                head = next;
            }
    
            // 小的和相等的重新连接
            if (sT != null){
                sT.next = eH;
                if(eT==null){
                    eT=sT;
                }
            }
            // 和大的重新连接
            if (eT != null){
                eT.next = bH;
            }
    
            // 判断头节点是否为空
            if(sH!=null){
                return sH;
            }else{
                if(eH!=null){
                    return eH;
                }else{
                    return bH;
                }
            }
        }
        
        /***测试**/
        public static void main(String[] args) {
            int[] array = {2,3,4,6,7,1,2,4,8,9};
            int pivot = 4;
            Node head = new Node(array[0]);
            Node cur = head;
            for (int i = 1; i < array.length; i++) {
                cur.next = new Node(array[i]);
                cur=cur.next;
            }
            head = listPartition2(head, pivot);
            cur = head;
            while(cur!=null){
                System.out.print(cur.value+" ");
                cur = cur.next;
            }
        }
    }
  • 相关阅读:
    方式方法和思维技巧集合
    【NOIP/CSP2019】D2T1 Emiya 家今天的饭
    【NOIP/CSP2019】D1T2 括号树
    【网络流24】餐巾
    【NOIP2016】愤怒的小鸟
    结论和典例集合
    2020牛客寒假集训营第一场题解
    新生训练赛001题解
    The 2014 ACM-ICPC Asia Regional Contest Xi'an Site题解
    SDNU ACM-ICPC 2019 Competition For the End of Term(12-15)山师停训赛题解
  • 原文地址:https://www.cnblogs.com/haimishasha/p/11446954.html
Copyright © 2020-2023  润新知