问题
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