Two arrays (nums1 and nums2) of length m and n respectively have to be merged and the and be sorted in the array nums1. length of nums1 is m+n and last n elements in nums1 are 0.
Not to be returned, nums1 has to be modified.
LeetCode question
Example
Input
nums1 = [1, 2, 3, 0, 0, 0]
m = 3
nums2 = [2, 5, 6]
n = 3
Output [1, 2, 2, 3, 5, 6]
Explanation
The arrays we are merging are [1,2,3] and [2,5,6]. The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.
I have done the question but no idea why its not working.
var merge = function(nums1, m, nums2, n) {
let j = 0
for (let i = m; i < n; i++) {
nums1[i] = nums2[j]
j++
}
};
Driven Code:
let nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
merge(nums1, m, nums2, n)
console.log(nums1)
Output:
[1, 2, 3, 0, 0, 0]
You've misunderstood the purpose of m and n. You should step through this in the debugger, and you'll quickly notice your loop is never entered.
They're not first and last indices of the "zero region". They're the first index, and the count of zeros found after that (which is as long as the num2 array that would be merged into num1. This would be more apparent if the names weren't as useless as m and n.
A performant solution to this would involve doing this in-place (in fact, the problem outline requires that you modify num1 rather than make a new array).
You know both arrays are sorted, so "merging" only requires you pick the smallest element from each. The problem is that all your "free space" in num1 (the 0s) are located at the back, which makes it had to make room at the beginning of the array to insert elements from num2.
Instead, you can rely on this fact: An array that's sorted smallest-to-largest is also sorted when reversed, except from largest-to-smallest. While this may be obvious, it's the key trick: you fill num2 starting from the end, and working towards the start. At every step, you replace a 0 (and eventually, the other numbers)with the largest element from the "tail" ofnum1ornum2`.
Doing this all the way through gives you a time complexity of O(n) with no extra space used.
Usse concat function of array and then sort function
e.g.
num1 = num1.concat(num2)
num1.sort()
OR
num1 = num1.concat(num2).sort()
Do you searching something like this?
nums1 = [...nums1, ...nums2].sort().filter(i => i != 0);
console.log(nums1);
Steps taken here:
First contact two array
Then sort the array in ascending order
Then remove 0 from the array
Check this out:
tempNums1 = nums1.slice(0, m);
tempNums2 = nums2.slice(0, n);
arr = [...tempNums1, ...tempNums2].sort((a,b) => { return a - b; });
nums1.splice(0, nums1.length);
for(let i=arr.length - 1;i>=0;i--){
nums1.unshift(arr[i]);
}
Here the hack is splice and unshift takes effect outside of the function scope
Updated:
nums1.splice(m, nums1.length);// O(n)
for(let j=0; j< n; j++){
nums1.unshift(nums2[j]); // O(n)
}
nums1.sort((a, b) => a - b); // O(n log n)
There you go
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (n == 0) {
return;
}
int i = m - 1;
int j = n - 1;
int k = nums1.length - 1;
while (i >= 0 && j >= 0) {
if (nums2[j] > nums1[i]) {
nums1[k--] = nums2[j--];
} else {
nums1[k--] = nums1[i--];
}
}
while (j >= 0) {
nums1[k--] = nums2[j--];
}
}
Related
This question already has answers here:
How to sort in-place using the merge sort algorithm?
(10 answers)
Closed 2 years ago.
I have two sorted arrays, I have to merge two sorted arrays into one without using extra space?
I was checking this solution but I am unable to understand it.
Example
Input: ar1[] = {10};
ar2[] = {2, 3};
Output: ar1[] = {2}
ar2[] = {3, 10}
Input: ar1[] = {1, 5, 9, 10, 15, 20};
ar2[] = {2, 3, 8, 13};
Output: ar1[] = {1, 2, 3, 5, 8, 9}
ar2[] = {10, 13, 15, 20}
Here is a simple algorithm:
while last element of ar1 is larger than ar2[0]:
swap them.
shift the last element of ar1 to its place in ar1,
shift the first element of ar2 to its place in ar2,
repeat
The space complexity is O(1), the time complexity is O(n2).
I'll solve it for the slightly simpler case of "the two arrays are already in one buffer".
// requires: array is a pointer to a buffer of numbers,
// such that from [array, array+middle) is sorted, and [array+middle, array+length)
// is also sorted.
void merge_inplace( int* array, int length );
// This halves the number "gap", rounding up. Unless the value was 1, in
// which case it returns 0.
int nextgap( int gap ) {
if (gap==1) return 0;
return (gap+1)/2;
}
void merge_inplace( int* array, int length ) {
int gap = nextgap(length); // about half of length
while (gap != 0)
{
int left = 0;
int right = left+gap;
while (right < length) {
// ensure elements at left and right are in correct relative order:
if (array[left] > array[right])
std::swap(array[left], array[right]);
// advance:
++left;
++right;
}
// repeat on a gap half-ish the size:
gap = nextgap(gap);
}
}
now operating on two different arrays requires some extra work/logic, but that is mainly about fiddling with the indexes.
The point is that when you have two arrays that are sorted and next to each other, one pass of this "merge far apart, then closer together" algorithm (which has log-length count of subloops; so O(n lg n) steps) is enough to sort it.
In your examples the arrays are re-sorted. Is it what you need to do?
For this problem you can use the next algorithm:
Use a for loop from 0 to the length of the array1
Compare elements from the array1 and the array2
If an element of the array2 is less than an element of the array1 then swap them
Iterate over the array2 to find a better place of just swapped element
Algorithm:
void reorder(std::vector<int>& arr1, std::vector<int>& arr2)
{
for (size_t i = 0, j = 0; i < arr1.size(); )
{
if (arr1[i] < arr2[j])
{
i++;
continue;
}
std::swap(arr1[i], arr2[j]);
// find a better place for a swapped element in array 2
for (size_t k = j, l = k+1; l < arr2.size(); k++, l++)
{
if (arr2[k] < arr2[l])
break;
std::swap(arr2[k], arr2[l]);
}
}
}
This algorithm can be improved...
Problem:
Given an array, find two increasing subarrays(say a and b) such that when joined they produce one increasing array(say ab). We need to find max possible length of array ab.
For example:
given array = [2 3 1 2 5 4 5]
Two sub arrays are a = [2 3], b = [4, 5] and ab = [2 3 4 5]
Output: length(ab) = 4
I would solve it using brute force. By brute force I can get all the subarrays and then check if it is increasing. Then I can use a merge array and check if there are overlapping elements. If there are overlapping elements will remove them and store the length.
The time complexity for getting all the subarrays will be O(n^2) (I am assuming subarray will maintain the relative order and you do not mean all the subsets). And then will sort the subarrays using a queue and the sorting strategy would be the according to the first element. Then I will check how many can be merged with increasing property(something you use to merge already sorted array).
Then count the strictly increasing arrays after merging.
The other two approaches can be used by dynamic programming(this is same as longest contiguous increasing subarray): (Look here)
First approach:
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) { return 0; }
int[] dp = new int[nums.length];
int len = 0;
for(int n: nums) {
// Find the position of it in binary tree.
int pos = Arrays.binarySearch(dp, 0, len, n);
// Convert the negative position to positive.
if(pos < 0) { pos = -1*(pos + 1); }
// assign the value to n
dp[pos] = n;
// If the length of the dp grows and becomes equal to the current len
// assign the output length to that.
if(pos == len) {
len++;
}
}
// Return the length.
return len;
}
Another method:
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length == 0) { return 0; }
int n = nums.length;
Integer lis[] = new Integer[n];
int max = 0;
/* Initialize LIS values for all indexes
for ( int i = 0; i < n; i++ ) {
lis[i] = 1;
}
/* Compute optimized LIS values in bottom up manner
for (int i = 1; i < n; i++ ) {
for ( int j = 0; j < i; j++ ) {
if ( nums[i] > nums[j] && lis[i] < lis[j] + 1) {
lis[i] = lis[j] + 1;
}
}
}
max = Collections.max(Arrays.asList(lis));
return max;
}
Idea is of brute force, By brute force I can get all the increasing sub arrays. Then I can use check if there are overlapping elements. If there are overlapping elements will calculate the length after merge and then compare and store the max length.
I am working on a problem where I have an unsorted array. And I need to process this array in order to generate an index array as if it were sorted in an ascending order.
Example 1:
let's say I have an unsorted array [9, 7, 8, 6, 12]
And as an output, I need an index array [3, 1, 2, 0, 4].
Example 2:
Unsorted array : [10, 9, 11, 8, 12]
Index array should be : [ 2, 1, 3, 0, 4]
As of now, I am doing it just like old "bubble sort" where I'm comparing each and every possibility. I was wondering way to make it fast.
If you are not worried about extra space, do this:
Make an array of pairs (value, index)
Sort pairs on the value (first member) in ascending order
Harvest indexes (second member) from the sorted array of pairs
Using your data as an example, you would get this:
[{9,0}, {7,1}, {8,2}, {6,3}, {12,4}] // Step 1
[{6,3}, {7,1}, {8,2}, {9,0}, {12,4}] // Step 2
[ 3, 1, 2, 0, 4 ] // Step 3
(comment) I need is index of an unsorted array as if they were sorted in ascending order.
You can use array from step 3 to produce this output as well. Using your second example, you get this:
[{10,0}, {9,1}, {11,2}, {8,3}, {12,4}]
[ {8,3}, {9,1}, {10,0}, {11,2}, {12,4}]
[ 3, 1, 0, 2, 4 ]
Now create the output array, walk the array of indexes (i.e. [3,1,0,2,4]) and set the index of each item into the position in the result determined by the value, i.e. index 3 would get 0 because 3 is at index 0, index 1 would get 1 because 1 is at 1, index 0 would get 2 because 0 is at 2, and so on.
Here is the illustration of that additional step:
int position[] = {3, 1, 0, 2, 4};
int res[5];
for (int i = 0 ; i != 5 ; i++) {
res[position[i]] = i;
}
This produces the following array:
[2, 1, 3, 0, 4]
"Fast" means you need a sorted data structure with an complexity of O(log n) for inserts (and lookups of course). So a binary tree would do.
You create the index as an array of positions, and initialize it to the existing order: idx=[0, 1, 2, ...., n-1].
Then you sort the index array using your favorite sorting algorithm, but whenever performing a comparison, you use the values as positions to refernce the original array, instead of comparing them directly. For example, to compare the items i and j, you perform cmp(arr[idx[i]], arr[idx[j]]) instead of cmp(idx[i], idx[j]).
Did you try Radix Sort:
* Approach:
* radix sort, like counting sort and bucket sort, is an integer based
* algorithm (i.e. the values of the input array are assumed to be
* integers). Hence radix sort is among the fastest sorting algorithms
* around, in theory. The particular distinction for radix sort is that it
* creates a bucket for each cipher (i.e. digit); as such, similar to
* bucket sort, each bucket in radix sort must be a growable list that may
* admit different keys.
***************************************************************************/
import java.io.IOException;
public class RadixSort {
public static void sort( int[] a)
{
int i, m = a[0], exp = 1, n = a.length;
int[] b = new int[10];
for (i = 1; i < n; i++)
if (a[i] > m)
m = a[i];
while (m / exp > 0)
{
int[] bucket = new int[10];
for (i = 0; i < n; i++)
bucket[(a[i] / exp) % 10]++;
for (i = 1; i < 10; i++)
bucket[i] += bucket[i - 1];
for (i = n - 1; i >= 0; i--)
b[--bucket[(a[i] / exp) % 10]] = a[i];
for (i = 0; i < n; i++)
a[i] = b[i];
exp *= 10;
}
}
public static void main(String[] args) throws IOException {
int[] aa={9,7,8,6,12};
for (int i = 0; i < aa.length; i++) {
System.out.print(aa[i]+" ");
}
System.out.println();
sort(aa);
for (int i = 0; i < aa.length; i++) {
System.out.print(aa[i]+" ");
}
}
}
This is an interview question. A swap means removing any element from the array and appending it to the back of the same array. Given an array of integers, find the minimum number of swaps needed to sort the array.
Is there a solution better than O(n^2)?
For example:
Input array: [3124].
The number of swaps: 2 ([3124] -> [1243] -> [1234]).
The problem boils down to finding the longest prefix of the sorted array that appears as a subsequence in the input array. This determines the elements that do not need to be sorted. The remaining elements will need to be deleted one by one, from the smallest to the largest, and appended at the back.
In your example, [3, 1, 2, 4], the already-sorted subsequence is [1, 2]. The optimal solution is to delete the remaning two elements, 3 and 4, and append them at the back. Thus the optimal solution is two "swaps".
Finding the subsequence can be done in O(n logn) time using O(n) extra memory. The following pseudo-code will do it (the code also happens to be valid Python):
l = [1, 2, 4, 3, 99, 98, 7]
s = sorted(l)
si = 0
for item in l:
if item == s[si]:
si += 1
print len(l) - si
If, as in your example, the array contains a permutation of integers from 1 to n, the problem can be solved in O(n) time using O(1) memory:
l = [1, 2, 3, 5, 4, 6]
s = 1
for item in l:
if item == s:
s += 1
print len(l) - s + 1
More generally, the second method can be used whenever we know the output array a priori and thus don't need to find it through sorting.
This might work in O(nlogn) even if we don't assume array of consecutive values.
If we do - it can be done in O(n).
One way of doing it is with O(n) space and O(nlogn) time.
Given array A sort it (O(nlogn)) into a second array B.
now... (arrays are indexed from 1)
swaps = 0
b = 1
for a = 1 to len(A)
if A[a] == B[b]
b = b + 1
else
swaps = swaps + 1
Observation: If an element is swapped to the back, its previous position does not matter. No element needs to be swapped more than once.
Observation: The last swap (if any) must move the largest element.
Observation: Before the swap, the array (excluding the last element) must be sorted (by former swaps, or initially)
Sorting algorithm, assuming the values are conecutive: find the longest sorted subsequence of consecutive (by value) elements starting at 1:
3 1 5 2 4
swap all higher elements in turn:
1 5 2 4 3
1 5 2 3 4
1 2 3 4 5
To find the number of swaps in O(n), find the length of the longest sorted subsequence of consecutive elements starting at 1:
expected = 1
for each element in sequence
if element == expected
expected += 1
return expected-1
then the number of swaps = the length of the input - its longest sorted subsequence.
An alternative solution ( O(n^2) ) if the input is not a permutation of 1..n:
swaps = 0
loop
find the first instance of the largest element and detect if the array is sorted
if the array is sorted, return swaps.
else remove the found element from the array and increment swaps.
Yet another solution ( O(n log n) ), assuming unique elements:
wrap each element in {oldPos, newPos, value}
make a shallow copy of the array
sort the array by value
store the new position of each element
run the algorithm for permutations on the newPos' in the (unsorted) copy
If you don't want to copy the input array, sort by oldPos before the last step instead.
This can be done in O(n log n).
First find the minimum element in the array. Now, find the max element that occurs before this element. Call this max_left. You have to call swap()for all the elements before the min element of the array.
Now, find the longest increasing subsequence to the right of the min element, along with the constraint that you should skip elements whose values are greater than max_left.
The required number of swaps is size(array) - size(LIS).
For example consider the array,
7 8 9 1 2 5 11 18
Minimum element in the array is 1. So we find the max before the minimum element.
7 8 9 | 1 2 5 11 18
max_left = 9
Now, find the LIS to the right of min with elements < 9
LIS = 1,2,5
No of swaps = 8 - 3 = 5
In cases where max element is null, ie., min is the first element, find the LIS of the array and required answer is size(array)-size(LIS)
For Example
2 5 4 3
max_left is null. LIS is 2 3
No of swaps = size(array) - size(LIS) = 4 - 2 = 2
Here is the code in python for minimum number of swaps,
def find_cycles(array):
cycles = []
remaining = set(array)
while remaining:
j = i = remaining.pop()
cycle = [i]
while True:
j = array[j]
if j == i:
break
array.append(j)
remaining.remove(j)
cycles.append(cycle)
return cycles
def minimum_swaps(seq):
return sum(len(cycle) - 1 for cycle in find_cycles(seq))
O(1) space and O(N) (~ 2*N) solution assuming min element is 1 and the array contains all numbers from 1 to N-1 without any duplicate value. where N is array length.
int minimumSwaps(int[] a) {
int swaps = 0;
int i = 0;
while(i < a.length) {
int position = a[i] - 1;
if(position != i) {
int temp = a[position];
a[position] = a[i];
a[i] = temp;
swaps++;
} else {
i++;
}
}
return swaps;
}
int numSwaps(int arr[], int length) {
bool sorted = false;
int swaps = 0;
while(!sorted) {
int inversions = 0;
int t1pos,t2pos,t3pos,t4pos = 0;
for (int i = 1;i < length; ++i)
{
if(arr[i] < arr[i-1]){
if(inversions){
tie(t3pos,t4pos) = make_tuple(i-1, i);
}
else tie(t1pos, t2pos) = make_tuple(i-1, i);
inversions++;
}
if(inversions == 2)
break;
}
if(!inversions){
sorted = true;
}
else if(inversions == 1) {
swaps++;
int temp = arr[t2pos];
arr[t2pos] = arr[t1pos];
arr[t1pos] = temp;
}
else{
swaps++;
if(arr[t4pos] < arr[t2pos]){
int temp = arr[t1pos];
arr[t1pos] = arr[t4pos];
arr[t4pos] = temp;
}
else{
int temp = arr[t2pos];
arr[t2pos] = arr[t1pos];
arr[t1pos] = temp;
}
}
}
return swaps;
}
This code returns the minimal number of swaps required to sort an array inplace.
For example, A[] = [7,3,4,1] By swapping 1 and 7, we get [1,3,4,7].
similarly B[] = [1,2,6,4,8,7,9]. We first swap 6 with 4, so, B[] -> [1,2,4,6,8,7,9]. Then 7 with 8. So -> [1,2,4,6,7,8,9]
The algorithm runs in O(number of pairs where value at index i < value at index i-1) ~ O(N) .
Writing a very simple JavaScript program to sort an array and find number of swaps:
function findSwaps(){
let arr = [4, 3, 1, 2];
let swap = 0
var n = arr.length
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
if (arr[i] > arr[j]) {
arr[i] = arr[i] + arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j]
swap = swap + 1
}
}
}
console.log(arr);
console.log(swap)
}
for(int count = 1; count<=length; count++)
{
tempSwap=0; //it will count swaps per iteration
for(int i=0; i<length-1; i++)
if(a[i]>a[i+1])
{
swap(a[i],a[i+1]);
tempSwap++;
}
if(tempSwap!=0) //check if array is already sorted!
swap += tempSwap;
else
break;
}
System.out.println(swaps);
this is an O(n) solution which works for all inputs:
static int minimumSwaps(int[] arr) {
int swap=0;
boolean visited[]=new boolean[arr.length];
for(int i=0;i<arr.length;i++){
int j=i,cycle=0;
while(!visited[j]){
visited[j]=true;
j=arr[j]-1;
cycle++;
}
if(cycle!=0)
swap+=cycle-1;
}
return swap;
}
}
def minimumSwaps(arr):
swaps = 0
'''
first sort the given array to determine the correct indexes
of its elements
'''
temp = sorted(arr)
# compare unsorted array with the sorted one
for i in range(len(arr)):
'''
if ith element in the given array is not at the correct index
then swap it with the correct index, since we know the correct
index because of sorting.
'''
if arr[i] != temp[i]:
swaps += 1
a = arr[i]
arr[arr.index(temp[i])] = a
arr[i] = temp[i]
return swaps
I think this problem can be solved in O(N) if you notice that an element in the array needs to be removed and appended if:
There is a smaller element to the right or...
There is a smaller element to his left that needs to be removed and appended.
Then it's just about identifying elements that will need to be removed and appended. Here is the code:
static int minMoves(int arr[], int n) {
if (arr.length == 0) return 0;
boolean[] willBeMoved = new boolean[n]; // keep track of elements to be removed and appended
int min = arr[n - 1]; // keep track of the minimum
for (int i = n - 1; i >= 0; i--) { // traverse the array from the right
if (arr[i] < min) min = arr[i]; // found a new min
else if (arr[i] > min) { // arr[i] has a smaller element to the right, so it will need to be moved at some point
willBeMoved[i] = true;
}
}
int minToBeMoved = -1; // keep track of the minimum element to be removed and appended
int result = 0; // the answer
for (int i = 0; i < n; i++) { // traverse the array from the left
if (minToBeMoved == -1 && !willBeMoved[i]) continue; // find the first element to be moved
if (minToBeMoved == -1) minToBeMoved = i;
if (arr[i] > arr[minToBeMoved]) { // because a smaller value will be moved to the end, arr[i] will also have to be moved at some point
willBeMoved[i] = true;
} else if (arr[i] < arr[minToBeMoved] && willBeMoved[i]) { // keep track of the min value to be moved
minToBeMoved = i;
}
if (willBeMoved[i]) result++; // increment
}
return result;
}
It uses O(N) space.
#all , the accepted solution provided by #Itay karo and #NPE is totally wrong because it doesn't consider future ordering of swapped elements...
It fails for many testcases like:
3 1 2 5 4
correct output: 4
but their codes give output as 3...
explanation: 3 1 2 5 4--->1 2 5 4 3--->1 2 4 3 5--->1 2 3 5 4--->1 2 3 4 5
PS:i cann't comment there because of low reputation
Hear is my solution in c# to solve the minimum number of swaps required to short an array
At at time we can swap only 2 elements(at any index position).
public class MinimumSwaps2
{
public static void minimumSwapsMain(int[] arr)
{
Dictionary<int, int> dic = new Dictionary<int, int>();
Dictionary<int, int> reverseDIc = new Dictionary<int, int>();
int temp = 0;
int indx = 0;
//find the maximum number from the array
int maxno = FindMaxNo(arr);
if (maxno == arr.Length)
{
for (int i = 1; i <= arr.Length; i++)
{
dic[i] = arr[indx];
reverseDIc.Add(arr[indx], i);
indx++;
}
}
else
{
for (int i = 1; i <= arr.Length; i++)
{
if (arr.Contains(i))
{
dic[i] = arr[indx];
reverseDIc.Add(arr[indx], i);
indx++;
}
}
}
int counter = FindMinSwaps(dic, reverseDIc, maxno);
}
static int FindMaxNo(int[] arr)
{
int maxNO = 0;
for (int i = 0; i < arr.Length; i++)
{
if (maxNO < arr[i])
{
maxNO = arr[i];
}
}
return maxNO;
}
static int FindMinSwaps(Dictionary<int, int> dic, Dictionary<int, int> reverseDIc, int maxno)
{
int counter = 0;
int temp = 0;
for (int i = 1; i <= maxno; i++)
{
if (dic.ContainsKey(i))
{
if (dic[i] != i)
{
counter++;
var myKey1 = reverseDIc[i];
temp = dic[i];
dic[i] = dic[myKey1];
dic[myKey1] = temp;
reverseDIc[temp] = reverseDIc[i];
reverseDIc[i] = i;
}
}
}
return counter;
}
}
int temp = 0, swaps = 0;
for (int i = 0; i < arr.length;) {
if (arr[i] != i + 1){
// System.out.println("Swapping --"+arr[arr[i] - 1] +" AND -- "+arr[i]);
temp = arr[arr[i] - 1];
arr[arr[i] - 1] = arr[i];
arr[i] = temp;
++swaps;
} else
++i;
// System.out.println("value at position -- "+ i +" is set to -- "+ arr[i]);
}
return swaps;
This is the most optimized answer i have found. It is so simple. You will probably understand in one look through the loop. Thanks to Darryl at hacker rank.
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);