Related
This is the task I have got:
I need to write a function (not recursive) which has two parameters.
An array of integers.
An integer representing the size of the array.
The function will move the duplicates to an end of the array.
And will give the size of the different digits.
Example:
5 , 2 , 4 , 5 , 6 , 7 , 2, n = 7
we will get back 5 , 2 , 4 , 6 , 7 , 5 , 2 and 5
We must keep the original sort as it is (which means like in example 5 must)
It does not matter how we sort the duplicates ones but just keep the sort for the original array as it is)
The function has to print the number of different digits (like in example 5)
The the input range of numbers in array [-n,n]
I can only use 1 additional array for help.
It has to be O(n)
I tried it so many times and feel like am missing something. Would appreciate any advice/suggestions.
int moveDup(int* arr, int n)
{
int* C = (int*)calloc(n * 2 + 1, sizeof(int));
assert(C);
/*int* count = C + n;*/
int *D = arr[0];
int value = 0, count = 0;
for (int i = 0; i < n; i++)
{
value = arr[i];
if (C[value + n] == 0)
{
*D = arr[i];
D++;
count++;
}
C[value + n] = C[value + n] + 1;
}
while (1 < C[value + n])
{
*D = i;
D++;
C[value + n]--;
}
free(C);
return count;
}
This algorithm will produce the required results in O(n) arithmetic complexity:
Input is an array A with n elements indexed from A0 to An−1 inclusive. For each Ai, −n ≤ Ai ≤ n.
Create an array C that can be indexed from C−n to C+n, inclusive. Initialize C to all zeros.
Define a pointer D. Initialize D to point to A0.
For 0 ≤ i < n:
If CAi=0, copy Ai to where D points and advance D one element.
Increment CAi.
Set r to the number of elements D has been advanced from A0.
For −n ≤ i ≤ +n:
While 1 < CAi:
Copy i to where D points and advance D one element.
Decrement CAi.
Release C.
Return r. A contains the required values.
A sample implementation is:
#include <stdio.h>
#include <stdlib.h>
#define NumberOf(a) (sizeof (a) / sizeof *(a))
int moveDuplicates(int Array[], int n)
{
int *memory = calloc(2*n+1, sizeof *Array);
if (!memory)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
int *count = memory + n;
int *destination = Array;
for (int i = 0; i < n; ++i)
// Count each element. If it is unique, move it to the front.
if (!count[Array[i]]++)
*destination++ = Array[i];
// Record how many unique elements were found.
int result = destination - Array;
// Append duplicates to back.
for (int i = -n; i <= n; ++i)
while (0 < --count[i])
*destination++ = i;
free(memory);
return result;
}
int main(void)
{
int Array[] = { 5, 2, 4, 5, 6, 7, 2 };
printf("There are %d different numbers.\n",
moveDuplicates(Array, NumberOf(Array)));
for (int i = 0; i < NumberOf(Array); ++i)
printf(" %d", Array[i]);
printf("\n");
}
here is the right answer, figured it out by myself.
int moveDup(int* arr, int n)
{
int* seen_before = (int*)calloc(n * 2 + 1, sizeof(int));
assert(seen_before);
int val = 0, count = 0, flag = 1;
int j = 0;
for (int i = 0; i < n; i++)
{
val = arr[i];
if (seen_before[arr[i] + n] == 0)
{
seen_before[arr[i] + n]++;
count++;
continue;
}
else if (flag)
{
j = i + 1;
flag = 0;
}
while (j < n)
{
if (seen_before[arr[j] + n] == 0)
{
count++;
seen_before[arr[j] + n]++;
swap(&arr[i], &arr[j]);
j++;
if (j == n)
{
free(seen_before);
return count;
}
break;
}
/*break;*/
j++;
if (j == n)
{
free(seen_before);
return count;
}
}
}
}
second right answer
int* mem = (int*)calloc(2 * n + 1, sizeof * arr);
assert(mem);
int* count = mem + n;
int* dest = arr;
for (i = 0; i < n; ++i)
{
if (count[arr[i]]++ == 0)
{
*dest = arr[i];
*dest++;
}
}
res = dest - arr;
for (i = -n; i <= n; ++i)
{
while (0 < --count[i])
{
*dest++ = i;
}
}
free(mem);
return res;
I have a int array that contains five random numbers. I am trying to check if three of the numbers match.
int die[5] = {2, 3, 5, 2, 1};
int kind = 0;
int score = 0;
int i = 0;
int x = 0;
for (i; i <= 4; i++) {
for (x; x <= 4; x++) {
if (die[i] == die[x]) {
kind++;
score += die[i];
}
}
}
The issue I am running into is the very first case it will compare itself to itself. Which will always come back true. And if I add a +1 to the index, it will end up going out of bounds.
If I start at 1 instead of 0, then when it goes to the second digit, it will return the same once it checks itself against the 2nd number(itself).
You could check if i equals j and just continue; your loop.
for(i=0; i<=4; i++){
// you can set x=i+1 and skip some numbers
for(x=0; x<=4; x++){
if(i==x)
continue;
if (die[i] == die[x]) {
kind++;
score += die[i];
}
}
}
EDIT:
There are simpler ways of doing this (checking if 3 numbers are equal), but if you just want to skip an iteration, use continue.
int die[5] = {2, 3, 5, 2, 1};
int kind = 0;
int score = 0;
for (i = 0; i < 4; i++) { // last check will be die[3] == die[4] to avoid
// die[4] == die[4]
for (x = i + 1 ; x < 5; x++) { // it always checks with the next element
if (die[i] == die[x]) {
kind++;
score += die[i];
}
}
}
DISCLAIMER:
Described problem looks like a task from a competition. I'm not participating in any of them, I'm not aware about any ongoing competitions, which might involve the problem. If there are any of them, I'll close the question to stay fair!
I have a problem:
given an array A of values and integer K, split A into exactly K non-overlapping contiguous subarrays in such way that difference between a subarray with minimal and a subarray maximum sums is minimal. It is allowed to rotate A by any number in any direction.
Consider an example:
Input: A = [5 1 1 1 3 2], K = 3
Output: [5][1 1 1][3 2], maximum sum = 5, minimum sum = 3, result = 2
I have partially working code (terribly ugly, my bad, but it does not meant to be production quality):
#include <climits>
#include <cstdio>
#include <cstring>
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = INT_MAX;
// consider all possible rotations/shifts
for(int offset = 0; offset < n; ++offset) {
for(int l_min = 0; l_min < n; ++l_min) {
for(int r_min = l_min; r_min < n; ++r_min) {
// check minimal sum subarray
int min_sum = sum (deps, l_min, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = 0;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = 0; l_max < n; ++l_max) {
for(int r_max = 0; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max, r_max);
if (max_sum >= min_sum) dp[p][r_max] = max(dp[p-1][l_max], max_sum);
} // l_maxs
} // r_maxs
} // partitions
// printing dp
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == 0) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
} // start min sum seg
//break;
} // cuts
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}
The idea is simple: assume that current partition has minimal sum, enumerate all possible maximal partitions, setup dynamic programming for generating maximum sum with minimal value, check for difference. Total complexity: O(K*N^4).
My problem is that it fails some tests and I'm stuck with troubleshooting it. Could someone help me with it?
Failed test, for example:
N = 4, K = 2, A = [6 13 10 2]
UPDATE
This version should fix some previous issues. First, it removes wasteful loop over "offsets" and adds just an array rotation in the end of l_min loop. Second, I've noticed, that dp can't be initialized with 0 - this is minimization task, so it should be initialized with some large value (depends on a problem's constants, max_value here already is out of value domain). Finally, intervals should not overlap anymore - each sum exclude left end of an interval. However, it still does not produce expected results.
#include <climits>
#include <cstdio>
#include <cstring>
const int max_value = 200000;
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = max_value;
for(int l_min = 0; l_min < n; ++l_min) {
for(int r_min = l_min; r_min < n; ++r_min) {
int min_sum = sum (deps, l_min+1, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = max_value;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = 0; l_max < n; ++l_max) {
for(int r_max = l_max; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max+1, r_max);
if (max_sum >= min_sum) dp[p][r_max] = max(dp[p-1][l_max], max_sum);
} // l_maxs
} // r_maxs
} // partitions
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == max_value) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
// rotate an array to consider different starting points
int tmp[n];
for (int i = 0; i < n; ++i) {
int new_idx = i + n + 1;
tmp[new_idx % n] = deps[i];
}
for(int i = 0; i < n; ++i) deps[i] = tmp[i];
} // start min sum seg
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}
Ok, I think I did it!
The idea is following: we assume that minimum sum interval always starts from 0. Then we start to enumerate maximum sum intervals, starting from the right boundary of the minimal interval. We build DP problem for current max interval to determine a minimum maximal sum. After that you update result and rotate an array by one.
My code is not perfect in a way that I compute current sums each iteration. One can pre-compute them and just index them each time.
This code might have some bugs, but it passes all test that I have.
#include <climits>
#include <cstdio>
#include <cstring>
const int max_value = 200000;
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = max_value;
for(int offset = 0; offset < n; ++offset) {
int l_min = 0;
for(int r_min = l_min; r_min < n; ++r_min) {
int min_sum = sum (deps, l_min, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = max_value;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = r_min; l_max < n; ++l_max) {
for(int r_max = l_max; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max+1, r_max);
if (max_sum >= min_sum) {
dp[p][r_max] = min(dp[p][r_max], max(dp[p-1][l_max], max_sum));
}
} // l_maxs
} // r_maxs
} // partitions
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == max_value) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
int tmp[n];
for (int i = 0; i < n; ++i) {
int new_idx = i + n - 1;
tmp[new_idx % n] = deps[i];
}
for(int i = 0; i < n; ++i) deps[i] = tmp[i];
} // start min sum seg
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}
Solution without rotations:
1) Compute max M and total S of the array - O(n)
2) Let there be a function F(P), which returns True if it is possible to get a Sum P or less with k (>= 0) partitions still remaining.
3) Do a binary search on range(M, S) using F. - O(log(S-M))
4) Logic behind F: Fill a bucket till it's not greater than S/K. Then move onto next bucket. If there are still items remaining and no buckets remaining, then the answer is false - O(n)
Time Complexity = O(n) + O(n) * (log(S-M)) = O(n*log(S-M))
Solution with Rotations:
For all rotations in [0, 1, ... N-1], compute min sum.
Total Time Complexity = O(n) * O(nlog(S-M)) = O(n^2*log(S-M))
Now that you've got your code working, here's an alternative method :)
Consider that for each k, we can pair a sum growing from A[i] to the left (sum A[i-j..i]) with all available intervals recorded for f(k-1, i-j-1) and update them - for each interval, (low, high), if the sum is greater than high, then new_interval = (low, sum) and if the sum is lower than low, then new_interval = (sum, high); otherwise, the interval stays the same. For example,
i: 0 1 2 3 4 5
A: [5 1 1 1 3 2]
k = 3
i = 3, j = 0
The ordered intervals available for f(3-1, 3-0-1) = f(2,2) are:
(2,5), (1,6) // These were the sums, (A[1..2], A[0]) and (A[2], A[0..1])
Sum = A[3..3-0] = 1
Update intervals: (2,5) -> (1,5)
(1,6) -> (1,6) no change
Now, we can make this iteration much more efficient by recognizing and pruning intervals during the previous k round.
Watch:
A: [5 1 1 1 3 2]
K = 1:
N = 0..5; Intervals: (5,5), (6,6), (7,7), (8,8), (11,11), (13,13)
K = 2:
N = 0: Intervals: N/A
N = 1: Intervals: (1,5)
N = 2: (1,6), (2,5)
Prune: remove (1,6) since any sum <= 1 would be better paired with (2,5)
and any sum >= 6 would be better paired with (2,5)
N = 3: (1,7), (2,6), (3,5)
Prune: remove (2,6) and (1,7)
N = 4: (3,8), (4,7), (5,6), (5,6)
Prune: remove (3,8) and (4,7)
N = 5: (2,11), (5,8), (6,7)
Prune: remove (2,11) and (5,8)
For k = 2, we are now left with the following pruned record:
{
k: 2,
n: {
1: (1,5),
2: (2,5),
3: (3,5),
4: (5,6),
5: (6,7)
}
}
We've cut down the iteration of k = 3 from a list of n choose 2 possible splits to n relevant splits!
The general algorithm applied to k = 3:
for k' = 1 to k
for sum A[i-j..i], for i <- [k'-1..n], j <- [0..i-k'+1]:
for interval in record[k'-1][i-j-1]: // records are for [k'][n']
update interval
prune intervals in k'
k' = 3
i = 2
sum = 1, record[2][1] = (1,5) -> no change
i = 3
// sums are accumulating right to left starting from A[i]
sum = 1, record[2][2] = (2,5) -> (1,5)
sum = 2, record[2][1] = (1,5) -> no change
i = 4
sum = 3, record[2][3] = (3,5) -> no change
sum = 4, record[2][2] = (2,5) -> no change
sum = 5, record[2][1] = (1,5) -> no change
i = 5
sum = 2, record[2][4] = (5,6) -> (2,6)
sum = 5, record[2][3] = (3,5) -> no change
sum = 6, record[2][2] = (2,5) -> (2,6)
sum = 7, record[2][1] = (1,5) -> (1,7)
The answer is 5 paired with record[2][3] = (3,5), yielding the updated interval, (3,5). I'll leave the pruning logic for the reader to work out. If we wanted to continue, here's the pruned list for k = 3
{
k: 3
n: {
2: (1,5),
3: (1,5),
4: (3,5),
5: (3,5)
}
}
I finally solved this question : Split array into three subarrays, It may help you.
here I'm splitting a array into three sub-array with java.
package com.array2;
public class SplitArray {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = { 1, 2, 3, 5, 4, 6, 9, 8, 15, 52, 4, 6, 89 };
splitArray(a);
}
private static void splitArray(int[] a) {
// TODO Auto-generated method stub
int a_l = a.length;
int[] a1 = new int[a.length / 3];
int[] a2 = new int[a.length / 3];
int[] a3 = new int[a.length / 3 + a.length % 3];
for (int i = 0; i < a3.length; i++) {
if (i < a1.length) {
a1[i] = a[i];
a2[i] = a[a1.length + i];
a3[i] = a[a1.length + a2.length + i];
} else {
a3[i] = a[a1.length + a2.length + i];
}
}
}
}
I should make new array out of existing one (ex. 1 0 4 5 4 3 1) so that the new one contains digits already in existing array and the number of their appearances.
So, the new one would look like this: 1 2 0 1 4 2 5 1 3 1 (1 appears 2 times, 0 appears 1 time.... 3 appears 1 time; the order in which they appear in first array should be kept in new one also); I know how to count no. of times a value appears in an array, but how do I insert the no.of appearances? (C language)
#include <stdio.h>
#define max 100
int main() {
int b, n, s, i, a[max], j, k;
printf("Enter the number of array elements:\n");
scanf("%d", &n);
if ((n > max) || (n <= 0)) exit();
printf("Enter the array:\n");
for (i = 0; i < n; i++)
scanf("%d", a[i]);
for (i = 0; i < n; i++) {
for (j = i + 1; j < n;) {
if (a[j] == a[i]) {
for (k = j; k < n; k++) {
a[k] = a[k + 1];
}}}}
//in the last 5 rows i've tried to compare elements, and if they are same, to increment the counter, and I've stopped here since I realised I don't know how to do that for every digit/integer that appears in array//
If you know that the existing array consists of digits between 0 and 9, then you can use the index of the array to indicate the value that you are incrementing.
int in[12] = {1,5,2,5,6,5,3,2,1,5,6,3};
int out[10] = {0,0,0,0,0,0,0,0,0,0};
for (int i = 0; i < 12; ++i)
{
++out[ in[i] ];
}
If you provide any code snippet, its easy for the community to help you.
Try this, even you optimize the no.of loops :)
#include <stdio.h>
void func(int in[], int in_length, int *out[], int *out_length) {
int temp[10] = {0}, i = 0, j = 0, value;
//scan the input
for(i=0; i< in_length; ++i) {
value = in[i];
if(value >= 0 && value <= 9) { //hope all the values are single digits
temp[value]++;
}
}
// Find no.of unique digits
int unique_digits = 0;
for(i = 0; i < 10; ++i) {
if(temp[i] > 0)
unique_digits++;
}
// Allocate memory for output
*out_length = 2 * unique_digits ;
printf("digits: %d out_length: %d \n",unique_digits, *out_length );
*out = malloc(2 * unique_digits * sizeof(int));
//Fill the output
for(i = 0, j = 0; i<in_length && j < *out_length; ++i) {
//printf("\n i:%d, j:%d val:%d cout:%d ", i, j, in[i], temp[in[i]] );
if(temp[in[i]] > 0 ) {
(*out)[j] = in[i];
(*out)[j+1] = temp[in[i]];
temp[in[i]] = 0; //Reset the occurrences of this digit, as we already pushed this digit into output
j += 2;
}
}
}
int main(void) {
int input[100] = {1, 0, 4, 5, 4, 3, 1};
int *output = NULL, output_length = 0, i = 0;
func(input, 7, &output, &output_length );
for(i=0; i < output_length; i+=2) {
printf("\n %d : %d ", output[i], output[i+1]);
}
return 0;
}
I got an interview question and my algorithm only pass given example test cases, and didn't pass all test cases.
Question: Given a sorted integer array, return sum of array so that each element is unique by adding some numbers to duplicate elements so that sum of unique elements is minimum.
I.e., if all elements in the array are unique, return the sum.
If some elements are duplicates, then increment them to make sure all elements are unique so that the sum of these unique elements is minimum.
Some examples:
input1[] = { 2, 3, 4, 5 } => return 19 = 2+3+4+5 (all elements are unique, so just add them up)
input2[] = { 1, 2, 2 } => return 6 = 1+2+3 (index 2 is duplicate, so increment it)
input3[] = { 2, 2, 4, 5 } => return 14 = 2+3+4+5 (index 1 is duplicate, so increment it)
These three are examples in the question, my simple algorithm is as follows and passed the given three examples, but didn't pass other cases where I couldn't see the inputs.
static int minUniqueSum(int[] A) {
int n = A.length;
int sum = A[0];
int prev = A[0];
for( int i = 1; i < n; i++ ) {
int curr = A[i];
if( prev == curr ) {
curr = curr+1;
sum += curr;
}
else {
sum += curr;
}
prev = curr;
}
return sum;
}
I couldn't see other inputs which this algorithm failed.
What I can think of other input examples are
{1, 1, 1, 1} --> {1, 2, 3, 4}
{1, 1, 2, 2, 3, 3, 3} --> {1, 2, 3, 4, 5, 6, 7}
{1, 2, 4, 4, 7, 7, 8} --> I think this should be {1, 2, 3, 4, 6, 7, 8} and my algorithm fails in this example because my algorithm has {1, 2, 4, 5, 7, 8, 9} whose sum is not minimum
What are some other test cases and an algorithm which can pass all cases?
Some people are complaining that the question is not clear. I'd like to let you know about the problem. There was no clear description about the added number if it will be allowed only positive or positive and negative. Given three examples with input and output, and some others input and output cases which you are not allowed to see, write a program to pass all other unseen input / output cases as well. That was the question.
Your algorithm will fail in cases with more repeated values, for example
2, 2, 2
You'd get 7 instead of 9.
A minimal fix using your algorithm would be:
static int minUniqueSum(int[] A) {
int n = A.length;
int sum = A[0];
int prev = A[0];
for( int i = 1; i < n; i++ ) {
int curr = A[i];
if( prev >= curr ) {
curr = prev+1;
}
sum += curr;
prev = curr;
}
return sum;
}
*As pointed out in the comments, no need to sort an already sorted array.
In JavaScript
var list = [1, 1, 1, 10, 3, 2];
function minUniqueSum(arr) {
const temp = arr.reduce((acc, cur) => {
while (acc.includes(cur)) cur++;
acc.push(cur);
return acc;
}, []);
console.log(temp); // [1, 2, 3, 10, 4, 5]
return temp.reduce((acc, cur) => acc + cur, 0);
}
var result = minUniqueSum(list);
console.log(result); // 25
I did like this, without sort.
// Complete the getMinimumUniqueSum function below.
static int getMinimumUniqueSum(int[] arr) {
int sum = 0;
ArrayList < Integer > arrayList = new ArrayList < Integer > (arr.length);
arrayList.add(arr[0]);
for (int i = 1; i < arr.length; i++) {
int val = arr[i];
while (arrayList.contains(val)) {
val++;
}
arrayList.add(val);
}
for (int i = 0; i < arrayList.size(); i++) {
sum += arrayList.get(i);
}
return sum;
}
And it passed all (13) test cases.
While this solution is based on java the thought process can be applied everywhere.
Your solution is nearly correct and optimized. Using multiple for loops will slow things down A LOT and thus should be avoided if possible! Since your array is already pre-sorted you have enough with 1 for loop.
Your assumption that you had the last test case wrong does not seem to be correct since increment means you can only do +1 (and indeed most questions limit this assignment to increments only.)
What you missed was the max range of the Integers.
If they pass a Integer.MAX_VALUE, your sum will overflow and be negative instead. So your sum variable needs to be of a bigger type. double or BigInteger should work (BigInteger would be best).
Also when they pass MAX_VALUE twice your curr+1 will also overflow becoming negative instead. So you want your curr and prev to also be a larger type. long should do for this.
public static double calculateMinSumSorted(int[] input){
double sum = input[0];
long prev = input[0];
long cur;
for(int i = 1 ; i < input.length ; i++){
cur = input[i];
if(cur <= prev){
cur = ++prev;
}
prev = cur;
sum += cur;
}
return sum;
}
Here is some of the test cases I used:
#Test
public void testSimpleArray(){
double test1 = muas.calculateMinSumSorted(new int[]{1,2,3,4});
Assert.assertEquals(10, test1, 0.1);
}
#Test
public void testBeginningSameValues(){
double test1 = muas.calculateMinSumSorted(new int[]{2,2,3,4});
Assert.assertEquals(14, test1, 0.1);
}
#Test
public void testEndingSameValues(){
double test1 = muas.calculateMinSumSorted(new int[]{1,2,4,4});
Assert.assertEquals(12, test1, 0.1);
}
#Test
public void testAllSameValues(){
double test1 = muas.calculateMinSumSorted(new int[]{1,1,1,1});
Assert.assertEquals(10, test1, 0.1);
}
#Test
public void testOverMaxIntResult(){
double test1 = muas.calculateMinSumSorted(new int[]{1,2,3,3,4,4,4,4,4,Integer.MAX_VALUE});
System.out.println(test1);
Assert.assertEquals(2147483692.0, test1, 0.1);
}
#Test
public void testDoubleMaxIntArray(){
double test1 = muas.calculateMinSumSorted(new int[]{2,2,3,4,5,6,7,8,9, Integer.MAX_VALUE, Integer.MAX_VALUE});
Assert.assertEquals(4294967349.0, test1, 0.1);
}
#Test
public void testDoubleMinIntArray(){
double test1 = muas.calculateMinSumSorted(new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE,2,2,3,4,5,6,7,8,9});
Assert.assertEquals(-4294967241.0, test1, 0.1);
}
// 1,1,2,3 -> 1,2,2,3 -> 1,2,3,3 -> 1,2,3,4 => 10
// 2,2,2 -> 2,3,2 -> 2,3,3 -> 2,3,4 => 9
public int calculateMinSumSorted(int[] input) {
int sum = input[0];
for (int i = 1, v = sum; i < input.length; v = input[i++]) {
if (input[i] <= input[i - 1]) {
input[i--] = ++v;
} else {
sum += input[i];
}
}
return sum;
}
It you're allowed to add negative values to any of the inputs then the minimum is just the Nth triangular number where N is the number of elements in the array. (I'm presuming that we're dealing only with positive numbers for the adjusted array since we could make it arbitrarily small (negative) otherwise.
So you're algorithm is just a matter of looking for a pair of consecutive values that are the same. If not found return the sum else N * (N + 1) / 2.
If instead it's true that only duplicate elements can be adjusted, then the approach is to find holes between consecutive elements and fill them up with previously "queued" values. The actual values of the "queued" elements is irrelevant and only a counter is necessary. Below is a C# solution where I'm assuming that the adjustments to elements must be positive values. So that means we can't go backward and fill unused holes which simplifies the problem.
int F()
{
int[] a = {2, 2, 2, 3, 8, 9}; // sorted list
int n = 0; /* num */ int p = 0; /* prev; zero is an invalid value in the list */
int q = 0; /* queue */ int s = 0; /* sum */
for (int i = 1; i < a.Length; i++)
{
n = a[i];
if (n == p)
q++; // increment queue on duplicate number
else
{
// for every hole between array values, decrement queue and add to the sum
for (int j = 1; q > 0 && j < n - p; j++, q--)
s += p + j;
s += (p = n);
}
}
// flush the queue
for (; q > 0; q--)
s += ++n;
return s;
}
You example {1, 2, 4, 4, 7, 7, 8} suggests that the previous assumption is not valid. So I went ahead and wrote a version that uses a queue to store skipped holes for later filling. It's not really that painful, and it's very similar in structure, but it might still be too much for most interviews.
using System.Collections.Generic;
int F2()
{
int[] a = {1, 1, 8, 8, 8, 8, 8}; // sorted list
int n = 0; /* num */ int p = 0; // prev; zero is an invalid value in the list
int q = 0; /* queue */ int s = 0; // sum
Queue<int> h = new Queue<int>(); // holes
for (int i = 1; i < a.Length; i++)
{
n = a[i];
if (n == p)
q++; // increment queue on duplicate number
else
{
for (int j = 1; j < n - p; j++)
if (h.Count <= q + a.Length - i) // optimization
h.Enqueue(p + j);
s += (p = n);
}
}
// flush the queue
for (; q > 0; q--)
s += h.Count > 0 ? h.Dequeue() : ++n;
return s;
}
Try them both out here: http://rextester.com/APO79723
int a[] = {1,2,2,3,5,6,6,6,6 }; So what would be elements in array for sum
As per above problem statement it would be {1,2,3,4,5,6,7,8,9 }
Solution
public static void uniqueSum(){
int a[] = {1,2,2,3,5,6,6,6,6 };
int n = a.length;
int sum = a[0];
int prv=a[0];
for(int i=1; i<n;i++){
int cur = a[i];
if(cur==prv){
cur = cur+1;
sum+= cur;
System.out.print("--"+cur);
}else{
if(cur<prv){
cur = prv +1;
}
sum += cur;
}
prv = cur;
}
System.out.println("===================== "+sum);
}
You can try the below code.
int a[] = {1, 1 , 1};
ArrayList<Integer> arr = new ArrayList<Integer>();
HashMap hash = new HashMap();
for(int i=0;i<a.length;i++){
arr.add(a[i]);
}
int sum = 0;
hash.put(0, arr.get(0));
sum = (int) hash.get(0);
for(int i=1;i<arr.size();i++){
for(int j=1;j<=a.length;j++){
if(hash.containsValue((arr.get(i)))){
arr.set(i, arr.get(i)+1);
}else{
hash.put(i, arr.get(i));
sum += (int) hash.get(i);
break;
}
}
}
System.out.println(sum);
PS: Even I got this question in my interview, the above code passed all the test cases.
public static int minSum(int arr[]){
for(int i=0; i<arr.length-1;i++){
if(arr[i]==arr[i+1]){
arr[i+1]= arr[i+1]+1;
}
}
int sum=0;
for(int i=0; i<arr.length;i++){
sum=sum+arr[i];
}
System.out.println("sum: "+sum);
return sum;
}
Going by your description of hidden I/O, it's probably a HackerRank Test question. A better way to state the problem is "Given a sorted array of numbers, make the numbers distinct by incrementing them (num++ at a time) in such a way that the array sum is minimized."
The problem allows only increments i.e. increase a number by 1 at a time. This also ensures that the array always remains sorted.
so {1, 2, 4, 4, 7, 7, 8} --> {1, 2, 4, 5, 7, 8, 9}
Here is the problem with the solution.
https://www.geeksforgeeks.org/making-elements-distinct-sorted-array-minimum-increments/
Working solution (JAVA 7)
:
public static int getMinimumUniqueSum(List <Integer> arr){
int sum = 0, val = 0;
ArrayList < Integer > arrayList = new ArrayList < Integer > (arr.size());
arrayList.add(arr.get(0));
for (int i = 1; i < arr.size(); i++) {
val = arr.get(i);
while (arrayList.contains(val)) {
val++;
}
arrayList.add(val);
}
for (int i = 0; i < arrayList.size(); i++) {
sum += arrayList.get(i);
}
return sum;
}
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
/* No sorting required. Works even with random list */
public static int getMinUniqueSum(List<Integer> list)
{
Set<Integer> set = new HashSet<Integer>();
int sum = 0;
for (Integer val : list)
{
if(!set.add(val))
{
while(true)
{
Integer temp = val + 1;
if(set.add(temp))
{
sum = sum + temp;
break;
}
}
}
else
{
sum = sum + val;
}
}
return sum;
}
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
System.out.println("Enter size of the list");
int n = s.nextInt();
List<Integer> list = new ArrayList<Integer>(n);
System.out.println("Enter " + n + " elements of the list");
for(int i = 0; i < n; i++)
list.add(s.nextInt());
s.close();
System.out.println("MinUniqueSum = " + getMinUniqueSum(list));
}
}
In C++:
int64_t getMinimumUniqueSum(std::vector<int> arr)
{
std::sort(arr.begin(), arr.end());
int64_t sum = arr[0];
size_t i = 0;
size_t j = 1;
size_t gap_i = j;
int avail_val = arr[j] + 1;
while (j < arr.size()) {
// find next gap with available values
if (j > gap_i) {
gap_i = j;
avail_val = arr[gap_i] + 1;
}
while (gap_i < arr.size() && arr[gap_i] <= avail_val) {
avail_val = arr[gap_i] + 1;
gap_i++;
}
if (arr[i] == arr[j]) {
// update duplicated value
arr[j] = avail_val;
avail_val++;
} else {
// move index of prev value - i
i = j;
}
sum += arr[j];
j++;
}
return sum;
}
Straightforward solution that uses hash set would be mush slower:
int64_t getMinimumUniqueSum_Slow(std::vector<int> arr)
{
std::unordered_set<int> s;
int64_t sum = 0;
for (int a : arr) {
while (s.find(a) != s.end()) {
a++;
}
s.insert(a);
sum += a;
}
return sum;
}
Slow version takes about 10s to process array with 10^5 numbers.
While optimized one takes about 0.5s to process array with 10^7 numbers.
But while the slow solution is obviously correct - we can use it for testing of the optimized one:
std::vector<int> random_vec(size_t size, int min_val, int max_val)
{
std::random_device rnd_device;
std::mt19937 mersenne_engine {rnd_device()};
std::uniform_int_distribution<int> dist {min_val, max_val};
auto gen = [&dist, &mersenne_engine](){
return dist(mersenne_engine);
};
std::vector<int> arr(size);
generate(begin(arr), end(arr), gen);
return arr;
}
int main()
{
for (int i = 0; i < 1000; i++) {
printf("%d\n", i);
auto arr = random_vec(i*10+1, -5, 5);
int64_t x = getMinimumUniqueSum(arr);
int64_t y = getMinimumUniqueSum_Slow(arr);
if (x != y) {
printf("Results not match: fast -> %lld, slow -> %lld !!!\n\n", x, y);
return 1;
}
}
return 0;
}
In Haskell:
countdups _ _ [] = []
countdups first prev (x:xs)
| (prev >= x) && (first /= True) = (prev+1) : countdups False (prev+1) xs
| otherwise = x: countdups False x xs
minsum list = sum $ countdups True 0 (sort list)
Here is some of the test cases I used:
countdups True 0 [2, 3, 4, 5]
[2,3,4,5]
minsum = 14
countdups True 0 [1, 2, 2]
[1,2,3]
minsum = 6
countdups True 0 [2, 2, 4, 5]
[2,3,4,5]
minsum = 14
countdups True 0 [1,2,2,3,7]
[1,2,3,4,7]
minsum = 17
countdups True 0 [1,1,1,2,3,10]
[1,2,3,4,5,10]
minsum = 25
countdups True 0 [1,1,1,1]
[1,2,3,4]
minsum= 10
countdups True 0 [1,2,3,3,4,4,4,4,4,2147483647]
[1,2,3,4,5,6,7,8,9,2147483647]
minsum= 2147483692
Using Collections in java helps a lot ,
Here i use HashMap as it stores values for every Unique Key
My Key in hashmap is the array elements and the value is the no. of counts as it appears in the array.
package uniquesum;
import java.util.*;
public class Uniquesum {
static HashMap<Integer, Integer> hp = new HashMap<Integer, Integer>();
static int Sum(int arr[]){
int sum=0;
Arrays.sort(arr);
hp.put(arr[0], 1);
for(int i=1; i<arr.length; i++){
if(hp.containsKey(arr[i])){
Integer val = hp.get(arr[i]);
hp.put(arr[i], val+1);
hp.put(arr[i]+val, 1);
}
else{
hp.put(arr[i], 1);
}
}
for(Map.Entry m:hp.entrySet()){
sum = sum + (int)m.getKey();
}
return sum;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int arr[] = new int [n];
for(int i=0; i<n;i++){
arr[i] = scan.nextInt();
}
System.out.println("Sum is " + Sum(arr));
}
}