We have an strictly increasing array of length n ( 1 < n < 500) . We sum the digits of each element to create a new array with each elements values is in range 1 to 500.The task is to rebuild the old array from the new one. since there might be more than one answer, we want the answers with the minimum value of the last element.
Example:
3 11 23 37 45 123 =>3 2 5 10 9 6
now from the second array, we can rebuild the original array in many different ways for instance:
12 20 23 37 54 60
from all the possible combinations, we need the one we minimum last element.
My Thoughts so far:
The brute force way is to find all possible permutations to create each number and then create all combinations possible of all numbers of the second array and find the combination with minimum last element. It is obvious that this is not a good choice.
Using this algorithm(with exponential time!) we can create all possible permutations of digits that sum to a number in the second arrays. Note that we know the original elements were less than 500 so we can limit the death of search of the algorithm.
One way I thought of that might find the answer faster is to:
start from the last element in the new arrays and find all possible
numbers that their digit sum resulted this element.
Then try to use the smallest amount in the last step for this element.
Now try to do the same with the second to last element. If the
minimum permutation value found for the second to last element is bigger
than the one found for the last element, backtrack to the last
element and try a larger permutation.
Do this until you get to the first element.
I think this is a greed solution but I'm not very sure about the time complexity. Also I want to know is there a better solution for this problem? like using dp?
For simplicity, let's have our sequence 1-based and the input sequence is called x.
We will also use an utility function, which returns the sum of the digits of a given number:
int sum(int x) {
int result = 0;
while (x > 0) {
result += x % 10;
x /= 10;
}
return result;
}
Let's assume that we are at index idx and try to set there some number called value (given that the sum of digits of value is x[idx]). If we do so, then what could we say about the previous number in the sequence? It should be strictly less than value.
So we already have a state for a potential dp approach - [idx, value], where idx is the index where we are currently at and value denotes the value we are trying to set on this index.
If the dp table holds boolean values, we will know we have found an answer if we have found a suitable number for the first number in the sequence. Therefore, if there is a path starting from the last row in the dp table and ends at row 0 then we'll know we have found an answer and we could then simply restore it.
Our recurrence function will be something like this:
f(idx, value) = OR {dp[idx - 1][value'], where sumOfDigits(value) = x[idx] and value' < value}
f(0, *) = true
Also, in order to restore the answer, we need to track the path. Once we set any dp[idx][value] cell to be true, then we can safe the value' to which we would like to jump in the previous table row.
Now let's code that one. I hope the code is self-explanatory:
boolean[][] dp = new boolean[n + 1][501];
int[][] prev = new int[n + 1][501];
for (int i = 0; i <= 500; i++) {
dp[0][i] = true;
}
for (int idx = 1; idx <= n; idx++) {
for (int value = 1; value <= 500; value++) {
if (sum(value) == x[idx]) {
for (int smaller = 0; smaller < value; smaller++) {
dp[idx][value] |= dp[idx - 1][smaller];
if (dp[idx][value]) {
prev[idx][value] = smaller;
break;
}
}
}
}
}
The prev table only keeps information about which is the smallest value', which we can use as previous to our idx in the resulting sequence.
Now, in order to restore the sequence, we can start from the last element. We would like it to be minimal, so we can find the first one that has dp[n][value] = true. Once we have such element, we then use the prev table to track down the values up to the first one:
int[] result = new int[n];
int idx = n - 1;
for (int i = 0; i <= 500; i++) {
if (dp[n][i]) {
int row = n, col = i;
while (row > 0) {
result[idx--] = col;
col = prev[row][col];
row--;
}
break;
}
}
for (int i = 0; i < n; i++) {
out.print(result[i]);
out.print(' ');
}
If we apply this on an input sequence:
3 2 5 10 9 6
we get
3 11 14 19 27 33
The time complexity is O(n * m * m), where n is the number of elements we have and m is the maximum possible value that an element could hold.
The space complexity is O(n * m) as this is dominated by the size of the dp and prev tables.
We can use a greedy algorithm: proceed through the array in order, setting each element to the least value that is greater than the previous element and has digits with the appropriate sum. (We can just iterate over the possible values and check the sums of their digits.) There's no need to consider any greater value than that, because increasing a given element will never make it possible to decrease a later element. So we don't need dynamic programming here.
We can calculate the sum of the digits of an integer m in O(log m) time, so the whole solution takes O(b log b) time, where b is the upper bound (500 in your example).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
So I was solving this code in codefight and I stumbled upon this solution, I am not able to understand the return statment. If anyone can help me that'd be great.
int MakeArrayConsecutive2(std::vector<int>statues){
Arrays.sort(statues);
return statues[statues.Length-1]-statues[0]-statues.Length+1;
}
Here is my solution to this problem in PYTHON. I've tried to explain each step so that you can apply this to any language
My Solution:
a) First, sorting the array from least to greatest would make this process simpler,
thankfully there's a built in method for that ( called .sort())
b) fL loops from 0 to the second last element in the array (also look at the while statement)
c) sL loops from 1 to the last element in the array (also look at the while statement)
d) the differences variable keeps track of the number of statues needed to fill in between two consecutive numbers
so say the numbers were 5 and 9, differences would hold 3 because you need three statues (6,7,8) to go in-between those two numbers.
e) Inside the while loop, it records the number of statues that can go in-between every adjacent pairs.
f) Inside the if statement, if difference between two consecutive number is more than one
(ie. The difference between 6 and 7 is 1, but you cant put a statue in-between, so we look for a difference of higher than 1 for each consecutive pairs).
g) fL and sL are incremented by 1 as they continue the loop.
def makeArrayConsecutive2(statues):
# a
statues.sort()
# b
fL = 0
# c
sL = 1
lastItem = len(statues)-1
# d
differences = 0
# e
while (fL <= lastItem - 1) and (sL <= lastItem):
# f
if statues[sL] - statues[fL] > 1:
differences += (statues[sL] - statues[fL] - 1)
# g
fL += 1
sL += 1
return differences
My approach is a pretty straight forward and runs in linear time.
I subtract the number of elements currently in statues FROM
the number of elements that should be in statues.
def makeArrayConsecutive2(statues):
return (max(statues)-min(statues)+1)-len(statues)
So the first test case: [6,2,3,8]
number of elements that should be in statues: 7
number of element currently in statues: 4
7 - 4 = 3
(8-2 + 1) - (4) = 3, which is the correct answer
No one seems to have answered the person's question...
for the code:
int MakeArrayConsecutive2(std::vector<int>statues){
Arrays.sort(statues);
return statues[statues.Length-1]-statues[0]-statues.Length+1;
}
The way this works is we are given an unordered list of integers but after sorting it, the min and the max will be the first and last element in the array. (that is a rule about sorting which will cause this problem to be a big O of n log n) the way the return works is that max - min - len + 1 will tell you how many numbers are missing between the range of min and max. In order to access the last element you will need to be at the end of the array which is equal to the length - 1.
The min is the first element so to access that C++ uses zero based indexing.
the length tells us how many elements are in the range.
the plus 1 is a little bit harder to explain but if we look at a complete array we see why the +1 helps.
take 1,2,3
min = 1
max = 3
3 -1 - 3 = -1... that does not seem right so using +1 we get an answer of 0
I hope this helps!
Simple Java Solution would be to sort the array first and check the difference between the consecutive elements
int makeArrayConsecutive(int[] statues) {
Arrays.sort(statues);
int count = 0;
for(int i = 1;i<statues.length;i++)
{
int diff= statues[i]-statues[i-1];
if(diff != 1)
count = count + (p-1);
}
return count;
}
This is my solution in c#.
Works for all test cases.
int makeArrayConsecutive2(int[] statues) {
return (((statues.Max()-statues.Min()) + 1) - statues.Length);
}
Here is my solution to this problem in PHP.
Steps -:
1) Get minimum and maximum values of $statues array.
2) Defined a new array called $newArray.
3) Defined $loopLen for how many times loop will run.
4) After looping try to get same values between two arrays
$minVal = min($statues);
$maxVal = max($statues);
$newArray = [];
$loopLen = $maxVal - $minVal;
for($i = 0; $i <= $loopLen; $i++) {
$newArray[$i] = $minVal;
$minVal++;
}
$result = array_intersect($statues,$newArray);
$sResult = sizeof($result);
$newArrLen = sizeof($newArray);
$fresult = $newArrLen - $sResult;
return $fresult;
List<Integer> collect = Arrays.stream(statues)
.boxed()
.sorted(Comparator.comparingInt(a -> a))
.collect(toList());
int counter = 0;
for (int i = 1; i < collect.size(); i++){
if(!(collect.get(i - 1) + 1 == collect.get(i))){
counter += collect.get(i) - collect.get(i - 1) - 1;
}
}
return counter;
int makeArrayConsecutive2(int[] statues) {
return statues.Max()-statues.Min()-statues.Length+1;
}
In C++
int makeArrayConsecutive2(std::vector<int> vec) {
// find the maximum number
int maxNum=*max_element(vec.begin(), vec.end());
// find the minimum number
int minNum=*min_element(vec.begin(), vec.end());
// find vector size
int sizVec=vec.size();
return ((maxnum - minnum)+1)-sizVec;
}
I solved it Iteratively using a merge-sort function`
`
//Sort the array using merge sort
function mergeSort(arr){
if(arr.length <= 1) return arr;
//divide the array into half and sort the left and right side
let middle = Math.floor(arr.length/2);
let left = arr.slice(0, middle);
let right = arr.slice(middle);
let leftSorted = mergeSort(left);
let rightSorted = mergeSort(right);
return merge(leftSorted, rightSorted)
}
function merge(left, right){
let result = [];
let leftIndex = 0; rightIndex = 0;
while(leftIndex < left.length && rightIndex < right.length){
if(left[leftIndex]< right[rightIndex]){
result.push(left[leftIndex]);
leftIndex++
}else{
result.push(right[rightIndex]);
rightIndex++
}
}
return result
.concat(left.slice(leftIndex))
.concat(right.slice(rightIndex))
}
function makeArrayConsecutive2(statues) {
statues = mergeSort(statues);
return(statues[statues.length-1]-statues[0]+1-statues.length);
}
`
int makeArrayConsecutive2(std::vector<int> statues) {
int max=0,min=0;
int n=statues.size();
max=statues[0];
min=statues[0];
for(int i=0;i<n;i++){
if(max<statues[i])
max=statues[i];
if(min>statues[i])
min=statues[i];
}
int total=max-min+1;
int noofelements=total-n;
return add;
}
we just need to find the number of elements that are missing in sorted array, so to calculate that we need to find how many elements were supposed to be there(which will be equal to (max-min+1) of array, and as we already have arr.length() elements we just need to subtract both
In Java:
int makeArrayConsecutive2(int[] statues) {
Arrays.sort(statues);
return IntStream.range(1,statues.length).map(
i -> statues[i]-statues[i-1]
).filter(
diff -> diff !=1
).map(
diff -> (diff -1)
).sum();
}
Here's my approach in Haskell
makeArrayConsecutive2 statues =
-- Create a list that ranges from the minimum to the maximum of statues which are not in statues, then get its length
length [x | x <- [(minimum statues)..(maximum statues)], not (x `elem` statues)]
In PHP
function makeArrayConsecutive2($statues) {
$missing = [];
$min = min($statues);
$max = max($statues);
for($j=$min;$j<$max;$j++){
if(!in_array($j,$statues)){
$missing[] = $j;
}
}
return count($missing);
}
In PHP
function makeArrayConsecutive2($statues) {
$missing = [];
$min = min($statues);
$max = max($statues);
for($j=$min;$j<$max;$j++){
if(!in_array($j,$statues)){
$missing[] = $j;
}
}
return count($missing);
}
I'm trying to create an algorithm to create n strings of random length the sum of which is equal to a given amount.
An example to make it clearer:
total = 20;
n = 7;
strings = ['aaaa', 'a', 'aaaaaaa', 'aa', 'aaa', 'aa', 'a'];
So I have 7 strings of random lengths and the sum of their individual lengths is (unless I made an error counting) 20.
Till now I came up with this recursive function:
gaps = [];
function createGapsArray(total, n) {
if (n == 1) {
var gapLength = total;
} else {
var gapLength = getRandomInt(1, total / 2);
}
var gap = "";
for (var i = 0; i < gapLength; i++) {
gap += "a";
}
gaps.push(gap);
if (n > 1 && total > 0) {
createGapsArray(total - gapLength, --n);
}
}
Which doesn't really work. Usually it finishes before generating all the n segments I want. With the few tests that I've done, it seems that dividing the total by 4 instead of 2, gets the job done. Like:
var gapLength = getRandomInt(1, total / 4);
But the choice of this constraint is just arbitrary. I'm wondering if there is a better approach to this.
Also, I'm aware that with my approach the algorithm is likely to generate longer segments at first and smaller ones towards the end. I wouldn't mind an even distribution, but it's not a big deal because for what I need it I can simply shuffle the array once it's done.
This is a similar problem to "find a random collection of k numbers whose sum is N". The original version of this answer used a simple solution which is unbiased if the numbers are continuous (i.e. floating point): generate k-1 numbers in the range [0, N], sort them, put 0 at the beginning and N at the end, and then find the differences between successive elements. But since there are no fractional characters, we need the numbers to be integers and the above algorithm is biased against collections which include 0 (there is an infinitesimal probability of getting 0 in the continuous case, but it is significant in the discrete case).
An unbiased solution for generating non-empty integer solutions is to find a random (k-1)-combination of the integers in the inclusive range [1, N-1]. To find the random combination use the first k-1 elements of a random shuffle of the range (using the Fisher-Yates shuffle). The combination is then sorted (if necessary) and a 0 prepended; these values are the starting positions of each string (so that the next value is the ending position.)
That will not produce empty substrings, since each substring has a unique starting point. To include empty substrings, use the above with N+k instead of N, and then shrink every range by 1: if the indices are sorted, you can do that by subtracting i from the ith index.
In Python:
from random import sample
def random_split(str, k):
v = [0] + sorted(sample(range(1, len(str)), k-1)) + [len(str)]
return [str[v[i]:v[i+1]] for i in range(k)]
def random_split_allow_empty(str, k):
v = [0] + sorted(sample(range(1, len(str)+k), k-1)) + [len(str)+k]
return [str[v[i]-i:v[i+1]-i-1] for i in range(k)]
In Javascript:
function shuffle(vec, k) {
for (let i = 0; i < k; ++i) {
let r = i + Math.floor(Math.random() * (vec.length - i));
let t = vec[r];
vec[r] = vec[i];
vec[i] = t;
}
return vec;
}
function random_partition(N, k) {
let v = [];
for (let i = 1; i < N; ++i) v[i-1] = i;
shuffle(v, k - 1);
v[k-1] = 0;
return v.slice(0, k).sort((a,b)=>a-b);
}
function random_split(s, k) {
return random_partition(s.length, k).map(
(v, i, a) => s.slice(v, a[i+1]));
}
function random_split_allow_empty(s, k) {
return random_partition(s.length + k, k).map((v,i)=>v-i).map(
(v, i, a) => s.slice(v, a[i+1]));
}
Strictly speaking, you can't do this, because you're adding constraints to at least the last "string" that violate the desired randomness property. Of course, how strictly you need to interpret the requirement for randomness depends largely on what you're doing in the bigger problem domain.
What you could do instead, is start with an initial string of the desired length, and then iteratively generate a random split point until you have the desired number of fragments. To be truly random, you'd have to allow for some of those fragments to be empty (e.g. what happens if you randomly pick a single-character fragment to split?), but that could probably be worked around without doing too much violence to the randomness of the overall result...
The way to think of it is as having string of characters of length equal to total. I'll use 20 as an example:
string: aaaaaaaaaaaaaaaaaaaa
index: 01234567890123456789
You then generate N-1 random numbers between 0 and total that correspond to the positions that you should cut the string to generate N different strings.
Lets say the numbers are 5, 8, 13, 15, 1, 3. These will be the indices to cut the string:
string: a aa aa aaa aaaaa aa aaaaa
index: 0|12|34|567|89012|34|56789
This is the same as generating N-1 random numbers, sorting them, adding 0 at the beginning of the list and total at the end, and taking the difference:
var numbers = [0];
for (var i = 0; i < N-1; i++) numbers.push(getRandomInt(0, total));
numbers.push(total);
numbers.sort();
var strings = [];
for (var i = 0; i < N; i++)
strings.push(new Array(numbers[i + 1] - numbers[i]).join('a'));
This will give a uniform distribution.
Note that if you want only non-empty strings there should be no duplicate random values.
This question already has answers here:
Algorithm to find elements best fitting in a particular amount
(5 answers)
how do you calculate the minimum-coin change for transaction?
(3 answers)
Closed 9 years ago.
So here is the problem:
Given input = [100 80 66 25 4 2 1], I need to find the best combination to give me 50.
Looking at this, the best would be 25+25 = 50, so I need 2 elements from the array.
Other combinations include 25+4+4+4+4+4+4+1 and 25+4+4+4+4+4+2+2+1.. etc etc
I need to find all the possibilities which gives me the sum on a value I want.
EDIT: As well as the best possibility (one with least number of terms)
Here is what I have done thus far:
First build a new array (simple for loop which cycles through all elements and stores in a new temp array), check for all elements higher than my array (so for input 50, the elements 100,80,66 are higher, so discard them and then my new array is [25 4 2 1]). Then, from this, I need to check combinations.
The first thing I do is a simple if statement checking if any array elements EXACTLY match the number I want. So if I want 50, I check if 50 is in the array, if not, I need to find combinations.
My problem is, I'm not entirely sure how to find every single combination. I have been struggling trying to come up with an algorithm for a while but I always just end up getting stumped.
Any help/tips would be much appreciated.
PS - we can assume the array is always sorted in order from LARGEST to SMALLEST value.
This is the kind of problem that dynamic programming is meant to solve.
Create an array with with indices, 1 to 50. Set each entry to -1. For each element that is in your input array, set that element in the array to 0. Then, for each integer n = 2 to 50, find all possible ways to sum to n. The number of sums required is the minimum of the two addends plus 1. At the end, get the element at index 50.
Edit: Due to a misinterpretation of the question, I first answered with an efficient way to calculate the number of possibilities (instead of the possibilities themself) to get N using values from a given set. That solution can be found at the bottom of this post as a reference for other people, but first I'll give a proper answer to your questions.
Generate all possibilities, count them and give the shortest one
When generating a solution, you consider each element from the input array and ask yourself "should I use this in my solution or not?". Since we don't know the answer until after the calculation, we'll just have to try out both using it and not using it, as can be seen in the recursion step in the code below.
Now, to avoid duplicates and misses, we need to be a bit careful with the parameters for the recursive call. If we use the current element, we should also allow it to be used in the next step, because the element may be used as many times as possible. Therefore, the first parameter in this recursive call is i. However, if we decide to not use the element, we should not allow it to be used in the next step, because that would be a duplicate of the current step. Therefore, the first parameter in this recursive call is i+1.
I added an optional bound (from "branch and bound") to the algorithm, that will stop expanding the current partial solution if it is known that this solution will never be shorter then the shortest solution found so far.
package otherproblems;
import java.util.Deque;
import java.util.LinkedList;
public class GeneratePossibilities
{
// Input
private static int n = 50;
// If the input array is sorted ascending, the shortest solution is
// likely to be found somewhere at the end.
// If the input array is sorted descending, the shortest solution is
// likely to be found somewhere in the beginning.
private static int[] input = {100, 80, 66, 25, 4, 2, 1};
// Shortest possibility
private static Deque<Integer> shortest;
// Number of possibilities
private static int numberOfPossibilities;
public static void main(String[] args)
{
calculate(0, n, new LinkedList<Integer>());
System.out.println("\nAbove you can see all " + numberOfPossibilities +
" possible solutions,\nbut this one's the shortest: " + shortest);
}
public static void calculate(int i, int left, Deque<Integer> partialSolution)
{
// If there's nothing left, we reached our target
if (left == 0)
{
System.out.println(partialSolution);
if (shortest == null || partialSolution.size() < shortest.size())
shortest = new LinkedList<Integer>(partialSolution);
numberOfPossibilities++;
return;
}
// If we overshot our target, by definition we didn't reach it
// Note that this could also be checked before making the
// recursive call, but IMHO this gives a cleaner recursion step.
if (left < 0)
return;
// If there are no values remaining, we didn't reach our target
if (i == input.length)
return;
// Uncomment the next two lines if you don't want to keep generating
// possibilities when you know it can never be a better solution then
// the one you have now.
// if (shortest != null && partialSolution.size() >= shortest.size())
// return;
// Pick value i. Note that we are allowed to pick it again,
// so the argument to calculate(...) is i, not i+1.
partialSolution.addLast(input[i]);
calculate(i, left-input[i], partialSolution);
// Don't pick value i. Note that we are not allowed to pick it after
// all, so the argument to calculate(...) is i+1, not i.
partialSolution.removeLast();
calculate(i+1, left, partialSolution);
}
}
Calculate the number of possibilities efficiently
This is a nice example of dynamic programming. What you need to do is figure out how many possibilities there are to form the number x, using value y as the last addition and using only values smaller than or equal to y. This gives you a recursive formula that you can easily translate to a solution using dynamic programming. I'm not quite sure how to write down the mathematics here, but since you weren't interested in them anyway, here's the code to solve your question :)
import java.util.Arrays;
public class Possibilities
{
public static void main(String[] args)
{
// Input
int[] input = {100, 80, 66, 25, 4, 2, 1};
int n = 50;
// Prepare input
Arrays.sort(input);
// Allocate storage space
long[][] m = new long[n+1][input.length];
for (int i = 1; i <= n; i++)
for (int j = 0; j < input.length; j++)
{
// input[j] cannot be the last value used to compose i
if (i < input[j])
m[i][j] = 0;
// If input[j] is the last value used to compose i,
// it must be the only value used in the composition.
else if (i == input[j])
m[i][j] = 1;
// If input[j] is the last value used to compose i,
// we need to know the number of possibilities in which
// i - input[j] can be composed, which is the sum of all
// entries in column m[i-input[j]].
// However, to avoid counting duplicates, we only take
// combinations that are composed of values equal or smaller
// to input[j].
else
for (int k = 0; k <= j; k++)
m[i][j] += m[i-input[j]][k];
}
// Nice output of intermediate values:
int digits = 3;
System.out.printf(" %"+digits+"s", "");
for (int i = 1; i <= n; i++)
System.out.printf(" %"+digits+"d", i);
System.out.println();
for (int j = 0; j < input.length; j++)
{
System.out.printf(" %"+digits+"d", input[j]);
for (int i = 1; i <= n; i++)
System.out.printf(" %"+digits+"d", m[i][j]);
System.out.println();
}
// Answer:
long answer = 0;
for (int i = 0; i < input.length; i++)
answer += m[n][i];
System.out.println("\nThe number of possibilities to form "+n+
" using the numbers "+Arrays.toString(input)+" is "+answer);
}
}
This is the integer knapsack problem, which is one your most common NP-complete problems out there; if you are into algorithm design/study check those out. To find the best I think you have no choice but to compute them all and keep the smallest one.
For the correct solution there is a recursive algorithm that is pretty simple to put together.
import org.apache.commons.lang.ArrayUtils;
import java.util.*;
public class Stuff {
private final int target;
private final int[] steps;
public Stuff(int N, int[] steps) {
this.target = N;
this.steps = Arrays.copyOf(steps, steps.length);
Arrays.sort(this.steps);
ArrayUtils.reverse(this.steps);
this.memoize = new HashMap<Integer, List<Integer>>(N);
}
public List<Integer> solve() {
return solveForN(target);
}
private List<Integer> solveForN(int N) {
if (N == 0) {
return new ArrayList<Integer>();
} else if (N > 0) {
List<Integer> temp, min = null;
for (int i = 0; i < steps.length; i++) {
temp = solveForN(N - steps[i]);
if (temp != null) {
temp.add(steps[i]);
if (min == null || min.size() > temp.size()) {
min = temp;
}
}
}
return min;
} else {
return null;
}
}
}
It is based off the fact that to "get to N" you to have come from N - steps[0], or N - steps1, ...
Thus you start from your target total N and subtract one of the possible steps, and do it again until you are at 0 (return a List to specify that this is a valid path) or below (return null so that you cannot return an invalid path).
The complexity of this correct solution is exponential! Which is REALLY bad! Something like O(k^M) where M is the size of the steps array and k a constant.
To get a solution to this problem in less time than that you will have to use a heuristic (approximation) and you will always have a certain probability to have the wrong answer.
You can make your own implementation faster by memorizing the shortest combination seen so far for all targets (so you do not need to recompute recur(N, _, steps) if you already did). This approach is called Dynamic Programming. I will let you do that on your own (very fun stuff and really not that complicated).
Constraints of this solution : You will only find the solution if you guarantee that the input array (steps) is sorted in descending order and that you go through it in that order.
Here is a link to the general Knapsack problem if you also want to look approximation solutions: http://en.wikipedia.org/wiki/Knapsack_problem
You need to solve each sub-problem and store the solution. For example:
1 can only be 1. 2 can be 2 or 1+1. 4 can be 4 or 2+2 or 2+1+1 or 1+1+1+1. So you take each sub-solution and store it, so when you see 25=4+4+4+4+4+4+1, you already know that each 4 can also be represented as one of the 3 combinations.
Then you have to sort the digits and check to avoid duplicate patterns since, for example, (2+2)+(2+2)+(2+2)+(1+1+1+1)+(1+1+1+1)+(1+1+1+1) == (2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1). Six 2's and twelve 1's in both cases.
Does that make sense?
Recursion should be the easiest way to solve this (Assuming you really want to find all the solutions to the problem). The nice thing about this approach is, if you want to just find the shortest solution, you can add a check on the recursion and find just that, saving time and space :)
Assuming an element i of your array is part of the solution, you can solve the subproblem of finding the elements that sums to n-i. If we add an ordering to our solution, for example the numbers in the sum must be from the greater to the smallest, we have a way to find unique solutions.
This is a recursive solution in C#, it should be easy to translate it in java.
public static void RecursiveSum(int n, int index, List<int> lst, List<int> solution)
{
for (int i = index; i < lst.Count; i++)
{
if (n == 0)
{
Console.WriteLine("");
foreach (int j in solution)
{
Console.Write(j + " ");
}
}
if (n - lst[i] >= 0)
{
List<int> tmp = new List<int>(solution);
tmp.Add(lst[i]);
RecursiveSum(n - lst[i], i, lst, tmp);
}
}
}
You call it with
RecursiveSum(N,0,list,new List<int>());
where N is the sum you are looking for, 0 shouldn't be changed, list is your list of allowed numbers, and the last parameter shouldn't be changed either.
The problem you pose is interesting but very complex. I'd approach this by using something like OptaPlanner(formerly Drools Planner). It's difficult to describe a full solution to this problem without spending significant time, but with optaplanner you can also get "closest fit" type answers and can have incremental "moves" that would make solving your problem more efficient. Good luck.
This is a solution in python: Ideone link
# Start of tsum function
def tsum(currentSum,total,input,record,n):
if total == N :
for i in range(0,n):
if record[i]:
print input[i]
i = i+1
for i in range(i,n):
if record[i]:
print input[i]
print ""
return
i=currentSum
for i in range(i,n):
if total+input[i]>sum :
continue
if i>0 and input[i]==input[i-1] and not record[i-1] :
continue
record[i]=1
tsum(i+1,total+input[i],input,record,l)
record[i]=0
# end of function
# Below portion will be main() in Java
record = []
N = 5
input = [3, 2, 2, 1, 1]
temp = list(set(input))
newlist = input
for i in range(0, len(list(set(input)))):
val = N/temp[i]
for j in range(0, val-input.count(temp[i])):
newlist.append(temp[i])
# above logic was to create a newlist/input i.e [3, 2, 2, 1, 1, 1, 1, 1]
# This new list contains the maximum number of elements <= N
# for e.g appended three 1's as sum of new three 1's + existing two 1's <= N(5) where as
# did not append another 2 as 2+2+2 > N(5) or 3 as 3+3 > N(5)
l = len(input)
for i in range(0,l):
record.append(0)
print "all possibilities to get N using values from a given set:"
tsum(0,0,input,record,l)
OUTPUT: for set [3, 2, 2, 1, 1] taking small set and small N for demo purpose. But works well for higher N value as well.
For N = 5
all possibilities to get N using values from a given set:
3
2
3
1
1
2
2
1
2
1
1
1
1
1
1
1
1
For N = 3
all possibilities to get N using values from a given set:
3
2
1
1
1
1
Isn't this just a search problem? If so, just search breadth-first.
abstract class Numbers {
abstract int total();
public static Numbers breadthFirst(int[] numbers, int total) {
List<Numbers> stack = new LinkedList<Numbers>();
if (total == 0) { return new Empty(); }
stack.add(new Empty());
while (!stack.isEmpty()) {
Numbers nums = stack.remove(0);
for (int i : numbers) {
if (i > 0 && total - nums.total() >= i) {
Numbers more = new SomeNumbers(i, nums);
if (more.total() == total) { return more; }
stack.add(more);
}
}
}
return null; // No answer.
}
}
class Empty extends Numbers {
int total() { return 0; }
public String toString() { return "empty"; }
}
class SomeNumbers extends Numbers {
final int total;
final Numbers prev;
SomeNumbers(int n, Numbers prev) {
this.total = n + prev.total();
this.prev = prev;
}
int total() { return total; }
public String toString() {
if (prev.getClass() == Empty.class) { return "" + total; }
return prev + "," + (total - prev.total());
}
}
What about using the greedy algorithm n times (n is the number of elements in your array), each time popping the largest element off the list. E.g. (in some random pseudo-code language):
array = [70 30 25 4 2 1]
value = 50
sort(array, descending)
solutions = [] // array of arrays
while length of array is non-zero:
tmpValue = value
thisSolution = []
for each i in array:
while tmpValue >= i:
tmpValue -= i
thisSolution.append(i)
solutions.append(thisSolution)
array.pop_first() // remove the largest entry from the array
If run with the set [70 30 25 4 2 1] and 50, it should give you a solutions array like this:
[[30 4 4 4 4 4]
[30 4 4 4 4 4]
[25 25]
[4 4 4 4 4 4 4 4 4 4 4 4 2]
[2 ... ]
[1 ... ]]
Then simply pick the element from the solutions array with the smallest length.
Update: The comment is correct that this does not generate the correct answer in all cases. The reason is that greedy isn't always right. The following recursive algorithm should always work:
array = [70, 30, 25, 4, 3, 1]
def findSmallest(value, array):
minSolution = []
tmpArray = list(array)
while len(tmpArray):
elem = tmpArray.pop(0)
tmpValue = value
cnt = 0
while tmpValue >= elem:
cnt += 1
tmpValue -= elem
subSolution = findSmallest(tmpValue, tmpArray)
if tmpValue == 0 or subSolution:
if not minSolution or len(subSolution) + cnt < len(minSolution):
minSolution = subSolution + [elem] * cnt
return minSolution
print findSmallest(10, array)
print findSmallest(50, array)
print findSmallest(49, array)
print findSmallest(55, array)
Prints:
[3, 3, 4]
[25, 25]
[3, 4, 4, 4, 4, 30]
[30, 25]
The invariant is that the function returns either the smallest set for the value passed in, or an empty set. It can then be used recursively with all possible values of the previous numbers in the list. Note that this is O(n!) in complexity, so it's going to be slow for large values. Also note that there are numerous optimization potentials here.
I made a small program to help with one solution. Personally, I believe the best would be a deterministic mathematical solution, but right now I lack the caffeine to even think on how to implement it. =)
Instead, I went with a SAR approach. Stop and Reverse is a technique used on stock trading (http://daytrading.about.com/od/stou/g/SAR.htm), and is heavily used to calculate optimal curves with a minimal of inference. The Wikipedia entry for parabolical SAR goes like this:
'The Parabolic SAR is calculated almost independently for each trend
in the price. When the price is in an uptrend, the SAR emerges below
the price and converges upwards towards it. Similarly, on a
downtrend, the SAR emerges above the price and converges
downwards.'
I adapted it to your problem. I start with a random value from your series. Then the code enters a finite number of iterations.
I pick another random value from the series stack.
If the new value plus the stack sum is inferior to the target, then the value is added; if superior, then decreased.
I can go on for as much as I want until I satisfy the condition (stack sum = target), or abort if the cycle can't find a valid solution.
If successful, I record the stack and the number of iterations. Then I redo everything.
An EXTREMELY crude code follows. Please forgive the hastiness. Oh, and It's in C#. =)
Again, It does not guarantee that you'll obtain the optimal path; it's a brute force approach. It can be refined; detect if there's a perfect match for a target hit, for example.
public static class SAR
{
//I'm considering Optimal as the smallest signature (number of members).
// Once set, all future signatures must be same or smaller.
private static Random _seed = new Random();
private static List<int> _domain = new List<int>() { 100, 80, 66, 24, 4, 2, 1 };
public static void SetDomain(string domain)
{
_domain = domain.Split(',').ToList<string>().ConvertAll<int>(a => Convert.ToInt32(a));
_domain.Sort();
}
public static void FindOptimalSAR(int value)
{
// I'll skip some obvious tests. For example:
// If there is no odd number in domain, then
// it's impossible to find a path to an odd
// value.
//Determining a max path run. If the count goes
// over this, it's useless to continue.
int _maxCycle = 10;
//Determining a maximum number of runs.
int _maxRun = 1000000;
int _run = 0;
int _domainCount = _domain.Count;
List<int> _currentOptimalSig = new List<int>();
List<String> _currentOptimalOps = new List<string>();
do
{
List<int> currSig = new List<int>();
List<string> currOps = new List<string>();
int _cycle = 0;
int _cycleTot = 0;
bool _OptimalFound = false;
do
{
int _cursor = _seed.Next(_domainCount);
currSig.Add(_cursor);
if (_cycleTot < value)
{
currOps.Add("+");
_cycleTot += _domain[_cursor];
}
else
{
// Your situation doesn't allow for negative
// numbers. Otherwise, just enable the two following lines.
// currOps.Add("-");
// _cycleTot -= _domain[_cursor];
}
if (_cycleTot == value)
{
_OptimalFound = true;
break;
}
_cycle++;
} while (_cycle < _maxCycle);
if (_OptimalFound)
{
_maxCycle = _cycle;
_currentOptimalOps = currOps;
_currentOptimalSig = currSig;
Console.Write("Optimal found: ");
for (int i = 0; i < currSig.Count; i++)
{
Console.Write(currOps[i]);
Console.Write(_domain[currSig[i]]);
}
Console.WriteLine(".");
}
_run++;
} while (_run < _maxRun);
}
}
And this is the caller:
String _Domain = "100, 80, 66, 25, 4, 2, 1";
SAR.SetDomain(_Domain);
Console.WriteLine("SAR for Domain {" + _Domain + "}");
do
{
Console.Write("Input target value: ");
int _parm = (Convert.ToInt32(Console.ReadLine()));
SAR.FindOptimalSAR(_parm);
Console.WriteLine("Done.");
} while (true);
This is my result after 100k iterations for a few targets, given a slightly modified series (I switched 25 for 24 for testing purposes):
SAR for Domain {100, 80, 66, 24, 4, 2, 1}
Input target value: 50
Optimal found: +24+24+2.
Done.
Input target value: 29
Optimal found: +4+1+24.
Done.
Input target value: 75
Optimal found: +2+2+1+66+4.
Optimal found: +4+66+4+1.
Done.
Now with your original series:
SAR for Domain {100, 80, 66, 25, 4, 2, 1}
Input target value: 50
Optimal found: +25+25.
Done.
Input target value: 75
Optimal found: +25+25+25.
Done.
Input target value: 512
Optimal found: +80+80+66+100+1+80+25+80.
Optimal found: +66+100+80+100+100+66.
Done.
Input target value: 1024
Optimal found: +100+1+80+80+100+2+100+2+2+2+25+2+100+66+25+66+100+80+25+66.
Optimal found: +4+25+100+80+100+1+80+1+100+4+2+1+100+1+100+100+100+25+100.
Optimal found: +80+80+25+1+100+66+80+80+80+100+25+66+66+4+100+4+1+66.
Optimal found: +1+100+100+100+2+66+25+100+66+100+80+4+100+80+100.
Optimal found: +66+100+100+100+100+100+100+100+66+66+25+1+100.
Optimal found: +100+66+80+66+100+66+80+66+100+100+100+100.
Done.
Cons: It is worth mentioning again: This algorithm does not guarantee that you will find the optimal values. It makes a brute-force approximation.
Pros: Fast. 100k iterations may initially seem a lot, but the algorithm starts ignoring long paths after it detects more and more optimized paths, since it lessens the maximum allowed number of cycles.
I have a big 2-D array, array[length][2]. the length= 500000.
In array[i][0]= hex number, array[i][1]= 0 or 1, which represents some information related to each hex number. Like this:
array[i][0] array[i][1]
e05f56f8 1
e045ac44 1
e05f57fc 1
e05f57b4 1
e05ff8dc 0
e05ff8ec 0
e05ff900 1
I want to get a new array which stores: the hex number,# of occurance, the sum of array[i][1] of the same hex number.
I write the code like this:
//First Sort the array according to array[][0]
int x,y,temp1,temp2;
for (x=lines_num1-2;x>=0;x--)
{
for (y=0;y<=x;y++)
{
if(array[y][0]>array[y+1][0])
{
temp1=array[y][0];
array[y][0]=array[y+1][0];
array[y+1][0]=temp1;
temp2=array[y][1];
array[y][1]=array[y+1][1];
array[y+1][1]=temp2;
}
}
}
// generate the new_array[][]
int new_array[length][3];
int n=0;
for (n=0; n<length; n++){
new_array[n][0]=0;
new_array[n][1]=0;
new_array[n][2]=0;
}
int prev = array[0][0];
new_array[0][0]=array[0][0];
new_array[0][1]=1;
new_array[0][2]=array[0][2];
for (k=1;k<length;k++)
{
if (array[k][0] == prev)
{
new_array[n][1]=new_array[n][1]+1;
new_array[n][2]=new_array[n][2]+array[k][0];
}else{
prev = array[k][0];
new_array[n+1][0]=array[k][0];
new_array[n+1][1]=new_array[n+1][1]+1;
new_array[n+1][2]=new_array[n+1][2]+array[k][0];
n++;
}
}
But the code seems not work as I expected. First the sorting is so slow. And It seems cannot generate the correct new_array. Any suggestion on how to deal with this.
Personally, I would write a hash function to index the result array with the hexadecimal value directly. Then it is simple:
struct {
unsigned int nocc;
unsigned int nsum;
} result[/* ... */];
/* calculate the results */
for (i = 0; i < LENGTH; ++i) {
int *curr = &array[i];
unsigned int index = hash(curr[0]);
result[index].nocc++;
result[index].nsum += curr[1];
}
If you want to sort your array, don't reinventing the wheel: use qsort from the standard C library.
Sorting is slow because you're using bubble sort to sort the data. Bubble sort has quadratic average complexity, which means it has to perform more then 100 billion comparisons and swaps to sort your array. For this reason, never use bubble sort. Instead, learn to use the qsort library function and apply it to your problem.
Also, your sorting code has at least one bug: when exchanging values for the second column of the array, you are getting the value with the wrong column index, [3] instead of [1].
For your scenario insertion sort is the right solution, while doing the insertion itself you could make the #count and the sum. When the sort is finished, you will have your result array as well.
The code might look something like this
int hex = 0, count = 0, sum = 0, iHole;
for (i=1; i < lines_num1 -1; i++)
{
hex = array[i][0];
count = array[i][1];
sum = array[i][2];
iHole = i
// keep moving the hole to next smaller index until A[iHole - 1] is <= item
while (iHole > 0 and array[iHole - 1][0] > hex)
{
// move hole to next smaller index
A[iHole][0] = A[iHole - 1][0];
A[iHole][1] = A[iHole - 1][1];
A[iHole][2] = A[iHole - 1][2];
iHole = iHole - 1
}
// put item in the hole
if (array[iHole][0] == hex)
{
array[iHole][1]++;
array[iHole][2] += array[iHole][0];
}
else
{
array[iHole][0] = hex;
array[iHole][1] = 1;
array[iHole][2] = hex;
}
}
So the cost of making the second array is cost of the sorting itself. O(n) best case, O(n^2) worst case, and you don't have to travel again to make the sum and count.
Remember this sort is a inplace sort. If you don't want to affect your original array that could be done as well with iHole pointing to the new array. The iHole should point to the tail of new array instead of "i"