Partitioning a linked list

你说的曾经没有我的故事 提交于 2019-12-12 10:16:14

问题


I am trying to solve this algorithmic problem based on linked list data structure. The question is as follows:

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions.

For example,

Given 1->4->3->2->5->2 and x = 3, return 1->2->2->4->3->5.

My solution to the problem is:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode partition(ListNode head, int x) {
        if(head == null) return null;
        ListNode headNode = new ListNode(-1);
        headNode.next = head;

        ListNode tail = head;
        while(tail.next!=null){
            tail = tail.next;
        }
        ListNode actualTail = tail;
        ListNode current = headNode;
        while(current!=actualTail && current.next!=actualTail){
            if(current.next.val >= x && current.next!=tail){
                System.out.println("Moving "+current.next.val+" to end of list, ahead of "+tail.val);
                ListNode temp = current.next;
                current.next = current.next.next;
                tail.next = temp;
                tail = tail.next;
                tail.next = null;
            }else{
                current = current.next;    
            }

        }
        return headNode.next;
    }
}

While some test cases work fine with this code such as the one mentioned above, there are a set of test cases that fail, in that I am unable to maintain the original relative ordering of the nodes in the list.

For example: list = [1->2] x = 0

My result: [2,1]

Expected: [1,2]

Any help would be greatly appreciated.


回答1:


I think you can do it in a simpler way:

  • Keep 2 lists, one for lower nodes and other for greater nodes.
  • Iterate the list adding the nodes to the corresponding list.
  • Concatenate the lower list with greater list

Something like this:

public ListNode Partition(ListNode head, int x)
{
    ListNode lowerHead = null, lowerTail = null;              //Head and Tail of lower list
    ListNode greaterHead = null, greaterTail = null;          //Head and Tail of greater list

    ListNode current = head;

    while (current != null)
    {
        if (current.val < x)
        {
            if (lowerHead == null) lowerHead = current;      //If is the first node in the list
            if (lowerTail == null) lowerTail = current;      //set the head an tail to the same value
            else lowerTail = lowerTail.next = current;       //Otherwise, add the node and update the tail
        }
        else
        {
            if (greaterHead == null) greaterHead = current;  //If is the first node in the list
            if (greaterTail == null) greaterTail = current;  //set the head an tail to the same value
            else greaterTail = greaterTail.next = current;   //Otherwise, add the node and update the tail
        }

        current = current.next;
    }

    if (greaterHead != null)
        greaterTail.next = null;

    if (lowerHead == null) return greaterHead;
    else
    {
        lowerTail.next = greaterHead;
        return lowerHead;
    }
} 

Order is preserved since nodes are added as they appear in the original list




回答2:


It can be done in place, in O(N) time O(1) space. Just keep track of the immediate preceding node, before the first node, that is greater than or equal to the X.

This node acts as the boundary between the nodes that are less than X and nodes that are greater than or equal to X.

Refer the code along with inline comments.

    class Solution {
    public ListNode partition(ListNode head, int x) {
        // Assume that list has at least one instance of X and x = 3

        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode prev = dummy;
        ListNode curr = head;

        // Keeps track of the preceding node, before the first value greater than or equal to x.
        ListNode large = null;
        // Tracks weather the first node greater than or equal to x has been found.
        boolean isFirstLargeFound = false;

        while(curr != null) {
            if (curr.val >= x) {
                if (!isFirstLargeFound) {
                    large = prev;
                    isFirstLargeFound = true;    
                }
            } else if (isFirstLargeFound) {
                // If the current value is less than x and the first larger value has
                // been found, we need to swap the nodes.
                //
                // Consider the example: 1->4->0->3->2->5, the curr node is at value 0.
                // At this point of time the first larger value i.e. 4 has been already
                // found, hence we have to move the Node with value 0 to a place before 
                // the node with value 4.
                //
                // Before: 1->4->0->3->2->5
                // After: 1->0->4->3->2->5
                ListNode temp = large.next;
                prev.next = curr.next;
                large.next = curr;
                // Ensures that the first element that is >=X, is always next of large node.
                curr.next = temp;
                large = large.next;
            }

            prev = curr;
            curr = curr.next;
        }
        return dummy.next;
    }
}



回答3:


I solved it in Python and works fine.

current = runner = ll.head
while runner:
    if runner.value < part:
        temp = current.value
        current.value = runner.value
        runner.value = temp

        current = current.next
        runner = runner.next
    else:
        runner = runner.next


来源:https://stackoverflow.com/questions/37076648/partitioning-a-linked-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!