Bad performance in Java exercise - java

I'm doing some tests in Java to warm up, and I just made this one:
A non-empty zero-indexed array A consisting of N integers is given.
The consecutive elements of array A represent consecutive cars on a
road.
Array A contains only 0s and/or 1s:
0 represents a car traveling east, 1 represents a car traveling west.
The goal is to count passing cars. We say that a pair of cars (P, Q),
where 0 ≤ P < Q < N, is passing when P is traveling to the east and Q
is traveling to the west.
For example, consider array A such that:
A[0] = 0 A[1] = 1 A[2] = 0 A[3] = 1 A[4] = 1 We have five
pairs of passing cars: (0, 1), (0, 3), (0, 4), (2, 3), (2, 4).
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty zero-indexed array A of N integers, returns
the number of pairs of passing cars.
The function should return −1 if the number of pairs of passing cars
exceeds 1,000,000,000.
For example, given:
A[0] = 0 A[1] = 1 A[2] = 0 A[3] = 1 A[4] = 1 the function
should return 5, as explained above.
Assume that:
N is an integer within the range [1..100,000]; each element of array A
is an integer that can have one of the following values: 0, 1.
Complexity:
expected worst-case time complexity is O(N); expected worst-case space
complexity is O(1), beyond input storage (not counting the storage
required for input arguments). Elements of input arrays can be
modified.
My code is as follows:
public int solution(int[] A) {
// write your code in Java SE 8
int result = 0;
long mult = 0;
for(int value : A){
if(value == 0){
mult ++;
}
else {
result += mult;
}
}
return result;
}
The link with the result is this one:
https://codility.com/demo/results/trainingFFF4BS-AZ3/
If the link die, the result said:
Performance tests
▶ medium_random random, length = ~10,000 ✔OK ▶ large_random random,
length = ~100,000 ✘WRONG ANSWER got 1248768710 expected -1 ▶
large_big_answer
0..01..1, length = ~100,000 ✘WRONG ANSWER got -1794967296 expected -1 ▶ large_alternate
0101..01, length = ~100,000 ✘WRONG ANSWER got 1250025000 expected -1 ▶ large_extreme large test with all 1s/0s, length = ~100,000 ✔OK
Any ideas what is wrong in my code?.

Your rules say,
The function should return −1 if the number of pairs of passing cars exceeds 1,000,000,000.
And you don't test that condition. You could with a ternary operation and something like
return result > 1000000000 ? -1 : result;
or (debateably) more readable
if (result > 1000000000) {
return -1;
}
return result;
and for improved performance you might add that test like
for (int value : A) {
if (value == 0) {
mult++;
} else {
result += mult;
if (result > 1000000000) {
return -1;
}
}
}
return result;

Related

Make two array sum same with limited values

I have two arrays A & B (size of the array is 1 to 100,000) that can take values only 1,2,3,4,5,6.
Now my task is to make minimum numbers to be changed in arrays such that the sum of both the arrays is the same.
Example 2:
A=[5,4,1,2,6,6] & B=[2], we have to make A as [1,1,1,1,1,1] so we have to change A 5 times and then B=[6] once, so function should return 6.
Example 3:
A=[1,2,3,4,3,2,1] and B[6], function should return -1.
Method signature looks like this.
public int task(int[] A, int[] B) {
int diff = Math.abs(A.length - B.length);
if(diff >=6) return -1;
//
}
I am able to get answer for example 3 with simple condition. Bit not for first 2 examples.
What approach should I follow to solve this program? As we can turn each and every element in A & B and do a comparison, but that is more complex.
The alghorithm can be as following:
Prepare data part
Go through all items in array A and B and find out how many of each number (1,2,3,4,5,6) is in each array. Preferable have 2d array that stores the indexes of those numbers, so you can easily access it later.
i.e. array A=[1,1,1,4,6,4] will be translated into new 2d array as
2darr=
[]
[0,1,2]
[]
[]
[3,5]
[]
[4]
so when you i.e. want to see how many 1 are there you can see that 2darr[1].length is 3. And when you want to find out where it is i.e. the 2darr[1][0] will get you index in source array and A[0] is indeed 1
In process you can also count the sum, but even without it, the sum now can be easily found out just going through lengths of each subarray in 2darray.
Alghoritm
To find the minimum amount of changes, you will first find out which sum is smaller and which bigger. Then the best change is to start changing 1 values to 6 in smaller array or changing 6 values to 1 in bigger arrays. Then 2 to 6 in smaller array and 5 to 1 in bigger array. And then continue with other numbers.
In process you can changing the arrays based on indexes you already have and do it as long as needed to get both arrays to same sum. This is detailed alghoritm that will show you how actually both arrays will look like to satisfy your needs. Its O(n), so there is definitely no way how to make it faster as you have to go through all fields just to get the sum.
I suggest to do it so you can see the actual result. On the other hand, if you think more deeply, it can be done more easily, if you just seek the right answer - you just need to know how many times each number in each array is and then just find out how many changes are needed just by simple math. You already know, you are just changing up to all 1 to 6 in smaller array and up to all 6 to 1 in bigger array and it can be just counted easily how many of them you need to change and if it is sufficient or you change all of them and then you will continue with 5 to 1 and 2 to 6 etc.
Example
Imagine that A.length is 500 and B.length is 300. The sum of A=1000and B=700. You find out that A has 30 repetitions of number 6 and B has 20 repetitions of number 1. In A you change all those 6 to 1, therefore reducing it by 30*5=150 to total of A=850 and in B you change all those 1 to 6 and increasing the value 20*5=100 and therefore B=800. You did 50 changes in total.
Then you continue with higher number in smaller array and with lower number in bigger array. You find out that A has 100 numbers of 5. Reducing 5 to 1 decreases value by 4 for each. Right now you have only 50 value difference. 50/4=12.5, therefore you need to change 13 numbers and you are done. The answer is that minimum amount of changes is 63.
The impossibility-criteria is a simple one as you suspect, but it is different from what you guess: it depends on the length of the arrays, which determines their minimal and maximal sums. The shorter array can not produce a sum which is greater than 6 times its length (all elements are 6s) and the longer array can not produce a sum which is less than its length (all elements are 1s):
if( Math.min(A.length, B.length) * 6 < Math.max(A.length ,B.length) )
return -1;
Then you need the sums and the statistics what the other answer describes, but maybe there is place for a slightly different explanation. In order to have the two sums meet, the smaller one can be increased and the larger one can be decreased. For having the minimum amount of steps, you always want to make the largest steps possible, via starting to replace 1s with 6s in the smaller sum (each replacement increasing the sum by 5) and 6s with 1s in the larger sum (each replacement decreasing it by 5), and so on.
As you do not want to generate the steps (at least to my understanding), actually you can track the difference only and also count the pairs together (6s in the larger-sum-array and 1s in the smaller-sum-array, then the same with 5-2, etc.). And in fact you can do this pairing even at the beginning, without knowing which one is the larger/smaller sum, because the pairs will stay pairs, just their direction changes.
Example is JavaScript so it can run here, but I try to write it as Java as possible:
function task(A,B){
if( Math.min(A.length, B.length) * 6 < Math.max(A.length, B.length) )
return -1;
var diff=0;
var statistics=[0,0,0,0,0,0]; // would be a new int[6] in Java
for(var item of A){ // for(int item : A) in Java
// this loop guesses that A has the larger sum
diff+=item;
statistics[item-1]++; // 1s are counted in [0], 2s in [1], ... 6s in [5]
}
for(var item of B){ // for(int item : B) in Java
// this loop guesses that B has the smaller sum
diff-=item;
statistics[6-item]++; // 1s are counted in [5], 2s in [4], ... 6s in [0]
}
if(diff<0){
// the guess was wrong, swaps are needed
diff=-diff;
for(var i=0;i<3;i++){
var swap=statistics[i];
statistics[i]=statistics[5-i];
statistics[5-i]=swap;
}
}
var log=[A.join()," ",B.join()," ",diff," ",statistics.join()].join(); // <-- this one...
// at this point
// - array indices are conveniently denoting step sizes
// - diff is non-negative
// - and we know there is a solution (so we won't run out of array indices for example)
var changes=0;
var i=5;
while(diff>0){
var step = Math.min(statistics[i], Math.ceil(diff/i));
// would better be "int step = Math.min(statistics[i], (diff+i-1)/i);" in Java
// as Math.ceil() produces a double
changes += step;
diff -= i*step;
i--;
}
return [changes," ",log].join(); // <-- ... and this
// are only visuals
return changes;
}
console.log(task([1,2,3,4,3,2,1],[6]));
console.log(task([6],[1,2,3,4,3,2,1]));
console.log(task([2,3,1,1,2],[5,4,6]));
console.log(task([5,4,6],[2,3,1,1,2]));
console.log(task([5,4,1,2,6,6],[2]));
console.log(task([2],[5,4,1,2,6,6]));
At the end I've just thrown it together in Java too: https://ideone.com/mP3Sel
As others have noted, we can solve this with a greedy algorithm. Count the frequencies of numbers for each array, then iterate from the outside in. For the array with the larger sum, iterate over the negative multipliers; for the array with the smaller sum, the positive. Choose the greatest absolute multiplier, then the max frequency available (and needed) each time, and as soon as the sum difference is equal or reverses sign, stop.
2 3 1 1 2 = 9
mult 5 4 3 2 1 0
freq 2 2 1 0 0 0
^ -->
5 4 6 = 15
mult 0 -1 -2 -3 -4 -5
freq 0 0 0 1 1 1
<-- ^
function f(A, B){
let freqSm = [0, 0, 0, 0, 0, 0];
let freqLg = [0, 0, 0, 0, 0, 0];
let smSum = 0;
let lgSum = 0;
let sm = 'A';
let lg = 'B';
A.map(x => {
freqSm[x-1]++;
smSum += x;
});
B.map(x => {
freqLg[x-1]++;
lgSum += x;
});
if (lgSum < smSum){
sm = 'B';
lg = 'A';
let [_freq, _sum] = [freqSm, smSum];
freqSm = freqLg;
freqLg = _freq;
smSum = lgSum;
lgSum = _sum;
}
const smMult = [5, 4, 3, 2, 1, 0];
const lgMult = [0,-1,-2,-3,-4,-5];
const changes = [];
let diff = lgSum - smSum;
function numTxt(count, num){
const ws = [, 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
const countTxt = count < 10 ? ws[count] : count;
return `${ countTxt } ${ num }${ count > 1 ? 's' : '' }`;
}
function incSm(i){
const rem = diff % smMult[i];
const mult = Math.min(freqSm[i], Math.ceil(diff / smMult[i]));
diff -= mult * smMult[i];
let txt;
if (diff < 0 && rem){
if (mult > 1)
txt = `Change ${ numTxt(mult-1, i+1) } to 6 and one to ${ i + 1 + rem } in ${ sm }.`;
else
txt = `Change one ${ i + 1 } to ${ i + 1 + rem } in ${ sm }.`;
} else {
txt = `Change ${ numTxt(mult, i+1) } to 6 in ${ sm }.`;
}
changes.push(txt);
}
function decLg(j){
const rem = diff % -lgMult[j];
const mult = Math.min(freqLg[j], Math.ceil(-diff / lgMult[j]));
diff += mult * lgMult[j];
let txt;
if (diff < 0 && rem){
if (mult > 1)
txt = `Change ${ numTxt(mult-1, j+1) } to 1 and one to ${ j + 1 - rem } in ${ lg }.`;
else
txt = `Change one ${ j + 1 } to ${ j + 1 - rem } in ${ lg }.`;
} else {
txt = `Change ${ numTxt(mult, j+1) } to 1 in ${ lg }.`;
}
changes.push(txt);
}
for (let i=0; i<6; i++){
const j = 5 - i;
if (freqSm[i] >= freqLg[j]){
if (freqSm[i]){
incSm(i);
if (diff <= 0)
return changes.join('\n');
}
if (freqLg[j]){
decLg(j);
if (diff <= 0)
return changes.join('\n');
}
} else {
if (freqLg[j]){
decLg(j);
if (diff <= 0)
return changes.join('\n');
}
if (freqSm[i]){
incSm(i);
if (diff <= 0)
return changes.join('\n');
}
}
}
return -1;
}
var input = [
[[2,3,1,1,2], [5,4,6]],
[[5,4,1,2,6,6], [2]],
[[1,2,3,4,3,2,1], [6]]
];
for (let [A, B] of input){
console.log(`A: ${ A }`);
console.log(`B: ${ B }`);
console.log(f(A, B));
console.log('');
}

Find the minimal absolute value of a sum of two elements

I am solving the Codility problem provided below,
Let A be a non-empty array consisting of N integers.
The abs sum of two for a pair of indices (P, Q) is the absolute value |A[P] + A[Q]|, for 0 ≤ P ≤ Q < N.
For example, the following array A:
A[0] = 1 A1 = 4 A[2] = -3 has pairs of indices (0, 0), (0,
1), (0, 2), (1, 1), (1, 2), (2, 2). The abs sum of two for the pair
(0, 0) is A[0] + A[0] = |1 + 1| = 2. The abs sum of two for the pair
(0, 1) is A[0] + A1 = |1 + 4| = 5. The abs sum of two for the pair
(0, 2) is A[0] + A[2] = |1 + (−3)| = 2. The abs sum of two for the
pair (1, 1) is A1 + A1 = |4 + 4| = 8. The abs sum of two for the
pair (1, 2) is A1 + A[2] = |4 + (−3)| = 1. The abs sum of two for
the pair (2, 2) is A[2] + A[2] = |(−3) + (−3)| = 6.`
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty array A consisting of N integers, returns the minimal abs sum of two for any pair of indices in this array.
For example, given the following array A:
A[0] = 1 A1 = 4 A[2] = -3 the function should return 1, as
explained above.
Given array A:
A[0] = -8 A1 = 4 A[2] = 5 A[3] =-10 A[4] = 3 the function
should return |(−8) + 5| = 3.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000]; each element of array A is an integer within the range [−1,000,000,000..1,000,000,000].
I write the solution provided below.
public static int solution(int[] A) {
int N = A.length;
Arrays.sort(A);
if (A[0] >= 0) {
return 2 * A[0];
}
int i = 0;
int j = N - 1;
int sum = Math.abs((A[i] + A[j]));
// -10, -8, 3, 4, 5
while (i <= j) {
if (Math.abs(A[i + 1] + A[j]) < sum) {
++i;
sum = Math.abs(A[i] + A[j]);
} else if (Math.abs(A[i] + A[j - 1]) < sum) {
--j;
sum = Math.abs(A[i] + A[j]);
} else {
i++;
j--;
}
}
return sum;
}
The solution gets hanged in the online judge and seems it enters in a forever loop. Is there a possibility that the code can enter a non-ending loop?
UPDATE
After I update the solution with the all negatives check, the code passed the online judge and provides a good performance.
if(A[N-1] <=0){
return 2* Math.abs(A[N-1]);
}
For input arrays e.g({-1, -2, -3}, {-1, -2}, {-1} your algorithm throws ArrayIndexOutOfBoundsException, so arrays when there are only negative numbers and there is no repeats
There is no chance to reach endless loop because either i or j change only + or - 1
I would like to explain the algorithm that I have implemented and then the implementation in C++.
Sort the array because otherwise we would need to check any two arbitrary indices. That brute-force solution would result in O(N ^ 2) runtime complexity.
We initialise the min abs sum to something higher than the possible value in the arrays.
Apply the caterpillar method by having front and back indices.
In every iteration, update the min abs sum as and when needed.
There two special cases:
a. all values are zero or positive. We could return A[front] * 2 early.
b. all values are negative or zero. We could return A[back] * 2 early.
In both cases, we could return early, however, it would result in a bit more code, so I personally avoid that. In the above cases, we can still go through the array without degrading the overall runtime complexity. In these cases, it also does not matter how we go through the array with regards to the result, so I just go through the array in one way in both cases. But the code will be shared with the third case.
In the third case, where the array, and thereby the sorted array, contains both negative and positive values, we try to keep the sum of front and back to zero since this when the abs sum value is minimised. In other words, we try to keep the balance between the negative and positive numbers by keeping their distance to the minimum.
Therefore, if the sum of front and back are less than zero, then we know that the negative front value is greater than the positive back value. As a direct consequence of that, we need to advance the front index.
If the sum of front and back are equal to zero, then we found the smallest min abs sum that is ever possible. The absolute value cannot be less than zero. Whilst I could return at this point in the code for some constant optimisation, I do not do so to keep the code the minimal and also functional.
If the sum of front and back are greater than zero, then we know that the negative front value is less than the positive back value. As a direct consequence of that, we need to decrease the index.
We loop until the front and back indices meet, but we handle the case when they are equal since according to the task specification, the same index can be used twice for the absolute sum.
The runtime complexity of this solution is O(N * logN) because the sorting of the array is O(N * logN) and the loop is O(N) since we go through every element. Therefore, the sorting runtime complexity dominates the loop.
The space complexity is O(1) because we only allocate constant space independently from the number of inputs. The sorting is done in place.
int solution(vector<int> &A)
{
const int N = A.size();
sort(A.begin(), A.end());
int min_abs_sum_of_two = INT_MAX;
for (int front = 0, back = N - 1; front <= back;) {
const int ef = A[front];
const int eb = A[back];
min_abs_sum_of_two = min(min_abs_sum_of_two, abs(ef + eb));
if (ef + eb < 0) ++front; else --back;
}
return min_abs_sum_of_two;
}
I got 100% for following code ( java). Slightly modified version of https://www.techiedelight.com/find-pair-array-minimum-absolute-sum/
import java.util.*;
// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
// sort the array if it is unsorted
Arrays.sort(A);
int low = 0;
int high = A.length - 1;
if (A[0] >= 0) {
return 2 * A[0];
}
if (A[high] <= 0) {
return -2 * A[high];
}
// maintain two indexes pointing to endpoints of the array
// `min` stores the minimum absolute difference
int min = Integer.MAX_VALUE;
int i = 0, j = 0;
// reduce the search space `A[low…high]` at each iteration of the loop
int sum = 0;
// loop if `low` is less than `high`
while (low < high)
{
// update the minimum if the current absolute sum is less.
sum = A[high] + A[low];
if (Math.abs(sum) < min)
{
min = Math.abs(sum);
i = low;
j = high;
}
// optimization: pair with zero-sum is found
if (min == 0) {
break;
}
// increment `low` index if the total is less than 0;
// decrement `high` index if the total is more than 0
if (sum < 0) {
low++;
}
else {
high--;
}
}
return min;
}
}
The Answer is late but I hope to help anyone have the same question
//============================================================================
// Author: Hamdy Abd El Fattah
// Code is like humor. When you have to explain it, it’s bad.
//============================================================================
#include <bits/stdc++.h>
#define FIO cin.tie(0), cin.sync_with_stdio(0)
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int main() {
FIO;
ll n , m = INF , x;
vector<ll> positive,negative;
cin>>n;
while(n--){
cin>>x;
if(x < 0)
negative.push_back(x * -1);
else if(x > 0)
positive.push_back(x);
else
m = 0;
}
if(m == 0){
cout<<"0\n";
}else{
sort(positive.begin(), positive.end());
sort(negative.begin(), negative.end());
int i= 0, j = 0;
int positive_size = positive.size(), negative_size =negative.size();
while(i < positive_size || j < negative_size){
if(abs(positive[i] - negative[j]) < m){
m=abs(positive[i] - negative[j]);
m=min(min(m,positive[i]*2),negative[j] * 2);
}
if((i < positive_size && positive[i] <= negative[j]) || j == negative_size)
i++;
else if((j < negative_size && positive[i] > negative[j]) || i == positive_size)
j++;
}
cout<<m<<endl;
}
return 0;
}

How to find the Kth largest difference in int[]?

I have an Algorithm question.
For example, there is an int[] array like [1,5,4,3,7,2].
I want to find the kth largest difference in this array like :
array[i] - array[j] = kth largest difference
(index i must smaller than j and array[i] must larger than array[j]).
The output is return the j in this question.
My current idea:
I can build a int[][] to store all the difference in the array.
Then sorting them and find the kth larget difference.
But time complexity is O(n^2).
Are there better solutions?
You could run 2 separate methods that finds the max and min of the corresponding arrays then find the difference.
OR
You can use your method of creating a new array that finds the difference of every single value THEN find the max of that array and output that.
Then use Array sort() method to reorder an array and print out the values of max differences when called by index+1
Example in Python
results = []
a = [1,5,4,3,7,2]
a_new = [(1,0), (5,1), (4,2), (3,3), (7,4), (2,5)] #(5,1) -> 5:value and 1:index
sort a_new by value # e.g. mergesort O(nlogn)
start_index = 0
end_index = len(a_new) - 1
i = -1
j = -1
diff = 0
while true: # sequential search
if(a_new[start_index][1] < a_new[end_index][1]): #compare i and j
tmp_diff = a_new[end_index][0] - a_new[start_index][0]
i = start_index
j = end_index
diff = tmp_diff
results.append((I,j,diff)) #add a tuple in results_list
end_index -= 1
else: # a_new[start_index][1] > a_new[end_index][1]
start_index += 1
if start_index == end_index: break
sort results by diff and return results[k-1]
I hope this help. I can't check typing error.
My Idea is: max difference is -> max_possible_element_value - min_element_value
Sample:
results = []
a_new = [(1,0), (2,5), (3,3), (4,2), (5,1), (7,4)]
start_index = 0
end_index = len(a_new) - 1
i = -1
j = -1
diff = 0
while True:
if(a_new[start_index][1] < a_new[end_index][1]):
i = a_new[start_index][1]
j = a_new[end_index][1]
diff = a_new[end_index][0] - a_new[start_index][0]
results.append((i, j, diff))
end_index -= 1
else:
start_index -= -1
if start_index == end_index: break
print(results)
Result:
[(0, 4, 6), (0, 1, 4), (0, 2, 3), (0, 3, 2), (0, 5, 1)]
you can sort the result array then get kth diff.
Pseudocode-wise, it could go this way :
You can sort the current array descending, then start your calculation like so :
diffList = {}
calculate(array,k) :
if (k<=0) OR (array.length < 2) OR (k > 2^(array.length-1))
return nothing // whatever behavior you want (exception or null Integer whatever suits you)
else
return kthLargest(k, 0 , array.length-1, array)
end if
kthLargest(count, upperBound, lowerBound, array) :
if count = 0
if upperBound != lowerBound
return max(array[upperBound]-array[lowerBound], max(sortDesc(diffList)))
else
return max(sort(diffList))
end if
else if upperBound = lowerBound
sortDesc(diffList)
return diffList[count]
else
topDiff = array[upperBound]-array[upperBound+1]
botDiff = array[lowerBound-1]-array[lowerbound]
if(topDiff > botDiff)
add botDiff to diffList
return kthLargest(count-1,upperBound,lowerBound-1,array)
else
add topDiff to diffList
return kthLargest(count-1,upperBound+1,lowerBound,array)
end if
end if
Call calculate(array,k) and you're set.
This basically keeps track of a 'discarded pile' of differences while iterating and reducing bounds to always have your final largest difference be the current bounds' difference or a potential better value in that discarded pile.
Both sorts (omitted for brevity) should make this O(n log n).
You can substitute arrays for the most convenient collections, and unwrap this into an iterative solution also.
Corrections appreciated!
It can be done in complexity O( N * logN + N * logValMax ). First lets sort the array. After that we can build a function countSmallerDiffs( x ) which counts how many differences smaller or equal to x are in the array, this function has complexity O( N ) using two pointers. After that we can binary search the result in range minVal-maxVal. We need to find p such that satisfies countSmallerDiffs( p ) <= k < countSmallerDiffs( p + 1 ). The answer will be p.
Hope this helps you out! Good luck!

Complexity of coin algorithm

Can anyone tell me the complexity (Big O notation preferred) of this code? It finds the least number of "coins" needed to make a target sum.
To do this it calculates the least number of coins for each number up to the target starting from 1. Each number is worked out based on the possible pairs of numbers that could sum to it, and the pair with the smallest cost is used. An example hopefully makes this clearer
If the "coins" are {1, 3, 4} and the target is 13 then it iterates from 1 to 13, where the cost of 2 the minimum from (0+2, 1+1), the c(5) is the smallest cost of (c(0)+c(5), c(1)+c(4), c(2)+c(3)), etc up to c(13)
This is a version of the knapsack problem and I'm wondering how to define its complexity?
Code:
import java.util.*;
public class coinSumMinimalistic {
public static final int TARGET = 12003;
public static int[] validCoins = {1, 3, 5, 6, 7, 10, 12};
public static void main(String[] args) {
Arrays.sort(validCoins);
sack();
}
public static void sack() {
Map<Integer, Integer> coins = new TreeMap<Integer, Integer>();
coins.put(0, 0);
int a = 0;
for(int i = 1; i <= TARGET; i++) {
if(a < validCoins.length && i == validCoins[a]) {
coins.put(i, 1);
a++;
} else coins.put(i, -1);
}
for(int x = 2; x <= TARGET; x++) {
if(x % 5000 == 0) System.out.println("AT: " + x);
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i = 0; i <= x / 2; i++) {
int j = x - i;
list.add(i);
list.add(j);
}
coins.put(x, min(list, coins));
}
System.out.println("It takes " + coins.get(TARGET) + " coins to reach the target of " + TARGET);
}
public static int min(ArrayList<Integer> combos, Map<Integer, Integer> coins) {
int min = Integer.MAX_VALUE;
int total = 0;
for(int i = 0; i < combos.size() - 1; i += 2) {
int x = coins.get(combos.get(i));
int y = coins.get(combos.get(i + 1));
if(x < 0 || y < 0) continue;
else {
total = x + y;
if(total > 0 && total < min) {
min = total;
}
}
}
int t = (min == Integer.MAX_VALUE || min < 0) ? -1:min;
return t;
}
}
EDIT: Upon research I think that the complexity is O(k*n^2) where n is the target, and k is the number of coins supplied, is this correct?
I thinky the code you provided is kind of chaotic. So this post is more about the conceptual algorithm instead of the real algorithm. This can differ a bit since for instance insertion in an ArrayList<T> is not O(1), but I'm confident that you can use good datastructures (for instance LinkedList<T>s) for this to let all operations run in constant time.
What your algorithm basically does is the following:
It starts with a map that maps all the given coins to one: it requires one coin to achieve the value on the coin.
For each iteration, it mixes all already achieved values with all already achieved values. The result is thus the sum of the coins and it takes at the sum of the number of coins unless it was already present in the collection.
This step you forgot: kick out values strictly larger than the requested value: since all coins are strictly positive, you will never be able to construct a value with such composition less than the requested value.
You keep doing this until you have constructed the requested coin value.
If at iteration i all new values added to the set are strictly larger than the requested value, you can stop: the requested value can't be constructed.
The parameters are:
n: the number of coins.
r: the requested value.
A first observation is that each step of (2.) requires O(s^2) time with s the number of elements in the set at the start of the iteration: this is because you match every value with every value.
A second observation is that you can never have more elements in the set than the requested value. This means that s is bounded by O(r) (we assume all coins are integers, thus the set can contain at most all integer values from 0 to r-1). Step (2.) has thus a maximum time complexity of O(r^2).
And furthermore the set evolves progressively: at each iteration, you will always construct a new value that is at least one larger than the maximum thus far. As a consequence, the algorithm will perform maximum O(r) iterations.
This implies that the algorithm has a time-complexity of O(r^3): r times O(r^2).
Why is the behavior exponential and thus at least NP-hard?
A first argument is that it comes down on how you represent input: in many cases, numbers are represented using a system with a radix greater than or equal to 2. This means that with k characters, you can represent a value that scales with O(g^k) with g the radix. Thus exponential. In other words, if you use a 32-bit number, worst case, r=O(2^32). So if you take this as input, there is an exponential part. If you would encode the target using unary notation, the algorithm is in P. But of course that's a bit like the padding-argument: given you provide enough useless input data (exponential or even super-exponential), all algorithms are in P, but you don't buy much with this.
A second argument is that if you leave the the requested value out of the input, you can only state that you start with n coins. You know that the number of iterations is fixed: you see the target value as an unknown constant. Each iteration, the total number of values in the Map<Integer,Integer> potentially squares. This thus means that the computational effort is:
n+n^2+n^4+n^6+...n^(log r)
^ ^ ^
| \-- first iteration \-- end of algorithm
\-- insertion
It is clear that this behavior is exponential in n.

Big negative integer representation in a LinkedList

My LinkedList represents big numbers by having one digit in each of the nodes.
I can represent positive big integers in a LinkedList with this code:
public BigInteger(int x)
{
list = new LinkedList<Integer>();
while (x > 0)
{
list.push(( x % 10 ));
x = x / 10;
}
}
Declaring:
BigInteger bigPositive = new BigInteger(91234)
Produces:
[9,1,2,3,4]
However, I am not sure how to represent big negative integers such as -9321312345
You could push a 1 or a 0 to the front of the list, indicating whether it was positive or negative. For instance:
(15) would map to [1 1 5]
(-13) would map to [0 1 3]
(1) would map to [1 1]
And so on. You'd just have to know to interpret that first number as a sign (+/-), and not part of the value.
If BigInteger is your own custom class, you could add a Boolean property that determines whether the integer is positive or negative.
Then, in your constructor, you could determine the sign of the integer and set that property accordingly.
public BigInteger(int x) this value for int x the input itself would be the limit so you can never go over.
Why not just have ?
public BigInteger(int x){
bigIntValue = x;
}
Because that's not the point. You want to be able to create values bigger then the intended int from the input.
The better option IMO would be something along the lines of add a String as the input then having an operation that can push int's or something you want into the back or front of the linklist.
public BigInteger(String x)
{
int endLoop = 0;
list = new LinkedList<char>();
// have a boolean for negative in your class then multiple by
// negative one to your operations if its true.
if(x.charAt(0) == '-'){
this.negative = true;
endLoop = 1;
}
list = new LinkedList<char>();
int i = x.length() - 1;
while(i >= endLoop) {
if(!validNumber(x.charAt(i)) //fail
list.push(( x.charAt(i)));
i--;
}
}
// this checks if it's a number.
boolean validNumber(char n){
for(int i = 48; i =< 57; i++){
if(n = i) return true;
}
return false;
}
You can even change the type of your lists to int if you want by writing a converter from char to int.
You could do the same they do in binary; by having the firstmost digit determine the sign
0b0100 == 4
0b1100 == -4
Similarly you could write
{0, 1, 1} == 11
{1, 1, 1} == -11,
Although this deviates from the initial idea; since you ARE working with integers, you could do this:
{-1, 1} == -11
{ 1, 1} == 11

Categories