sorting integers with restrictions - algorithm

if we have an array of integers then how can we determine the minimum steps required to sort them(in ascending order) if the only allowed operation per step is : moving the elements to either extremes?
E.g if we have
7 8 9 11 1 10
then in 1st step one can move 11 to right end and in second step move 1 to left end to get 1 7 8 9 10 11 . Hence total steps = 2
Can bubble sort be applied here? but the worst case complexity would be O(n^2) then. So how can we do more efficiently?
Thanks.

Here is a solution that takes O(n log n) time, O(n) auxiliary space, and exactly n MoveToFront operations.
Given the input array, A, Make a second array, B, with value/index pairs, like so...
7 8 9 11 1 10 -> (7 0) (8 1) (9 2) (11 3) (1 4) (10 5)
[this step takes O(n) time and O(n) space]
then sort B in descending order of the value of each pair...
(7 0) (8 1) (9 2) (11 3) (1 4) (10 5) -> (11 3) (10 5) (9 2) (8 1) (7 0) (1 4)
[this step takes O(n log n) time]
prepare a binary search tree, T.
Now for each element in B do the following...
Let I be the index of this element.
Let V be the sum of I and the number of elements in T that are greater than I.
Do a MoveToFront operation on the Vth element of A.
Add I to T.
[Both of the operations on T take O(log n) time]
Here is this algorithm working on your example array
(11 3)
I := 3
V := 3 + 0 = 3
MoveToFront(3): 7 8 9 11 1 10 -> 11 7 8 9 1 10
T: () -> (3)
(10 5)
I := 5
V := 5 + 0 = 5
MoveToFront(5): 11 7 8 9 1 10 -> 10 11 7 8 9 1
T: (3) -> (3 5)
(9 2)
I := 2
V := 2 + 2 = 4
MoveToFront(4): 10 11 7 8 9 1 -> 9 10 11 7 8 1
T: (3 5) -> (2 3 5)
(8 1)
I := 1
V := 1 + 3 = 4
MoveToFront(4): 9 10 11 7 8 1 -> 8 9 10 11 7 1
T: (2 3 5) -> (1 2 3 5)
(7 0)
I := 0
V := 0 + 4 = 4
MoveToFront(4): 8 9 10 11 7 1 -> 7 8 9 10 11 1
T: (1 2 3 5) -> (0 1 2 3 5)
(1 4)
I := 4
V := 4 + 1 = 5
MoveToFront(5): 7 8 9 10 11 1 -> 1 7 8 9 10 11
T: (0 1 2 3 5) -> (0 1 2 3 4 5)
I imagine you can find ways to sort these arrays that use fewer than n MoveToFront/Back operations, but I don't think you can find those in less than O(n log n) time. If those operations are slow, though, then it might be worth using an algorithm that takes more time to plan so you can do fewer of those operations.

Can you clarify this problem a little bit? When you say list, do you mean a linked list or do you mean an array? If it's not a linked list, I'm a little confused by the limited operation set. If it is a linked list you can probably modify quicksort which runs in average case O(nlgn) time.

Essentially the data structure you are mentioning is a linked list. For linked lists you can use quicksort or mergesort ( O(nlogn) ).

That doesn't sound to me like a sorting problem. You need to just find how many movements you need to do, but you don't need to sort the array. I bet that could be done faster than O(n log n)
I propose such solution:
just count how many a[i] > a[i - 1]. And that will be your result.
Argumentation:
If you have a[i] > a[i-1], it means, that either a[i] or a[i-1] aren't in their places. So you can:
1) move a[i-1] to the beginning of the array
2) move a[i] to the end of the array.
Upd. You need to define which a[i] or a[i-1] are you moving, as for your example for the array: 7 8 9 11 1 10 you have two comparations, that shows what aren't in place: 11 > 1 and 11 > 10. So that is definetely a task for dynamic programming. But, it is still faster then O(n log n)

Related

Deleting element and getting it's neighbours

I have got a sequence 1 2 3 4 5 6 ... n. Now, I am given a sequence of n deletions - each deletion is a number which I want to delete. I need to respond to each deletion with two numbers - of a left and right neighbour of deleted number (-1 if any doesn't exists).
E.g. I delete 2 - I respond 1 3, then I delete 3 I respond 1 4 , I delete 6 I respond 5 -1 etc.
I want to do it fast - linear of linear-logarithmic time complexity.
What data structure should I use? I guess the key to the solution is the fact that the sequence is sorted.
A doubly-linked list will do fine.
We will store the links in two arrays, prev and next, to allow O(1) access for deletions.
First, for every element and two sentinels at the ends, link it to the previous and next integers:
init ():
for cur := 0, 1, 2, ..., n, n+1:
prev[cur] := cur-1
next[cur] := cur+1
When you delete an element cur, update the links in O(1) like this:
remove (cur):
print (num (prev[cur]), " ", num (next[cur]), newline)
prev[next[cur]] := prev[cur]
next[prev[cur]] := next[cur]
Here, the num wrapper is inserted to print -1 for the sentinels:
num (cur):
if (cur == 0) or (cur == n+1):
return -1
else:
return cur
Here's how it works:
prev next
n = 6 prev/ print 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
/next ------------------- -------------------
init () -1 0 1 2 3 4 5 6 1 2 3 4 5 6 7 8
remove (2) 1 3 1 3 -1 0 1 3 4 5 6 1 3 4 5 6 7 8
remove (3) 1 4 1 4 -1 0 1 4 5 6 1 4 5 6 7 8
remove (6) 5 7 5 -1 -1 0 1 4 5 1 4 5 7 8
remove (1) 0 4 -1 4 -1 0 4 5 4 5 7 8
remove (5) 4 7 4 -1 -1 0 4 4 7 8
remove (4) 0 7 -1 -1 -1 0 7 8
Above, the portions not used anymore are blanked out for clarity.
The respective elements of the arrays still store the values printed above them, but we no longer access them.
As Jim Mischel rightly noted (thanks!), storing the list in two arrays instead of dynamically allocating the storage is crucial to make this O(1) per deletion.
You can use a binary search tree. Deleting from it is logarithmic. If you want to remove n elements and the number of total elements is m, then the complexity of removing n elements from it will be
nlogm

How to understand how many comparisons are made in the merge algorithm?

In the merge algorithm, why is the number of comparisons is at most N, and at least N/2. I thought the comparison is at most N/2, since there would be at most calls on less(aux[j], aux[i]). Or does that mean the comparison include the statements of
if(i > mid) and else if (j > hi )? Thanks!
public static void merge(Comparable[] a, int lo, int mid, int hi)
{
for (int k = lo; k <= hi; k++)
aux[k] = a[k];
for (int k = lo; k <= hi; k++)
if(i > mid) a[k] = aux[j++];
else if (j > hi ) a[k] = aux[i++];
else if (less(aux[j], aux[i])) a[k] = aux[j++];
else a[k] = aux[i++];
}
As an example, suppose you want to merge these lists together:
1 3 5 7 9
2 4 6 8 10
This work work as follows:
1 3 5 7 9
2 4 6 8 10
^
+--------------- Compare 1 and 2, output 1
3 5 7 9
2 4 6 8 10
^
+--------------- Compare 3 and 2, output 2
3 5 7 9
4 6 8 10
^
+--------------- Compare 3 and 4, output 3
5 7 9
4 6 8 10
^
+--------------- Compare 5 and 4, output 4
5 7 9
6 8 10
^
+--------------- Compare 5 and 6, output 5
7 9
6 8 10
^
+--------------- Compare 7 and 6, output 6
7 9
8 10
^
+--------------- Compare 7 and 8, output 7
9
8 10
^
+--------------- Compare 9 and 8, output 8
9
10
^
+--------------- Compare 9 and 10, output 9
10
^
+--------------- Output 10
Here, there are 10 total elements and, as you can see, 9 comparisons were needed. The maximum number of compares that will be made is actually N - 1 for an N-element list, since if you alternate back and forth between one list having a larger value and the other having a larger value one comparison will be made per element being outputted (except for the very last one). The case where N / 2 comparisons are made is actually the best possible case; that happens only when all elements in one list are strictly smaller than all elements in the other.

Algorithm suggestion

I'm looking for the best way to accomplish the following tasks:
Given 4 non-repeatable numbers between 1 and 9.
Given 2 numbers between 1 and 6.
Adding up the two numbers (1 to 6), check to see if there is a way make that same number using the four non-repeatable numbers (1 to 9), plus you may not even have to use all four numbers.
Example:
Your four non-repeatable (1 to 9) numbers are: 2, 4, 6, and 7
Your two numbers between 1 and 6 are: 3 and 3
The total for the two numbers is 3 + 3 = 6.
Looking at the four non-repeatable (1 to 9) numbers, you can make a 6 in two different ways:
2 + 4 = 6
6 = 6
So, this example returns "yes, there is a possible solution".
How do I accomplish this task in the most efficient, cleanest way possible, algorithmic-ally.
enter code hereSince the number of elements here is 4 so we should not worry about efficiency.
Just loop over 0 to 15 and use it as a bit mask to check what are the valid results that can be generated.
Here is a code in python to give you idea.
a = [2,4,6,7]
for i in range(16):
x = i
ans = 0
for j in range(4):
if(x%2):
ans += a[j]
x /= 2
print ans,
0 2 4 6 6 8 10 12 7 9 11 13 13 15 17 19

Bubble Sort Ascending Comparison & Swap Count

We are studying algorithms and we haven't yet started making any programs with it, so we have a simple exercises. For example:
I have to bubble sort:
4 2 7 16 6
Here is a proccess (we have to look from the right to left in this case):
4 2 7 16 6 (it makes 3 swaps and 4 comparisons in this)
2 4 6 7 16 (it makes 0 swaps and 3 comparison in this)
2 4 6 7 16 (the result)
This how I understand it:
4 2 7 16 6 (6 is swapped with 16)
4 2 7 6 16 (6 is swapped with 7)
4 2 6 7 16 (6 is not swapped with 2)
4 2 6 7 16 (2 is swapped with 4)
2 4 6 7 16 (result after 1st iteration)
now we have numbers which have been arranged properly, we have made 4 comparisons at the beginning and 3 swaps and we know that 2 is the smallest number so we will look at 4 6 7 16 now. However they are arranged properly but still we have to make 3 additional
comparisons.
My question is: do we have to make another 2 comparisons and then the last 1 comparison (which would result in 10 comparisons overall) to finish the bubble sort? Or it stops after 7?
I'm not sure when the Bubble-sort stops.

Partitioning a circular buffer while keeping order

I've got a circular buffer with positive natural values, e.g.
1 5
4 2
11 7
2 9
We're going to partition it into exactly two continuous parts, while keeping this order. These two parts in this example could be:
(4 1 5) and (2 7 9 2 11),
(7 9 2 11 4) and (1 5 2),
etc.
The idea is to keep order and take two continuous subsequences.
And the problem now is to partition it so that the sums of these subsequences are closes to each other, i.e. the difference between the sums must be closest to zero.
In this case, I believe the solution would be: (2 7 9 2) and (11 4 1 5) with sums, respectively, 20 and 21.
How to do this optimally?
Algorithm:
Calculate the total sum.
Let the current sum = 0.
Start off with 2 pointers at any point (both starting off at the same point).
Increase the second pointer, adding the number it passed, until the current sum is more than half of the total sum.
Increase the first pointer, subtracting the number it passed, until the current sum is less than half of the total sum.
Stop if either:
The first pointer is back where it started, or
The best sum is 0.5 or 0 from half the total sum (in which case the difference will be 1 or 0).
The difference can be 1 only if the total sum is odd, in which case the difference can never be 0. (Thanks Artur!)
Otherwise repeat from step 3.
Check all the current sums we got in this process and keep the one that's closest to half, along with indices of the partition that got that sum.
Running time:
The running time will be O(n), since we only ever increase the pointers and the first one only goes around once, and the second one can't go around more than twice.
Example:
Input:
1 5
4 2
11 7
2 9
Total sum = 41.
Half of sum = 20.5.
So, let's say we start off at 1. (I just put it on a straight line to make it easier to draw)
p1, p2
V
1 5 2 7 9 2 11 4
sum = 0
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 1
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 6
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 8
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 15
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 24
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 23
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 18
p1 p2
V V
1 5 2 7 9 2 11 4
sum = 20
Here the sum (20) is 0.5 from half the total sum (20.5), so we can stop.
The above corresponds to (11 4 1 5) (2 7 9 2), with a difference in sums of 1.

Resources