Arrange elements in an array in a specific order - arrays

Found this interview question on Careercup
Given an array A with n integers.
Rearrange array such that
A[0]<=A[1]>=A[2]<=A[3]>=A[4]<=A[5] and so on
Edit: Array is not sorted and You have to do it in linear time O(N)
I am unable to find a solution in linear time, the closest I get is sort the array and then rearrange elements. Anyone has idea how it can be done in linear time? Can this be even done in linear time?
My proposed solution is to sort the array in nlogn time and then rearrange every odd element i with i-1 and i+1 alternatively.

Use quickselect to find the median of the array in O(n). This will allow you to divide the array in two equal (or almost equal) parts: those who are less than or equal to the median (A) up to n/2 elements, and the rest (B), that will be, by definition, greater than or equal to the median.
Arrange the array using this two halves like the following:
A B A B A B A
This will be correct, because every item A will be less than or equal to every B, by definition.

You can use this function (the code is in Swift) to arrange the array in a Wave Form in time O(n).
func wave(inout list: [Int]) {
let evenIndexes = (0..<list.count).filter { $0 % 2 == 0 }
for index in evenIndexes {
if index > 0 && list[index] > list[index-1] {
swap(&list[index], &list[index-1])
}
if index < list.count - 1 && list[index] > list[index+1] {
swap(&list[index], &list[index+1])
}
}
}
This solution is based on the algorithm described here.
Test
var test0 = [1,2,3,4,5,6]
wave(&test0)
print(test0) // [1, 3, 2, 5, 4, 6]
var test1 = [4, 6, 2, 1, 3, 7]
wave(&test1)
print(test1) // [4, 6, 1, 3, 2, 7]
var test2 = [20, 9, 4, 2, 0]
wave(&test2)
print(test2) // [9, 20, 2, 4, 0]
Time complexity
The function has a for loop executed n/2 times (only for the even indexes). So the for loop has time complexity O(n).
Inside the for loop we found a couple of if then statement, both are executed in constante time so O(1).
So the time complexity is O(n) * O(1) = O(n) where n is the number of elements in the input array.

C# implementation of O(n) solution with usage of NthElement algorithm:
public void WaveSortTest(int[] a)
{
var nthElement = NthElement(a, a.Length / 2);
var element = a[nthElement];
var odd = 1;
var even = 0;
var r = new int[a.Length];
for (int i = 0; i < a.Length; i++)
{
if (a[i] <= element)
{
r[even] = a[i];
even += 2;
}
else
{
r[odd] = a[i];
odd += 2;
}
}
PrintArray(r);
}
private static readonly Random _rnd = new Random((int)DateTime.Today.ToFileTimeUtc());
private static int NthElement(int[] arr, int k)
{
return NthElement(arr, 0, arr.Length, k);
}
private static int NthElement(int[] arr, int low, int high, int k)
{
var pos = low + _rnd.Next(high - low);
Swap(arr, pos, high - 1);
var i = Partition(arr, low, high);
if (k < i)
{
return NthElement(arr, low, i, k);
}
if (k > i)
{
return NthElement(arr, i + 1, high, k);
}
return i;
}
private static int Partition(int[] arr, int low, int high)
{
var i = low - 1;
for (var j = low; j < high; j++)
{
if (arr[j] <= arr[high - 1])
{
i++;
Swap(arr, i, j);
}
}
return i;
}
private static void Swap<T>(T[] a, int first, int second)
{
var t = a[first];
a[first] = a[second];
a[second] = t;
}
private static void PrintArray(IEnumerable<int> arr)
{
foreach (var item in arr)
{
Console.Write(item + " ");
}
Console.WriteLine();
}

Related

Find max common sum of subsets of 2 arrays

Given 2 Arrays of Intergers (unsorted, may contains duplicate elements), e.g.:
int[] left = {1, 5, 3};
int[] right = {2, 2};
We can get sums of subset of left array by picking or not picking up each element (2^n combinations), so, all the possbile sums could be (remove the duplicate sums):
{0, 1, 3, 4, 5, 6, 8, 9}
Same thing to the right array, sums of subset of right array are:
{0, 2, 4}
Then, the max common sum of subsets of these 2 arrays is 4, because 4 = left[0] + left[2] = rihgt[0] + right[1] and it's the max.
Question: how to get max common sum and indexes to construct this sum from 2 arrays? (if there are multipe combinations could get the same max sum in one array, just need to return one combination) Any better way to get the max common sum without caculating out all the possbile sums of subset?
I think this solution using bitsets in C++ will work.
// returns maximum possible common subset sum
int fun(int left[], int right[]){
// for the given constraints, the maximum possible sum is 10^7
bitset<10000001> b, b1;
int n = // size of left array
int m = // size of right array
b[0] = b1[0] = 1;
for(int i=0;i<n;i++){
b|=b<<left[i];
}
for(int i=0;i<m;i++){
b1|=b1<<right[i];
}
// After the above loop, b and b1 contains all possible unique values of subset sum.
// Just loop from the most significant bit and find the position in which the
// bits of both, b and b1 are set.
// That position is the maximum possible common subset sum
// For indices, any standard algorithm for finding subset-sum
// for a particular sum will do.
}
Based on the method pointed out by risingStark for finding the maximum common sum and on Print all subsets with given sum for finding indexes of summands, and since the question uses Java syntax, here's an unoptimized and unbeautified Java program with some example data sets:
import java.util.Arrays;
import java.math.BigInteger;
public class _68232965
{
static int sum;
static boolean found;
public static void main(String[] args)
{
{ int[][] lr = { {1, 5, 3}, {2, 2} }; maxcommsum(lr); }
{ int[][] lr = { {1,1,2,3,4}, {2, 2} }; maxcommsum(lr); }
{ int[][] lr = { {1, 2, 3}, {2, 2} }; maxcommsum(lr); }
{ int[][] lr = { {3,3,3,10}, {9,13} }; maxcommsum(lr); }
}
static void maxcommsum(int[][] lr)
{
for (var a: lr) System.out.println(Arrays.toString(a));
var s = new BigInteger[] { BigInteger.ONE, BigInteger.ONE };
for (int j, i = 0; i < 2; ++i)
for (j = 0; j < lr[i].length; ++j) s[i] = s[i].shiftLeft(lr[i][j]).or(s[i]);
while (s[0].bitLength() != s[1].bitLength())
{ // find the maximum common sum
int larger = s[0].bitLength() < s[1].bitLength() ? 1 : 0;
s[larger] = s[larger].clearBit(s[larger].bitLength()-1);
}
sum = s[0].bitLength()-1;
System.out.println("sum = "+sum);
for (var a: lr) { found = false; f(a, 0, 0); System.out.println("<= indexes"); }
}
static void f(int[] pat, int i, int currSum)
{ // find indexes of summands
if (currSum == sum)
{
found = true;
return;
}
if (currSum < sum && i < pat.length)
{
f(pat, i+1, currSum + pat[i]); if (found) { System.out.print(i+" "); return; }
f(pat, i+1, currSum);
}
}
}

find number of pairs in an array that are out-of-order

I have written a program that inputs an array of n elements and outputs the number of pair of elements that are out-of-order.
We will call a pair of elements arr[i] and arr[j] out-of-order if i < j and arr[i] > arr[j].
The running time of my program is O(n^2). It's a naive approach with two nested for loops. I was wondering if there is another way to solve this problem in less time. maybe in O(nLogn) time?
The algorithm you are looking for is called Counting inversions. Yes you can solve this problem using divide and conquer approach and the time complexity will be O(nlogn). It's similar to merge sort and additionally we need to keep track of inversions count. I am only printing the inversions count.
public class InversionsInOrderNSquared {
public static void main(String[] args) {
int array[] = { 10, 15, 2, 2, -4, 100, 99999, -10 };
System.out.println("Inversions Count: "+inversions(array));
}
private static int inversions(int[] array) {
int n = array.length;
int inversionCountLeft = 0;
int inversionCountRight = 0;
int inversionCountCross = 0;
if (n >= 2) {
int mid = n / 2;
int[] leftArray = new int[mid];
int[] rightArray = new int[n - mid];
for (int i = 0; i < n; i++) {
if (i < mid) {
leftArray[i] = array[i];
} else {
rightArray[i - mid] = array[i];
}
}
inversionCountLeft = inversions(leftArray);
inversionCountRight = inversions(rightArray);
inversionCountCross = computeInversions(array, leftArray,
rightArray);
}
return (inversionCountLeft + inversionCountRight + inversionCountCross);
}
private static int computeInversions(int[] array, int[] leftArray,
int[] rightArray) {
int n_left = leftArray.length;
int n_right = rightArray.length;
int inversionCount = 0;
int i = 0;
int j = 0;
int k = 0;
while (i < n_left && j < n_right) {
if (leftArray[i] > rightArray[j]) {
array[k] = rightArray[j];
inversionCount += (n_left - i);// logic is we are doing index
// wise element comparison
// between 2 sorted arrays thus
// for any index if any element
// in left
// sub-array is grater than
// element in right sub array
// that mean all the elements
// after that element present in
// left sub-array should be
// grater than right sub-array
// elements. Thus we are
// considering (n_left - i) in
// inversion count calculation.
j++;
} else {
array[k] = leftArray[i];
i++;
}
k++;
}
while (i < n_left) {
array[k] = leftArray[i];
i++;
k++;
}
while (j < n_right) {
array[k] = rightArray[j];
j++;
k++;
}
return inversionCount;
}
}
Execution 1:
Output:
Input array:
int array[] = { 10, 15, 2, 2, -4, 100, 99999, -10 };
Inversions Count: 15
Execution 2:
Input array:
int array[] = { 1,2,3,4,5,6 };
Output:
Inversions Count: 0
Regarding time complexity calculation:
computeInversions() method will take theta(n) time.
inversions() method is getting called 2 times with array size n/2.
Hence the recurrence relation is,
T(n) = 2T(n/2) + theta(n);
It's following Master's theorem equation format.
Hence a =2, b=2 and f(n)=theta(n)
n^log a base b = n^log 2 base 2 = n^1 = n
Thus above recurrence is matching case 2 of Master's theorem.
Thus time complexity is O(nlogn)
You can calculate such out of order pairs in o(nlogn) complexity.
For example if arr[] = {1,5,3,2,4}
Out of order pairs are : (5,3), (5,2), (5,4), (3,2).
Below is the working code for the same :
public static int countOutOfOrder(int []nums) {
int len = nums.length, index=len-1, count=0, currindex=0, total=0;
List<Integer>sorted = new ArrayList<Integer>();
while(index>=0) {
currindex = search(sorted, nums[index]);
sorted.add(currindex, nums[index]);
total+=(currindex);
index--;
}
return total;
}
private static int search(List<Integer> sorted, int value) {
int start=0, end = sorted.size()-1, mid=0;
while(start<=end) {
mid = (start+end)/2;
if(sorted.get(mid) == value && (mid==start || sorted.get(mid-1) == value)) {
return mid;
} else if(sorted.get(mid) <= value) {
start = mid+1;
} else {
end = mid-1;
}
}
return start;
}
Explanation for o(nlogn) solution based on above example :
Maintain a list of sorted elements say sorted
Start from end index
search in sorted list where we can insert the current element in
Based on position we can insert , find total number of elements before this index that will be total inversions.
Add this element in the sorted list.
Time complexity :
We are looping through all elements so complexity for this is o(n)
For each element we are searching in sorted list , search complecity is o(logn).
So, total complexity is o(n)*o(logn) = o(nlogn)

Find 3rd highest sum of a pair in an array

If we have to find 3rd highest sum of a pair of elements in an array.
E.g. Given
int arr[] = { 1, 2, 3, 4 };
then, we have these pairs:
(1,2) = 3, (1,3) = 4, (1,4) = 5, (2,3) = 5, (2,4) = 6, (3,4) = 7
Here, the answer is 5 and the pairs are (1,4) and (2,3).
The array is not necessarily sorted and duplicated values in the array can appear in pairs.
I have tried an algorithm with two nested loops. Time complexity is quadratic. How can I lower the complexity?
Now, if we need to find the kth highest pair sum. Can we go for minheap or maxheap wherein we first store the pair sums in the maxheap/minheap and then find the kth largest of them.
First try a brute for approach:
scan the array with a double loop to find the largest sum sum1;
rescan the array with a double loop to find the largest sum sum2 different from sum1;
rescan the array a third time to find the largest sum sum3 different from both sum1 and sum2;
rescan the array one final time to print all pairs that have sum sum3.
Time complexity is quadratic, but it will handle duplicates correctly.
You can then drastically reduce the complexity by filtering the array, only keeping the largest 3 numbers with at most 2 instances if there are duplicates. This can be done in linear time. You then run the quadratic algorithm on a set of at most 6 elements. Total complexity is still linear.
var a=[30,4,2,5,6,0,9];
var first=a[0];
var second="";
var third="";
// Solve it in O(n) time
for(var i=1;i<a.length;i++)
{
//Find first Max
if(a[i]>first)
{
second=first;
first=a[i];
}
//Find second Max
else if(a[i]>second && a[i]!=first )
{
third=second;
second=a[i];
}
//Find third Max
else if(a[i]>third && a[i]!=first && a[i]!=second)
third=a[i];
}
console.log(first+second+third);
public int thirdHighest()
{
int sum = 0;
List<int> number = new List<int>();
int[] array = new int[] { 1, 2, 3, 4, 6, 7 };
for (int i = 0; i < array.Length; i++)
{
for (int j = i + 1; j < array.Length; j++)
{
sum = array[i] + array[j];
if (number.Contains(sum))
{
}
else
{
number.Add(sum);
}
}
}
int[] array1 = new int[number.Count];
for (int i = 0; i < number.Count; i++)
{
array1[i] = number[i];
}
Array.Sort<int>(array1);
Array.Reverse(array1);
return array1[2];
}
you can use it this way:
int varmax1, varmax2, varmax3, varmax4, varmax5, varmax6, i, j, max=0, max2=0, max3=0;
for(i=0; i<3;i++)
{
for(j=i;j<3;j++)
{
sum=arr[i]+arr[j];
if(sum>max)
{
max3=max2;
max2=max;
max=sum;
varmax1 = varmax3;
varmax2 = varmax4;
varmax3 = varmax5;
varmax4 = varmax6;
varmax5 = i;
varmax6 = j;
}
else if(sum>max2)
{
max3=max2;
max2=sum;
varmax1 = varmax3;
varmax2 = varmax4;
varmax3=i
varmax4=j
}
else if(sum>max3)
{
max3=sum;
varmax1 = arr[i];
varmax2 = arr[j];
}
}
}
printf("elements with 3rd largest sum are %d %d", varmax1, varmax2);
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] intList = {5,4,7,8,12,16,19,5};
Set<Integer> intSumList = new HashSet<Integer>();
List<Integer> intSumList1 = new ArrayList<Integer>();
for(int i=0;i<intList.length;i++){
for(int j=(intList.length - 1);j>i;j--)
{
// System.out.println(intList[j]+" --- "+intList[i]);
intSumList.add((intList[j]+intList[i]));
}
}
for(int ele : intSumList){
intSumList1.add(ele);
}
Collections.sort(intSumList1);
for(int ele : intSumList1){
System.out.println(ele);
}
System.out.println("sum is "+intSumList1.get((intSumList1.size()-3)));
}

Kth smallest element in sorted matrix

This is an interview question.
Find the Kth smallest element in a matrix with sorted rows and columns.
Is it correct that the Kth smallest element is one of a[i, j] such as i + j = K ?
False.
Consider a simple matrix like this one:
1 3 5
2 4 6
7 8 9
9 is the largest (9th smallest) element. But 9 is at A[3, 3], and 3+3 != 9. (No matter what indexing convention you use, it cannot be true).
You can solve this problem in O(k log n) time by merging the rows incrementally, augmented with a heap to efficiently find the minimum element.
Basically, you put the elements of the first column into a heap and track the row they came from. At each step, you remove the minimum element from the heap and push the next element from the row it came from (if you reach the end of the row, then you don't push anything). Both removing the minimum and adding a new element cost O(log n). At the jth step, you remove the jth smallest element, so after k steps you are done for a total cost of O(k log n) operations (where n is the number of rows in the matrix).
For the matrix above, you initially start with 1,2,7 in the heap. You remove 1 and add 3 (since the first row is 1 3 5) to get 2,3,7. You remove 2 and add 4 to get 3,4,7. Remove 3 and add 5 to get 4,5,7. Remove 4 and add 6 to get 5,6,7. Note that we are removing the elements in the globally sorted order. You can see that continuing this process will yield the kth smallest element after k iterations.
(If the matrix has more rows than columns, then operate on the columns instead to reduce the running time.)
O(k log(k)) solution.
Build a minheap.
Add (0,0) to the heap. While, we haven't found the kth smallest element, remove the top element (x,y) from heap and add next two elements [(x+1,y) and (x,y+1)] if they haven't been visited before.
We are doing O(k) operations on a heap of size O(k) and hence the complexity.
This problem can be solved using binary search and optimised counting in a sorted Matrix. A binary search takes O(log(n)) time and for each search value it takes n iterations on average to find the numbers that are smaller than the searched number. The search space for binary search is limited to the minimum value in the Matrix at mat[0][0] and the maximum value mat[n-1][n-1].
For every number that is chosen from the binary search we need to count the numbers that are smaller than or equal to that particular number. And thus the smallest number can be found.
For better understanding you can refer to this video:
https://www.youtube.com/watch?v=G5wLN4UweAM&t=145s
Start traversing the matrix from the top-left corner (0,0) and use a binary heap for storing the "frontier" - a border between a visited part of the matrix and the rest of it.
Implementation in Java:
private static class Cell implements Comparable<Cell> {
private final int x;
private final int y;
private final int value;
public Cell(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
#Override
public int compareTo(Cell that) {
return this.value - that.value;
}
}
private static int findMin(int[][] matrix, int k) {
int min = matrix[0][0];
PriorityQueue<Cell> frontier = new PriorityQueue<>();
frontier.add(new Cell(0, 0, min));
while (k > 1) {
Cell poll = frontier.remove();
if (poll.y + 1 < matrix[poll.x].length) frontier.add(new Cell(poll.x, poll.y + 1, matrix[poll.x][poll.y + 1]));
if (poll.x + 1 < matrix.length) frontier.add(new Cell(poll.x + 1, poll.y, matrix[poll.x + 1][poll.y]));
if (poll.value > min) {
min = poll.value;
k--;
}
}
return min;
}
As people mentioned previously the easiest way is to build a min heap. Here's a Java implementation using PriorityQueue:
private int kthSmallestUsingHeap(int[][] matrix, int k) {
int n = matrix.length;
// This is not necessary since this is the default Int comparator behavior
Comparator<Integer> comparator = new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
};
// building a minHeap
PriorityQueue<Integer> pq = new PriorityQueue<>(n*n, comparator);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
pq.add(matrix[i][j]);
}
}
int ans = -1;
// remove the min element k times
for (int i = 0; i < k; i++) {
ans = pq.poll();
}
return ans;
}
Kth smallest element in the matrix :
The problem can be narrowed down as below.
if k is 20, then take k*k matrix (where answer will definitely lie.)
Now you can merge the rows in pair repeatedly to build a sorted array and then find the kth smallest number.
//int arr[][] = {{1, 5, 10, 14},
// {2, 7, 12, 16},
// {4, 10, 15, 20},
// {6, 13, 19, 22}
//};
// O(k) Solution
public static int myKthElement(int arr[][], int k) {
int lRow = 1;
int lCol = 0;
int rRow = 0;
int rCol = 1;
int count = 1;
int row = 0;
int col = 0;
if (k == 1) {
return arr[row][col];
}
int n = arr.length;
if (k > n * n) {
return -1;
}
while (count < k) {
count++;
if (arr[lRow][lCol] < arr[rRow][rCol]) {
row = lRow;
col = lCol;
if (lRow < n - 1) {
lRow++;
} else {
if (lCol < n - 1) {
lCol++;
}
if (rRow < n - 1) {
lRow = rRow + 1;
}
}
} else {
row = rRow;
col = rCol;
if (rCol < n - 1) {
rCol++;
} else {
if (rRow < n - 1) {
rRow++;
}
if (lCol < n - 1) {
rCol = lCol + 1;
}
}
}
}
return arr[row][col];
}

In-place array reordering?

Let's say I have an array a of length n and a second array indices, also of length n. indices contains some arbitrary permutation of the sequence [0, n). I want to to rearrange a such that it's in the order specified by indices. For example, using D syntax:
auto a = [8, 6, 7, 5, 3, 0, 9];
auto indices = [3, 6, 2, 4, 0, 1, 5];
reindexInPlace(a, indices);
assert(a == [5, 9, 7, 3, 8, 6, 0]);
Can this be done in both O(1) space and O(n) time, preferably without mutating indices?
With mutating indices :(. Without looks hard (see stable in-place mergesort).
a = [8, 6, 7, 5, 3, 0, 9]
indices = [3, 6, 2, 4, 0, 1, 5]
for i in xrange(len(a)):
x = a[i]
j = i
while True:
k = indices[j]
indices[j] = j
if k == i:
break
a[j] = a[k]
j = k
a[j] = x
print a
This is what I call a "permute from" algorithm. In C-like language it would look as follows
for (i_dst_first = 0; i_dst_first < n; ++i_dst_first)
{
/* Check if this element needs to be permuted */
i_src = indices[i_dst_first];
assert(i_src < n);
if (i_src == i_dst_first)
/* This element is already in place */
continue;
i_dst = i_dst_first;
pending = a[i_dst];
/* Follow the permutation cycle */
do
{
a[i_dst] = a[i_src];
indices[i_dst] = i_dst;
i_dst = i_src;
i_src = indices[i_src];
assert(i_src != i_dst);
} while (i_src != i_dst_first);
a[i_dst] = pending;
indices[i_dst] = i_dst;
}
Note though that this algorithm destroys the index array. I call it "permute from" since the index[i] value specifies from where to take the i-th element of the resultant sequence.
Note also, that the number of "element move" operations required for in-place permutation of a sequence is equal to number of misplaced elements + number of cycles in the permutation. This algorithm achieves this limit, so in terms of the number of moves no better algorithm is possible.
Potential problem with this algorithm is that it is based on "juggling" approach, making its cache behavior far from optimal. So, while this algorithm is the best one in theory, it could lose to some more "practical" algorithms in real life.
One can also implement a "permute to" algorithm, where index[i] value specifies where to relocate the original i-th element.
If a is an array of integers, then an O(n)-time, O(1)-space algorithm is possible that keeps the order of permutation indices. In this case we can permute a into indexes and use a as a temporary storage of the inverse permutation. After the permutation is performed, the arrays a and indices are swapped, and indices is inverted in situ using e.g. algorithm J from TAoCP. The following is a working Java program:
int [] a = {8, 6, 7, 5, 3, 0, 9};
int [] indices = {3, 6, 2, 4, 0, 1, 5};
int n = indices.length;
int i, j, m;
// permute a and store in indices
// store inverse permutation in a
for (j = 0; j < n; ++j) {
i = indices[j]; indices[j] = a[i]; a[i] = j;
}
// swap a and indices
for (j = 0; j < n; ++j) {
i = indices[j]; indices[j] = a[j]; a[j] = i;
}
// inverse indices permutation to get the original
for (i = 0; i < n; ++i) {indices[i] = -indices[i] - 1;}
for (m = n - 1; m >= 0; --m) {
// for (i = m, j = indices[m]; j >= 0; i = j, j = indices[j]) ;
i = m; j = indices[m];
while (j >= 0) {i = j; j = indices[j];}
indices[i] = indices[-j - 1];
indices[-j - 1] = m;
}
This answers the question when indices array is mutable.
Here is a solution when it is not mutable.
void mutate(int[] input, int[] indices) {
int srcInd;
for (int tarInd = 0; tarInd < input.length; tarInd++) {
srcInd = indices[tarInd];
while(srcInd < tarInd) {
// when src is behind, it will have it's final value already and the original
// value would have been swapped with src's src pos. Keep searching for the
// original value until it is somewhere ahead of tarInd.
srcInd = indices[srcInd];
}
swap(input, srcInd, tarInd);
}
}
I think the classic way to deal with this problem is to work round the cycles, and to do this you need a marker bit per data item from somewhere. Here I pinched the top bit of the index array, which you could restore - of course this assumes that you don't have -ve array indexes or are using all bits of an unsigned number as an index. One reference for this is Knuth Volume 1 section 1.3.3 answer to question 12, which deals with the special case of transposing a matrix. Knuth gives references to slower in-place methods. The paper "Permuting in Place" by Fich, Munro, and Poblete claims nlogn time and O(1) space in the worst case.
import java.util.Arrays;
public class ApplyPerm
{
public static void reindexInPlace(int[] rearrangeThis, int[] indices)
{
final int TOP_BIT = 0x80000000;
for (int pos = 0; pos < rearrangeThis.length; pos++)
{
if ((indices[pos] & TOP_BIT) != 0)
{ // already dealt with this
continue;
}
if (indices[pos] == pos)
{ // already in place
continue;
}
// Now shift an entire cycle along
int firstValue = rearrangeThis[pos];
int currentLocation = pos;
for (;;)
{
// pick up untouched value from here
int replaceBy = indices[currentLocation];
// mark as dealt with for the next time we see it
indices[currentLocation] |= TOP_BIT;
if (replaceBy == pos)
{ // have worked our way round
rearrangeThis[currentLocation] = firstValue;
break;
}
if ((replaceBy & TOP_BIT) != 0)
{
throw new IllegalArgumentException("Duff permutation");
}
// Move value up
rearrangeThis[currentLocation] = rearrangeThis[replaceBy];
// and fill in source of value you have just moved over
currentLocation = replaceBy;
}
}
}
public static void main(String[] s)
{
int[] a = new int[] {8, 6, 7, 5, 3, 0, 9};
int[] indices = new int[] {3, 6, 2, 4, 0, 1, 5};
reindexInPlace(a, indices);
System.out.println("Result is " + Arrays.toString(a));
}
}
You can do this by hiding the values in the real array. By this way you can do this in both O(1) space and O(n) time.
Basically, you traverse through your indices array first, store the value of the indice array in the correct position. Now this can be done in the algorithm of your choice. For me, I would simply store the number's trailing bits from the Most Significant bit position. Do this in one traversal. Now the base array would be messed up.
During the second traversal store all the upper half bits to lower half.
The obvious disadvantage of this technique is that the stored integer
value can hold as much as half the bits. Meaning if you are dealing
with 4 byte integer, the values can only be of 2 bytes. However instead of using up half the array as show in the code below, it can be enhanced by using a better algorithm where you hide the value in the index array. Here you will require the max bits reserved in worst case would be the length of the array rather than constant 16 in the previous case. It will perform worst than the former when the length exceeds 2 power 16.
import java.util.Arrays;
class MyClass {
public static void main(String[] args) {
MyClass myClass = new MyClass();
int[] orig_array = {8, 6, 7, 5, 3, 0, 9};
int[] indices = {3, 6, 2, 4, 0, 1, 5};
myClass.meth(orig_array, indices);
}
public void meth(int[] orig_array, int[] indices){
for(int i=0;i<orig_array.length;i++)
orig_array[i] += orig_array[indices[i]] + orig_array[indices[i]] << 15 ;
for(int i=0;i<orig_array.length;i++)
orig_array[i] = orig_array[i] >> 16;
System.out.print(Arrays.toString(orig_array));
}
}
Here's a C++ version (it modifies the indices):
#include <algorithm>
#include <iterator>
template<class It, class ItIndices>
void permutate_from(
It const begin,
typename std::iterator_traits<It>::difference_type n,
ItIndices indices)
{
using std::swap;
using std::iter_swap;
for (typename std::iterator_traits<It>::difference_type i = 0; i != n; ++i)
{
for (typename std::iterator_traits<ItIndices>::value_type j = i; ; )
{
swap(j, indices[j]);
if (j == i) { break; }
iter_swap(begin + j, begin + indices[j]);
}
}
}
Example:
int main()
{
int items[] = { 2, 0, 1, 3 };
int indices[] = { 1, 2, 0, 3 };
permutate_from(items, 4, indices);
// Now items[] == { 0, 1, 2, 3 }
}
JavaScript version
var input = [1,2,3,4,5],
specArr = [0,2,1,4,3];
function mutate(input, specArr) {
var visited = [0,2]
for(var i=0; i<specArr.length; i++) {
var tmp;
//keep track of array items we've already looped through (wouldn't want to mutate twice :D)
visited.push(specArr[i]);
// if index hasn't changed we do nothing to input arr
if (visited.indexOf(1) < 0) {
// if it has changed temporarily store the value
tmp = input[i];
//swap input array item with spec item
input[i] = input[specArr[i]];
//swap specced array item with input item above
input[specArr[i]] = tmp;
}
}
}
mutate(input, specArr);

Resources