Interview Question
Country: India
@solvo4u : take an array ={1,7,8,20,30,36}
acc to you , ans is 7
But the correct ans is {7,8,36} and {1,20,30} i.e.0
can be done using the greedy approach
eg-{1,2,3,4,5,6,7,8,9,10}
first sort
-strt from ending
-let A,B be two subset
-place the next element in the subset with minimum sum till that point
A - 10 B- 9
B- 8
A-7
A-6
B-5
B-4
A-3
A-2
B- 1
@codz
That doesnt divide the 2 in equal halves....?
That solution will not work. Consider 1,5,6,20..
A-20
B-6
B-5
B-1
try this , not tested properly
int[] a = { 1, 2, 3, 4, 5, 1 };
int sm = 0;
for (int i = 0; i < a.length; i++)
sm += a[i];
boolean[] dp = new boolean[sm + 1];
dp[0] = true;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j <= sm - a[i]; j++)
if (dp[j])
dp[j + a[i]] = true;
}
for (int i = sm / 2; i >= 0; i--)
if (dp[i]) {
System.out.printf("set 1:%d set 2:%d\n", i, sm - i);
break;
not tested
int[] a = { 1, 2, 3, 4, 5, 1 };
int sm = 0;
for (int i = 0; i < a.length; i++)
sm += a[i];
boolean[] dp = new boolean[sm + 1];
dp[0] = true;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j <= sm - a[i]; j++)
if (dp[j])
dp[j + a[i]] = true;
}
for (int i = sm / 2; i >= 0; i--)
if (dp[i]) {
System.out.printf("set 1:%d set 2:%d\n", i, sm - i);
break;
}
I think we can do this using backtracking. First make a note of no.of elements in the array(say 'n') and the sum of all those elements(say 'sum').
At the start of the backtracking function check if the no.of elements in temp array are equal to half of the elements in original array. If so, then calculate the sum of temp array and compare with original array sum.
Temp array sum having least difference with half of original array sum is one of the two half arrays we are looking for. The other half array will be with remaining elements of original array not included in first half array.
Agree with you .
Could you please explain the backtracking function as I'm having problems while writing it .
Here is the backtracking function. I am printing only one half of the array. Hope you can print the other easily.
#include<stdio.h>
void halfArray(int a[], int b[], int c[], int pos, int start, int n, int sum, int currSum, int *minDiff)
{
int diff, i;
if(pos == n/2)
{
diff = ((sum/2) - currSum) > 0 ? (sum/2) - currSum : currSum - (sum/2);
if(*minDiff > diff)
{
for(i=0; i < pos; i++)
{
c[i] = b[i];
}
*minDiff = diff;
}
return;
}
for( i = start; i < n; i++)
{
b[pos] = a[i];
halfArray(a, b, c, pos+1, i+1, n, sum, currSum+a[i], minDiff);
}
}
void main()
{
int a[] = {1,2,3,4,5,6,7,8,9,10};
int b[10]={0}, c[10]={0};
int sum = 55; //given implicitly
int i;
int *minDiff;
clrscr();
*minDiff = 1000;
halfArray(a, b, c, 0, 0, 10, sum, 0, minDiff);
printf("\n One half is :\n");
for(i = 0; i < 5; i++)
printf("%d ", c[i]);
getch();
}
Here is the backtracking approach:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
void back(int *arr,int *sol,int N,int tillnow,int sumtillnow,int remainsum,int *finalsol)
{
static int mindiff=INT_MAX;
int i;
if(tillnow==N/2)
{
if(abs(sumtillnow-remainsum)<mindiff)
{
mindiff=abs(sumtillnow-remainsum);
for(i=0;i<N;i++)
finalsol[i]=sol[i];
}
}
else
{
for(i=0;i<N;i++)
{
if(!sol[i])
{
sol[i]=1;
back(arr,sol,N,tillnow+1,sumtillnow+arr[i],remainsum-arr[i],finalsol);
sol[i]=0;
}
}
}
}
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10},sol[10]={0},finalsol[10],i,sum=0;
for(i=0;i<10;i++)
sum+=arr[i];
back(arr,sol,10,0,0,sum,finalsol);
for(i=0;i<10;i++)
{
if(finalsol[i])
printf("%d ",arr[i]);
}
printf("\n");
for(i=0;i<10;i++)
{
if(!finalsol[i])
printf("%d ",arr[i]);
}
}
check it for array ={1,2,3,6}
your output is {3,6} and {1,2}
but the correct answer is {2,3} and {1,6}
@Barney, My program is working correctly for the input set given by you.
I request you to check it again. Can you provide the link where you tried it & it failed[like ideone]?
Here is the link where i have tried.
Please see: ideone.com/9c0A6
Note: Here i am not able to figure out why it is showing runtime error. The program is working perfectly under the ubuntu [gcc] platform without reporting any run-time error or segmentation fault[memory access violation exception].
Hope this works:
Assumptions are
All are positive elements
We have to split into 2 equal halves
Split it into 2 equal sets
Get the sum of each set
Set diff = |Sum(SetA) - Sum(SetB)|
While diff is > 1
Begin
-- Logic is try to reduce the difference between the two sets by exhanging 2 elements every time
DiferenceInDataToBeMoved = diff / 2
Find out the 2 elements one in SetA and another in SetB with diff <= DiferenceInDataToBeMoved
If 2 such elements are found
Exchange those 2 elemnts
Else
Return the 2 sets
Set diff = |Sum(SetA) - Sum(SetB)|
End
Return the 2 sets
Let us take an array which is sorted; eg:{1,2,3,6,8,9} - 4 elements
Te difference between the two subsets will be least when the elements are alternately put into the two different lists:
For example - first take 2 nos. - 1,2 =>put 1 in SetA and 2 in SetB [SetA{1} ; SetB{2}]
Then take the next two nos. - 3,6 => put 3 in SetB and 6 in SetA[SetA{1,6}, SetB{2,3}]
Then the next 2 - 8,9 => put 8 in SetA and 9 in SetB [SetA{1,6,8}; SetB{2,3,9}]
The logic is based on the fact that the difference will be least when the two nos. with least difference between them are put into different list. Sorting will automatically take care of this aspect. Now the reason behind alternating the insertions between the two sets is to keep the balance - if you inserted the smaller of the two nos. earlier in one set, compensate with a larger of the two nos. in the next iteration.
This is a tested code, it will work for all the cases, it is based on greedy algorithm where we start from index 1 and find the element which is nearest distance from it using O(n) time, then we put both these elements as used, now we use a par array of same size and maintain left and right index, now we see that if sumleft is less than sum right we put higher of the nearest neighbour in left part of partition that way trying to balance the sum of each half.
#include <stdio.h>
#include <stdlib.h>
int A[10] = {1,2,3,4,5,6,7,8,9,10};
bool used[10]={0};
int par[10]={0};
int mod(int n) {
if ( n>=0) return n;
else
return (-n);
}
int findMinDiff(int A[], bool used[], int idx, int N) {
int min = 1000; int minIndex = -1;
for (int i =0; i <N; i++) {
if(i==idx) continue;
if(used[i]==1) continue;
int diff = mod(A[idx]-A[i]);
if(diff < min){
min = diff;
minIndex = i;
}
}
printf("minimum distance neighbour for %d is %d with index %d and %d respectively\n",A[idx],A[minIndex],idx,minIndex);
return (minIndex);
}
int sumL(int left){
int sum=0;
for (int j = 0; j <left; j++){
sum=sum+par[j];
}
printf("sum left for left=%d is \n",sum);
return(sum);
}
int sumR(int right){
int sum=0;
for (int j = 9; j >right; j--){
sum=sum+par[j];
}
printf("sum right for right=%d is \n",sum);
return (sum);
}
int min(int a, int b) {
if ( a < b) return a;
else
return b;
}
int max(int a, int b) {
if ( a > b) return a;
else
return b;
}
void partitionSum(){
int M=10;
int left=0; int right=M-1;
for ( int i =0; i <M; i++ ){
if(used[i]==1) continue;
int j = findMinDiff(A,used,i,M);
used[j]=1; used[i]=1;
if (sumL(left) <= sumR(right)) {
par[left++] = max(A[i],A[j]);
par[right--] = min(A[i],A[j]);
}
else {
par[left++] = min(A[i],A[j]);
par[right--] = max(A[i],A[j]);
}
}
}
int main(){
partitionSum();
for(int i =0; i <10; i++)
printf("%d ",par[i]);
for(int k=0; k <10; k++)
printf("%d ",used[k]);
getchar();
return 0;
}
Partitioning is to be equal sized not arbitrary.
and, even if it is to be arbitrary your method will not work for:
A = [-1, 0 , 1]
Okay, even so, take A = [1, 5, 6, 10] Won't work !
He is forcing smallest and largest to be in different sets without any logic.
@Anonymous : You are right .
And it is also given that we've to divide the array in two equal halves .
1. Sort the array.
2. Pick odd indexed elements in the array for first set and even indexed elements for second set.
This solution will not work if arrays are not to be divided in two equal halves.
take an example . a[]={1,2,3,6}
acc to u a1={1,3} and a2={2,6};
but the ans should be a1={1,6} and a2={2,3};
i see..my earlier solution had flaw..
I think picking pairs of 1st and last(A1), 2nd and 2nd last(A2), 3rd and 3rd last(A1), 4th and 4th last(A2) .....till mid of array size.
logic: pair up max and min.
uses DP and more can be read on en.wikipedia.org/wiki/Partition_problem :
- salvo4u June 30, 2012