Interview Question: Longest Prefix That Contains An Equal Number Of Two Integers - c

I attempted to solve the following question in an online assessment for a technical interview, and failed. I have been thinking about the problem for a while now, and can't seem to find an answer that satisfies me:
You are looking for the longest leading fragment (prefix) of an array A in which there is an equal number of occurrences of X, and Y, where X and Y are integers.
For example, where X=7 and Y=42, the longest prefix where A=[6, 42, 11, 7, 1, 42] would be 4, because A[0]-A[4] contain the same number of X and Y.
Another example, X=6 and Y=13.
A=[13,13,1,6]. The function should return -1, because there is no prefix.
X=100, Y=63, and A=[100,63,1,6,2,13] should return 5.
My attempt at an answer in C:
int solution(int X, int Y, int A[], int N){
int result=-1;
int nX=0; //number of occurrences of X
int nY=0; //number of occurrences of Y
int i;
for(i=0;i<N;i++){//loop through the input array
if(A[i]==X)//occurrence of X
nX += 1;
/*
EDGE CASE BELOW: this should have been an if
statement, because X and Y could be the same
number. I know I missed this in the assessment,
but believe there is another issue, because I
failed almost all the test cases generated by the
assessment.
*/
else if(A[i]==Y)//occurrence of Y
nY += 1;
if((nX!=0)&& (nX==nY))//same number of X and Y
//and there is at least one occurence of each
result=i;//longest prefix is the index
}
return result;
}
Unfortunately, I was not able to generate a test case myself that failed, and the failure test cases are hidden on the assessment. Thus I can't provide much information that would be helpful.
I do know, that every time I failed, my program returned a -1 instead of the correct answer.
If any of you can see something wrong just through thinking through it, I would love to see what I am missing. Thanks!

If you've accurately described the requirements, then they don't specify an equal positive number of occurrences of X and Y. Zero is valid.
So this:
if((nX!=0)&& (nX==nY))//same number of X and Y
//and there is at least one occurence of each
result=i;//longest prefix is the index
}
should be this:
if(nX==nY)//same number of X and Y
result=i;//longest prefix is the index
}
without the check for nX!=0. So if X doesn't appear in the array and/or Y doesn't appear in the array, your code returns āˆ’1 unnecessarily.
Additionally, the requirements don't seem to guarantee that X and Y are distinct; if they're not, then your code returns āˆ’1, but according to a literal reading of the requirements, the answer would be Nāˆ’1.

After seeing your requirements and answers there is another change required to your code #Joshua.
The answer from #ruakh is also right but need one more change to handle other test cases.
You have to replace the "else if" condition to "if" condition for the occurrence of Y as shown in below code:
for(i=0;i<N;i++){
if(A[i]==X)
nX += 1;
if(A[i]==Y) //occurrence of Y
nY += 1;
Because, if "X" and "Y" have the same values and only "nX" will be counted, and "nY" is ignored with the "else if" condition. To tackle this situation you have to replace the "else if" condition with the "if" condition.
Sample: X=42, Y=42, and A=[42,63,42,6,2,13]
then with my condition, the above sample is handled perfectly.
I hope my answer solved or added more accuracy to your answer.

For starters never do any assignments in an interview. Interview is not an exam. It is a conversation of two equal participants. Ignore all firms that try to manipulate you and your time such a way.
Secondly, this function declaration
int solution(int X, int Y, int A[], int N);
is a declaration of a beginner.
First of all do not use upper case letters to name parameters.
Secondly the size of the array shall have the type size_t as and the return type of the function.
Thirdly the array should be the first parameter of the function and shall have the qualifier const.
Fourthly, declare variables in the smallest scope where they are used.
The function can be declared as it is shown in the demonstrative program. The function returns 0 if there is no such a prefix. You can change the return value either to the size of the array if there is no the prefix ot to ( size_t ) -1 as you like.
#include <stdio.h>
size_t largest_balanced_seq( const int a[], size_t n, int x, int y )
{
size_t last_index = 0;
for ( size_t i = 0, x_count = 0, y_count = 0; i < n; i++ )
{
x_count += a[i] == x;
y_count += a[i] == y;
if ( x_count != 0 && x_count == y_count )
{
last_index = i;
}
}
return last_index;
}
int main(void)
{
int a[] = { 6, 42, 11, 7, 1, 42 };
printf( "%zu\n", largest_balanced_seq( a, sizeof( a ) / sizeof( *a ), 7, 42 ) );
int b[] = { 100, 63, 1, 6, 2, 13 };
printf( "%zu\n", largest_balanced_seq( b, sizeof( b ) / sizeof( *b ), 100, 63 ) );
return 0;
}
The program output is
4
5
Take into account that it is much better when the function returns the length of the sub-sequence, that is when it specifiers a range like [0, N). For example such an approach is used throughout C++. So who gave you this assignment is not a very high qualified.:)

int solution(int X, int Y, int A[], int N){
int result=-1;
int nX=0; //number of occurrences of X
int nY=0; //number of occurrences of Y
int i;
for(i=0;i<N;i++){//loop through the input array
if(A[i]==X)//occurrence of X
nX += 1;
/*
EDGE CASE BELOW: this should have been an if
statement, because X and Y could be the same
number. I know I missed this in the assessment,
but believe there is another issue, because I
failed almost all the test cases generated by the
assessment.
*/
else if(A[i]==Y)//occurrence of Y
nY += 1;
if((nX!=0)&& (nX==nY))//same number of X and Y
//and there is at least one occurence of each
result=i;//longest prefix is the index
if (X==Y)
result =i;
}---this two lines of code is needed for the code correction
return result;
}

def solution(X, Y, A):
N = len(A)
result = -1
nX = 0
nY = 0
for i in range(N):
if A[i] == X:
nX += 1
if A[i] == Y:
nY += 1
if nX == nY:
result = i
if (X == Y and nX != 0):
break
return result
print( solution(7, 42, [6, 42, 11, 7, 1, 42]) )
print( solution(6, 13, [13, 13, 1, 6]) )
print( solution(100, 63, [100, 63, 1, 6, 2, 13]) )
print( solution(1, 1, [1]) )
print( solution(1, 1, [1, 1, 1]) )
print( solution(1, 1, [1, 2, 1]) )
print( solution(1, 1, [2, 2, 1]) )
print( solution(1, 1, [2, 1, 2]) )

def solution(X, Y, A):
N = len(A)
result = -1
nX = 0
nY = 0
for i in range(N):
if X==Y:
if A[i]==X:
nX += 1
if nX%2==0:
result=i
else:
if A[i] == X:
nX += 1
elif A[i] == Y:
nY += 1
if nX == nY:
result = i
return result
print( solution(7, 42, [6, 42, 11, 7, 1, 42]))
print( solution(6, 13, [13, 13, 1, 6]) )
print( solution(100, 63, [100, 63, 1, 6, 2, 13]) )
print( solution(1, 1, [1]) )
print( solution(1, 1, [1, 1, 1]) )
utput:
4
-1
5
-1
1

Related

Finding integer divisors of a set of numbers in C language

I want to do this in a function: How do I find out in a C program if a number is divisible by 2, 3, 4, 5, 6, 8, 9, 25 and 125 without using the % operator and using the divisibility rules? the base should be 10*
To use divisibility rules, you have to work with digits. Perhaps task assumes no division (at least in explicit form - you can extract digits from string representation)
For divisibility by 2, check whether the last digit is in set 0,2,4,6,8
For divisibility by 4, check whether the last digit + doubled previous one is in set 0,4,8. If result is larger than 10, repeat (88=>2*8+8=24=>2*2+4=8)
Similar situation for 8, but sum last + 2*previous + 4*second_from_the_end (512 => 4*5+2*1+2=24=>2*2+4=8)
For divisibility by 5, check whether the last digit is in set 0,5, similar situation for 25, 125
For divisibility by 3, sum all digits, repeat process until result becomes < 10. So-called "digit root" should be in set 0,3,6,9, similar situation for divisibility by 9.
For 6 check divisibilty by both 2 and by 3
I am not strong in C, so my example perhaps is very weird (ideone check)
#include <stdio.h>
int divby3(int n) {
char s[10];
do {
sprintf(s, "%d", n); //transform 72 to char buffer "72"
n = 0;
int i = 0;
while(s[i]) //until nil (end of string) found, we can also use for loop
n += s[i++] - 0x30; //get difference of current char and char "0"
}
while (n >= 10); //until 1-digit value
return (n==0) || (n==3) || (n==6) || (n==9);
}
int divby5(int n) {
char s[10];
int len = sprintf(s, "%d", n);
n = s[len - 1] - 0x30; //last digit
return (n==0) || (n==5);
}
int main(void) {
printf("%d", divby3(72)); //try 71
return 0;
}
A function that uses the a - (a / b * b) implementation of the modulus operator: (credit #MikeCat)
bool isDivisible(int a, int b)
{
if((a - (a / b * b)) == 0) return true;
return false;
}
Usage:
int main(void)
{
int a = 8;
int b = 4;
int c = 3;
bool res = isDivisible(a,b);
bool res2 = isDivisible(a,c);
return 0;
}
EDIT - to address question in comments:
"how can i represent such a program with the divisibility rules? Thank you for your code, i forgott to mention that i have to use the divisibility rules in each function"
The following shows how to pass in divisibility rules as an argument...
const int div_1[] = {2, 3, 4, 5, 6, 8, 9, 25, 125};
const int div_2[] = {7, 5, 17, 12, 11};
int main()
{
size_t size = 0;
size = sizeof div_1/sizeof div_1[0];
bool res = isDivisible(2*3*4*5*6*8*9*25*125, div_1, size);
size = sizeof div_2/sizeof div_2[0];
bool res2 = isDivisible(125, div_2, size);
return 0;
}
// numerator divisor array array size
bool isDivisible(long a, long div_rules[], size_t size)
{
//divisibility rules
const int divisors[] = {2, 3, 4, 5, 6, 8, 9, 25, 125};
for(int i = 0; i<size;i++)
{
if((a - (a / div_rules[i] * div_rules[i])) != 0) return false;
}
return true;
}

How do I solve the Coin Row problem using dynamic programming?

Coin-row problem: There is a row of n coins whose values are some positive integers C0, C2, . . . , Cn-1, not necessarily distinct. The goal is to pick up the maximum amount of money subject to the constraint that no two coins adjacent in the initial row can be picked up.
In the below code, n is the size of my array C(or number of coins), and this code returned the right result for the values [10, 2, 4, 6, 3, 9, 5] (the right result being 25). But when I run the same code for the values [3, 12, 10] or [3, 12, 10, 2], I got the wrong result. (The result should be 13 and 14 respectively for the set of values).
Please help me fix my code.
int max(int a, int b) {
if(a > b) return a;
return b;
}
int coin_row(int[] C, int n) {
if(n==1) return C[0];
if(n==2) return max(C[0],C[1];
int F[n], i;
F[0] = 0; F[1] = C[0];
for(i = 2;i < n;i++) {
F[i] = max(C[i] + F[i-2], F[i-1]);
}
return F[n-1];
}
The statement that all numbers will be positive makes things a little easier. From that information we can determine that we never want to skip over two consecutive numbers. We just have to calculate the best sequence possible using the first number and compare it with the best sequence possible using the 2nd number. This is ideal for recursion.
int coin_row(int *C, int n)
{
int first_total;
int second_total;
if (n == 0) return 0;
if (n == 1) return *C;
if (n == 2) return max(*C, *(C+1));
first_total = *C + coin_row(C+2, n-2);
second_total = *(C+1) + coin_row(C+3, n-3);
return(max(first_total, second_total));
}
By breaking down the problem into a sequence of pairs we treat the list as a large binary tree. At every pair you can choose either the first or second number. Calculate the total for each sub-tree and return the greatest value. For example with {10, 2, 4, 6, 3, 9, 5} your paths are:
10 2
/\ /\
4 6 6 3
/\ /\ /\ /\
3 9 9 5 9 5 5 -
Your algorithm is right but there are some bugs in implementation.
You are skipping the value at C[1] as your loop starts from i=2.
Since you are including 0 coin case in your F array, it needs to be of size n+1 for F[n] to exist. With the above corrections we arrive at:
int max(int a, int b) {
if(a > b) return a;
return b;
}
int coin_row(int* C, int n) {
if(n==1) return C[0];
if(n==2) return max(C[0],C[1]);
int F[n+1], i;
F[0] = 0; F[1] = C[0];
for(i = 2 ; i <= n + 1 ; i++) {
F[i] = max(C[i-1] + F[i-2], F[i-1]);
}
return F[n];
}

C best function to get split array on elements less, equals and greater than some value

I am programming in C. What is the best method (I mean in linear time) to spit array on elements less, equals and greater than some value x.
For example if I have array
{1, 4, 6, 7, 13, 1, 7, 3, 5, 11}
and x = 7 then it should be
{1, 4, 6, 1, 3, 5, 7, 7, 13, 11 }
I don't want to sort elements because I need more efficient way. Of course in this example in could be any permutation of {1, 4, 6, 1, 3, 5} and {13, 11}.
My thougt: less or grater than some element in array... In this example it is 7.
My function is:
int x = 7;
int u =0, z = 0;
for(int i=0; i<size-1; i++) // size - 1 because the last element will be choosen value
{
if(A[i] == x)
swap(A[i], A[u]);
else if(A[i] == x)
{
swap(A[i], A[n-(++z)]);
continue;
}
i++
}
for(int i = 0; i<z; i++)
swap(A[u+i],A[size-(++z)];
where u is number of current less elements, and z is the number of equals element
But if I have every elements in array equals there it doesn't work (size-(++z)) is going under 0
This is the so-called Dutch national flag problem, named after the three-striped Dutch flag. (It was named that by E.W. Dijkstra, who was Dutch.) It's similar to the partition function needed to implement quicksort, but in most explanations of quicksort a two-way partitioning algorithm is presented whereas here we are looking for a three-way partition. The classic quicksort partitioning algorithms divide the vector into two parts, one consisting of elements no greater than the pivot and the other consisting of elements strictly greater. [See note 1]
The wikipedia article gives pseudocode for Dijkstra's solution, which (unlike the classic partition algorithm usually presented in discussions of quicksort) moves left to right through the vector:
void dutchflag(int* v, size_t n, int x) {
for (size_t lo = 0, hi = n, j = 0; j < hi; ) {
if (v[j] < x) {
swap(v, lo, j); ++lo; ++j;
} else if (v[j] > x) {
--hi; swap(v, j, hi);
} else {
++j;
}
}
There is another algorithm, discovered in 1993 by Bentley and McIlroy and published in their paper "Engineering a Sort Function" which has some nice diagrams illustrating how various partitioning functions work, as well as some discussion about why partitioning algorithms matter. The Bentley & McIlroy algorithm is better in the case that the pivot element occurs infrequently in the list while Dijkstra's is better if it appears often, so you have to know something about your data in order to choose between them. I believe that most modern quicksort algorithms use Bentley & McIlroy, because the common case is that the array to be sorted has few duplicates.
Notes
The Hoare algorithm as presented in the Wikipedia Quicksort article, does not rearrange values equal to the pivot, so they can end up being present in both partitions. Consequently, it is not a true partitioning algorithm.
You can do this:
1) Loop through the array, if element is less than x then put in new array1.
2)If element is greater than x then put in new array2.
This is linear time O(n)
I tried something like this below which I think is O(n). Took me a little bit to work the kinks out but I think it's pretty similar to the dutchflag answer above.
My ouptput
a.exe
1 4 6 5 3 1 7 7 11 13
1 4 5 6 3 1 7 7 7 11 13
code:
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
void order(int * list, int size, int orderVal)
{
int firstIdx, lastIdx, currVal, tempVal;
firstIdx = 0;
lastIdx = size-1;
for ( ;lastIdx>firstIdx;firstIdx++)
{
currVal = list[firstIdx];
if (currVal >= orderVal)
{
tempVal = list[lastIdx];
list[lastIdx] = currVal;
lastIdx--;
list[firstIdx] = tempVal;
if (tempVal >= orderVal)
firstIdx--;
}
}
lastIdx = size-1;
for( ;lastIdx>firstIdx && middleNum>0;lastIdx--)
{
currVal = list[lastIdx];
if (currVal == orderVal)
{
tempVal = list[firstIdx];
list[firstIdx] = currVal;
firstIdx++;
list[lastIdx] = tempVal;
if (tempVal == orderVal)
lastIdx++;
}
}
}
int main(int argc, char * argv[])
{
int i;
int list[] = {1, 4, 6, 7, 13, 1, 7, 3, 5, 11};
int list2[] = {1, 4, 7, 6, 7, 13, 1, 7, 3, 5, 11};
order(list, ARRAY_SIZE(list), 7);
for (i=0; i<ARRAY_SIZE(list); i++)
printf("%d ", list[i]);
printf("\n");
order(list2, ARRAY_SIZE(list2), 7);
for (i=0; i<ARRAY_SIZE(list2); i++)
printf("%d ", list2[i]);
}
Here is an example using a bubble sort. Which type of sort algorithm is best, is up to you, this is just to demonstrate. Here, I treat values < x as -1, values == x as 0, values > x as 1.
Note that the elements < x and those > x are still in the same sequence.
#include <stdio.h>
int main(void)
{
int array[] = { 1, 4, 6, 7, 13, 1, 7, 3, 5, 11 };
int x = 7;
int len = sizeof array / sizeof array[0];
int i, j, m, n, tmp;
for (i=0; i<len-1; i++) {
m = array[i] < x ? -1 : array[i] == x ? 0 : 1;
for (j=i+1; j<len; j++) {
n = array[j] < x ? -1 : array[j] == x ? 0 : 1;
if (m > n) {
tmp = array[i]; // swap the array element
array[i] = array[j];
array[j] = tmp;
m = n; // and replace alias
}
}
}
for(i=0; i<len; i++)
printf("%d ", array[i]);
printf("\n");
return 0;
}
Program output:
1 4 6 1 3 5 7 7 13 11

array validation - without using an auxiliary array

This question is for real brainiacs, cause it should be done without an auxiliary array
and has to be most efficient!
C program - needs to recieve an array with X numbers
(suppose X=4 array : 5,4,3,2)
and check if the array has all the numbers from 0 to X-1
(If X is 44 it needs to check if all numbers between 0 to 43 inside the array).
It has to be super efficient - I mean, running on the array 43 times is not an option!
Do you have any idea how to do this?? I'm trying to figure this one for hours without any success!!
It has to be O(n).
If changing order of the array is allowed you can use in-place sort algorithm, then check if for some i:
array[i] == array[i+1]
Time complexity can be O(n*lg n) then.
You can simplify the problem to finding duplicates.
Proof:
If the length of the array is not X => There are numbers missing. You can easily check that in O(1) or O(n).
Else => you have either all the correct numbers or there are duplicates.
Having that, you can use this implementation: Finding duplicates in O(n) time and O(1) space. Also make sure you check the bounds of the array. If the numbers are not inside the bounds, the array contains incorrect numbers.
This leads to an O(n) solution.
Sort both arrays (is in O(n log n)). Then treat both arrays as queues:
If the head elements of both queues are equal, print one of them and pop both.
If the head elements are not equal, pop the smaller.
Repeat.
You could sort the array, and then scan through it once. That should give you O(N log N) performance, better than the O(N^2) you'd need for the naive approach.
foreach(int i in array)
{
int count = 0;
foreach(int i2 in array)
{
if(i == i2)
{
count++;
}
}
if(count > 1)
{
return false;
}
}
return true;
See some brilliant answers here, a C++ implementation of the #caf's answer could be
bool stop=true;
// first place the element i at location A[i], i.e 4 at A[4]
for(int i = 0; i<n; i++) {
while (A[A[i]] != A[i]){
swap(A[i], A[A[i]])
}
}
// than u can have the second loop which does the decision
for(int i = 0; i<n && !stop; i++) {
if (A[i] != i){
stop = true;
}
}
if (stop)
printf("duplicate");
else
printf("not duplicate)
an O(n) solution: The algorithm tries to put each element in the array onto its correct position, e.g. 1 onto a[0] and 2 onto a[1], by swapping with the element occupies the origin position.
at first, i = 1, a[i - 1] = 1, it's ok and nothing will be touched
i = 1
a = 1 6 3 4 5 7 1
then, i = 2, a[i - 1] = 6 != 2, then swap a[i - 1] and a[6 - 1]
i = 2
a = 1 7 3 4 5 6 1
then, i is still 2, but a[i - 1] == 7 != 2, then swap a[i - 1] and a[7 - 1]
i = 2
a = 1 1 3 4 5 6 7
now i = 2 but we see that a[i - 1] == a[1 - 1], thus we find the duplicate
full source:
#include <stdio.h>
int main() {
int a[7] = {1, 6, 3, 4, 5, 7, 1};
int i, t;
for (i = 0; i < 7; ++i) {
while (a[i] != i + 1) {
if (a[i] == a[a[i] - 1]) {
printf("duplicate: %d\n", a[i]);
goto out;
}
t = a[i];
a[i] = a[a[i] - 1];
a[t - 1] = t;
}
}
printf("no duplicate\n");
out:
return 0;
}
You can use a modified merge operation (like the one used in mergesort) if the arrays are both sorted.
You can do [on average case] better then the suggested O(nlogn) solution.
There is an O(n) armotorized average case solution using hash tables:
hash <- new hash set
for each e in A:
hash.add(e)
for each e in B:
if hash.contains(e): print e
You can overcome printing twice elements if they appear twice in B by storing an additional hash set of 'printed' elements.
If latency or worst case performacne is an issue, use one of the sort and iterate solutions suggested.
Sort the smaller and use binary search to search it for each element in the larger. That way, you can do it in O((n1+n2)*log(n1)) where n1, n2 are the sizes of the arrays (n1 is the smaller).
I don't understand what I'm missing in this question but AFAIK I don't see a reason why any (reasonable) solution should be anything more-/worse- than O(n) time (and space) complexity.
From the above comments and answers, I understand the following:
Negative numbers : I'm not sure whether negative numbers are allowed or not. The OP says check if all the array has all the numbers from 0 to X-1. So anything less than 0 is not expected in the array. So I assume negative numbers are not allowed
Duplicate numbers : referring to the same quote from the OP - check if all the array has all the numbers from 0 to X-1 I guess if X is the size of the array and all numbers from 0 to X-1 should be present, the I guess no duplicate numbers are allowed.
So making the above assumptions, we can use one bit to check whether i (0 <= i <= X-1) is present or not. If i is duplicate then it will fail mentioning that there is a duplicate number.
It scans the whole array one time - O(n) and just uses one bit per element, so X is 10 the X bits are needed - for example consider we need to handle 1000000 elements and sizeof(int) is 4 then we need 3.82M of memory to hold the array elements and only 0.48M is used for storing the presence of an element.
#include <stdio.h>
#define X 10
#define MIN 0
#define MAX X-1
int main(void)
{
//int arr[X] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//int arr[X] = {6, 7, 8, 9, 0, 5, 3, 2, 11, 12};
//int arr[X] = {1, 1, 2, 4, 5, 6, 7, 8, 2, 2};
int arr[X] = {1, 3, 2, 4, 5, 6, -7, 8, 2, 2};
/* if X is more than sizeof(int) then change
the flag type to a wider one! */
int flag = 0;
int i;
for(i=0 ;i<X ; i++) {
if (arr[i] >= MIN && arr[i] <= MAX) {
if (flag & 1<<arr[i]) {
printf("Duplicate found : %d \n", arr[i]);
return -1;
}
flag |= 1<<arr[i];
} else {
printf("Failure at %d : %d \n", i, arr[i]);
return -1;
}
}
printf("Success \n");
return 0;
}
Read this for an answer - array validation - without using an auxiliary array
an array of n elements which contains elements from 0 to n-1, with any of these numbers appearing any number of times.
For example, let n be 7 and array be {1, 2, 3, 4, 5, 4, 6}, the answer should FALSE
Isn't the above statements contradict themselves?!

Interview test - rearrange the array [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Reordering of array elements
In given array of elements like [a1,a2,a3,..an,b1,b2,b3,..bn,c1,c2,c3,...cn] Write a program to merge them like [a1,b1,c1,a2,b2,c2,...an,bn,cn].
We have to do it in O(1) extra space.
Sample Testcases:
Input #00:
{1,2,3,4,5,6,7,8,9,10,11,12}
Output #00:
{1,5,9,2,6,10,3,7,11,4,8,12}
Explanation:
Here as you can notice, the array is of the form
{a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4}
EDIT:
I got it in Amazon placement test. Have been trying it for a long time.
PLease provide psuedo code. What i tried is finding new position p for second element e(1st is already at correct position), inserting e at p and repeating the same for the old element at position p. But this is ending in a cycle.
I tried detecting cycle and incrementing the starting position by 1. But even this is not working.
EDIT2:
#include <iostream>
using namespace std;
int pos(int i, int n)
{
if(i<n)
{
return 3*i;
}
else if(i>=n && i<2*n)
{
return 3*(i-n) + 1;
}
else if(i>=2*n && i<3*n)
{
return 3*(i-2*n) + 2;
}
return -1;
}
void printn(int* A, int n)
{
for(int i=0;i<3*n;i++)
cout << A[i]<<";";
cout << endl;
}
void merge(int A[], int n)
{
int j=1;
int k =-1;
int oldAj = A[1];
int count = 0;
int temp;
while(count<3*n-1){
printn(A,n);
k = pos(j,n);
temp = A[k];
A[k] = oldAj;
oldAj = temp;
j = k;
count++;
if(j==1) {j++;}
}
}
int main()
{
int A[21] = {1,4,7,10,13,16,19,2,5,8,11,14,17,20,3,6,9,12,15,18,21};
merge(A,7);
cin.get();}
This is the so called in-place in-shuffle algorithm, and it's an extremely hard task if you want to do it efficiently. I'm just posting this entry so people don't post their so called "solutions" claiming that it can be extended to work with O(1) space, without any proof...
Here is a paper for a simpler case when the list is in the form: a1 a2 a3 ... an b1 b2 b3 .. bn:
http://arxiv.org/PS_cache/arxiv/pdf/0805/0805.1598v1.pdf
Here's is a description of an algorithm with 3 elements of extra space and O(n^2) complexity:
sa, sb, sc are, respectively, next source index for a, b and c sequences.
d is the copy destination index.
On each iterarion:
Copy elements at sa, sb and sc to temporary storage
Shift the array elements to the left to fill in the now vacant indices sa, sb and sc
This leaves three empty positions at d
Copy the three elements from temporary storage to empty positions.
Example (dots indicate "empty" positions):
First iteration:
copy to tmp: ., 2, 3, 4, ., 6, 7, 8, .,10,11,12
1 5 9
shift: ., ., ., 2, 3, 4, 6, 7, 8,10,11,12
copy to dst: 1, 5, 9, 2, 3, 4, 6, 7, 8,10,11,12
Second iteration:
copy to tmp: 1, 5, 9, ., 3, 4, ., 7, 8, .,11,12
2 6 10
shift: 1, 5, 9, ., ., ., 3, 4, 7, 8,11,12
copy to dst: 1, 5, 9, 2, 6,10, 3, 4, 7, 8,11,12
Third iteration:
copy to tmp: 1, 5, 9, 2, 6,10, ., 4, ., 8, .,12
3 7 11
shift: 1, 5, 9, 2, 6,10, ., ., ., 4, 8,12
copy to dst: 1, 5, 9, 2, 6,10, 3, 7 11, 4, 8,12
EDIT:
And here's a working program (it takes a bit more than a verbal description :)))
#include <stdio.h>
#define N 4
int a[] = {1, 2,3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
void
rearrange ()
{
int i;
int d;
int sa, sb, sc;
int tmp [3];
d = 0;
sa = 0;
sb = sa + N;
sc = sb + N;
while (sc < N*3)
{
/* Copy out. */
tmp [0] = a [sa];
tmp [1] = a [sb];
tmp [2] = a [sc];
/* Shift */
for (i = sc; i > sb + 1; --i)
a [i] = a [i - 1];
for (i = sb + 1; i > sa + 2; --i)
a [i] = a [i - 2];
sa += 3;
sb += 2;
sc++;
/* Copy in. */
a [d++] = tmp [0];
a [d++] = tmp [1];
a [d++] = tmp [2];
}
}
int
main ()
{
int i;
rearrange ();
for (i = 0; i < N*3; ++i)
printf ("%d\n", a [i]);
putchar ('\n');
return 0;
}
Appears to work. shrug
This is the general solution to the problems like yours.
First of all, for each source index you know the destination index. Now, you go like that:
Take the first item. Find its final place. Memorize the item at that place, and store the first item there. Now, find the place where the memorized item belongs to, and put that item there, memorizing that replaced item. Continue the process until it hits the place of the first item (obviously).
If you've replaced all the items, you are finished. If not, take the first non-transferred item and continue repeat the procedure from step 1, starting with that item.
You'll need to mark which items you've transferred already. There are different ways to do it: for example, you can use one bit from the item's storage.
Okay, the solution above is not exactly O(1), as it requires N extra bits. Here is the outline of O(1) solution by place, though less efficient:
Consider the items a1, b1, c1. They need to be located at the first 3 places of the result. So we are doing the following: remembering a1, b1, c1, compacting the array except these three items to the back (so it looks like this: , , , a2, a3, ..., an, b2, b3, ..., bn, c2, c3, ..., cn), and put the items a1, b1, c1 at their places at the beginning. Now, we found the place for the first 3 items, so continue this procedure for a2, b2, c2 and so on.
Edit:
let's consider the time complexity of the outline above. Denote list size 3*n. We need n steps. Each single compactification of the list can be done in one pass, and therefore is O(n). All the other operations inside a step are O(1), so we get altogether n * O(n) = O(n^2) complexity. This is far from the best solution, however, as #yi_H mentions, linear-time solution requires heavy usage of more-or-less advanced mathematics.
I can't find any O(n) algorithm but this is O(n^2) in-place one, I'll move triples to the last each time code is tested by given input, is in C#, may be is buggy, If is so let me know:
int[] a = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
int m = a.Length / 3;
int firstB = a[m];
for (int i = m-1; i > 0; i--)
{
int second = a[3 * m - 3];
int third = a[3 * m - 2];
//a[i + 2 * m] = a[i +2 * m];
a[3 * m - 2] = a[2 * m - 1];
a[3 * m - 3] = a[m - 1];
for (int j = m - 1; j < 2 * m - 1; j++)
{
a[j] = a[j + 1];
}
for (int j = 2 * m - 2; j < 3 * m - 3; j++)
{
a[j] = a[j + 2];
}
a[3 * m - 5] = second;
a[3 * m - 4] = third;
m--;
}
a[1] = firstB;
Here we have x * y numbers:
a_11, a_12, ..., a_1x,
a_21, a_22, ..., a_2x,
...
a_y1, a_y2, ..., a_yx
then the number a_ij has the index i*x + j in an array;
after your program, the new index will be
j * y + i
in your interview
{a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4}
x is 4, and y is 3,
so with the index ``n''
i = (n - (n % 4)) / 4;
j = n % 4;
now you can calculate the new index with i, j, x, y.
Good Luck.

Resources