第二十题:链表的荷兰国旗问题(Java)

题目要求

将一个链表,按照某一个标准,小于该标准的放置在链表的前面,等于的放置在中间,大于的放置在后面,不要求稳定性。

实现思路:

在前面第十五题:荷兰国旗问题中,我们已经解决了类似的问题,我们实现的思路是,遍历整个链表,然后将每一个节点放置到数组中去,然后使用荷兰国旗问题的思路来解决,在数组荷兰国旗话之后,在遍历数组,将数组转为链表,在笔试中,我们应该使用这样的解决方案。

代码实现:

package com.isea.brush;

/**
 * 将一个链表按照与pivot的关系,分成小于,等于,大于三部分
 * 实现思路:将链表遍历一遍,放入到Node类型的数组中,按照解决荷兰国旗的问题来解决
 * 最后将数组重新组建成为一个链表,返回
 */
public class SmallEqualBig {
    public static class Node {
        private int data;
        private Node next;

        public Node(int value) {
            this.data = value;
        }
    }

    public static Node smallEqualBig(Node head, int pivot) {
        if (head == null) {
            return head;
        }
        Node cur = head;
        int i = 0;
        while (cur != null) {
            i++;
            cur = cur.next;
        }

        Node[] nodeArr = new Node[i];
        cur = head;
        for (i = 0; i < nodeArr.length; i++) {
            nodeArr[i] = cur;
            cur = cur.next;
        }

        arrPartition(nodeArr, pivot);

        for (i = 1; i < nodeArr.length; i++) {
            nodeArr[i - 1].next = nodeArr[i];
        }
        nodeArr[i - 1].next = null;
        return nodeArr[0];

    }

    private static void arrPartition(Node[] nodeArr, int pivot) {
        int less = -1;
        int more = nodeArr.length;
        int index = 0;
        while (index < more) {
            if (nodeArr[index].data < pivot) {
                swap(nodeArr,  ++less, index++);
            } else if (nodeArr[index].data > pivot) {
                swap(nodeArr, --more, index);
            } else {
                index++;
            }
        }
    }

    private static void swap(Node[] arr, int i, int j) {
/*        arr[i].data = arr[i].data ^ arr[j].data;
        arr[j].data = arr[i].data ^ arr[j].data;
        arr[i].data = arr[i].data ^ arr[j].data;*/
        int tem = arr[i].data;
        arr[i].data =  arr[j].data;
        arr[j].data = tem;
    }

    public static void printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.data + " ");
            node = node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Node head1 = new Node(7);
        head1.next = new Node(9);
        head1.next.next = new Node(1);
        head1.next.next.next = new Node(8);
        head1.next.next.next.next = new Node(5);
        head1.next.next.next.next.next = new Node(2);
        head1.next.next.next.next.next.next = new Node(5);
        printLinkedList(head1);
        // head1 = listPartition1(head1, 4);
        head1 = smallEqualBig(head1, 5);
        printLinkedList(head1);

    }
}

这里,我们对于问题进一步升级:

保持原来链表中元素的稳定性,不能打破原来的数据的顺序,比如:9->0->4->5->1 ,排序的标准是pivot=3,输出之后是

0->1->9->4->5。另外要求:假如链表的长度是N,时间复杂度是O(N),额外空间复杂度是O(1)

代码实现:

package com.isea.brush;

/**
 * 将一个链表按照与pivot的关系,分成小于,等于,大于三部分,要求时间复杂度是O(N),额外空间复杂度是O(1),做到稳定性
 * 实现思路:第一次遍历链表,找到链表中第一个小于,等于,大于pivot的元素,分别赋值给less,equal,more
 * 第二次遍历链表,将小于pivot的元素接在less链表上,等于pivot的元素接在equal链表上,大于pivot的元素接在more链表上
 * 最后在将less,equal,more链表合并,返回头节点。下面的代码中将两次循环放在了一起。
 */
public class SmallEqualBig {
    public static class Node {
        private int data;
        private Node next;

        public Node(int value) {
            this.data = value;
        }
    }

    public static Node smallEqualBig(Node head, int pivot) {
        Node lessHead = null;
        Node lessEnd = null;
        Node equalHead = null;
        Node equalEnd = null;
        Node moreHead = null;
        Node moreEnd = null;
        Node next = null; // save the next node
        // 遍历链表,将链表分发到三个子链表中
        while (head != null) {
            next = head.next;
            head.next = null;
            if (head.data < pivot) {
                if (lessHead == null) {
                    lessHead = head;
                    lessEnd = head;
                } else {
                    lessEnd.next = head;
                    lessEnd = head;
                }
            } else if (head.data == pivot) {
                if (equalHead == null) {
                    equalHead = head;
                    equalEnd = head;
                } else {
                    equalEnd.next = head;
                    equalEnd = head;
                }
            } else {
                if (moreHead == null) {
                    moreHead = head;
                    moreEnd = head;
                } else {
                    moreEnd.next = head;
                    moreEnd = head;
                }
            }
            head = next;
        }
        // small and equal reconnected
        if (lessEnd != null) {
            lessEnd.next = equalHead;
            equalEnd = equalHead == null ? lessEnd : equalEnd;
        }

        // all reconnected
        if (equalEnd != null) {
            equalEnd.next = moreHead;
        }
        return lessHead != null ? lessHead : equalHead != null ? equalHead : moreHead;
    }

    public static void printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.data + " ");
            node = node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Node head1 = new Node(7);
        head1.next = new Node(9);
        head1.next.next = new Node(1);
        head1.next.next.next = new Node(8);
        head1.next.next.next.next = new Node(5);
        head1.next.next.next.next.next = new Node(2);
        head1.next.next.next.next.next.next = new Node(5);
        printLinkedList(head1);
        // head1 = listPartition1(head1, 4);
        head1 = smallEqualBig(head1, 5);
        printLinkedList(head1);
        /**
         * Linked List: 7 9 1 8 5 2 5 
         * Linked List: 1 2 5 5 7 9 8 
         */
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值