Print optimal solution for coin change algorithm - java

Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, what is the optimal way to make change for N cents.
Example:
S = {2, 5, 10}
N = 6, then optimal solution is : 2, 2, 2
I have below working code:
public static void main(String argv[]) {
long n = 10L;
int[] combo = new int[100];
int[] amounts = { 2, 5, 10 };
ways(n, amounts, combo, 0, 0, 0);
}
public static void ways(long n, int[] amounts, int[] combo, int startIndex, int sum, int index) {
if (sum == n) {
printArray(combo, index);
}
if (sum > n) {
return;
}
for (int i = 0; i < amounts.length; i++) {
sum = sum + amounts[i];
combo[index] = amounts[i];
ways(n, amounts, combo, startIndex, sum, index + 1);
sum = sum - amounts[i];
}
}
public static void printArray(int[] combo, int index) {
for (int i = 0; i < index; i++) {
System.out.print(combo[i] + " ");
}
System.out.println();
}
Output:
2 2 2 2 2
5 5
10
Here I just need to optimal combination with less number of coins so only 10 in this example code.
But this code uses recursive approach, my value for N is Long type so as the value of N increases I am getting stackoverflow error.
The recursive approach I am following here is not correct, What is the correct way to solve this problem?
Update:
Based on MBo answer I tried below program, but I am not able to get the correct results:
static void testcase() {
// make int array A of size N+1
int N = 6;
int[] A = new int[N + 1];
// make int array P of size N+1
int[] P = new int[N + 1];
// fill A[] with large value (len(S) + 1)
int[] S = { 2, 5, 10 };
int lengthOfS = S.length;
for (int i = 0; i < A.length; i++) {
A[i] = lengthOfS + 1;
}
A[0] = 0;
for (int s : S) {// coin value
for (int i = s; i <= N; i++) {
if (A[i - s] < A[i] + 1) { // using this coin we can get better
// result for sum i
A[i] = A[i - s] + 1;
P[i] = s; // write down coin for this sum
}
}
}
System.out.println(Arrays.toString(P)); // [0, 0, 2, 2, 2, 5, 2]
System.out.println(A[N]);// 3
int idx = N;
for (int i = 0; i < A[N]; i++) {
int result = idx - P[idx];
System.out.println(result); // 4 2 0
idx = result;
}
}
This code prints:
[0, 0, 2, 2, 2, 5, 2]
3
4
2
0
How to fix this code?

For fixed set S = {2, 5, 10} solution is rather simple:
No solutions for N=1,3
if N is odd, you must use 5 - so N=N-5
Now use greedy approach: get as much 10-s as possible, then as much 2-s as possible
def best(N):
print(N, end = ": ")
if (N % 2):
print("5", end = " ")
N = N - 5
if N >= 10:
print("10*", N//10, end = " ")
N = N % 10
if N > 1:
print("2*", N//2, end = " ")
21: 5 10* 1 2* 3
22: 10* 2 2* 1
23: 5 10* 1 2* 4
24: 10* 2 2* 2
In general you can find optimal solution using dynamic programming.
The first way is "memoization" - you have to implement recursive approach with the choice of the best solution, then add storing intermediate results in hashmap or another structure. Simple implementation:
S = [2, 3, 5, 7, 11]
dic = {}
def rec(summ):
if summ == 0:
return 0
rd = dic.get(summ)
if rd != None:
return rd
minn = 9999999999999
for s in S:
if s <= summ:
minn = min(minn, 1 + rec(summ - s))
dic[summ] = minn
return minn
N = 1000
print(rec(N))
>>92
Another way is using table - you fill it with the best possible results using the first item, then update solution using the second item and so on.
Pseudocode
make int array A of size N+1
make int array P of size N+1
fill A[] with large value (MaxInt` or at least `N/min(S))
A[0] = 0
for s in S: //coin value
for (i = s; i <= N; i++)
if A[i - s] < A[i] + 1 //using this coin we can get better result for sum i
A[i] = A[i - s] + 1
P[i] = s //write down coin for this sum
Now we have A[N] with the best count, and can retrieve needed coins using P[N], P[N - P[N]]... sequence.
Working Python code
S = [2, 3, 5, 7, 11]
N = 17
A = [0] + [10000] * N
P = [0] * (N + 1)
for s in S: #coin value
for i in range(s, N + 1):
if A[i - s] < A[i] + 1: #using this coin we can get better result for sum i
A[i] = A[i - s] + 1
P[i] = s #write down coin for this sum
print(A) #for reference
i = N
while i > 0:
print(P[i], end = " ")
i = i - P[i]
>> [0, 10000, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 3, 2, 3]
>> 11 3 3
Note - if we can use every coin only once, we have to make inner loop in backward direction to avoid multiple adding the same coin

As the number of coins is small, and since the amount can be large, it is likely that backtracking can provide a good solution
Here is an implementation in C++
(Note: this code was already posted, but I can't find the post. Question deleted ?)
The coins are first sorted if descending order, to fasten the search.
In order to minimize the number of coins, we first try solutions with maximum possible number of coins of largest value.
In a given search, if the current number of coins is larger than the current minimum number of coins, we stopped the search ("premature abandon").
In the code, "UP" means that we will consider adding coins with a lower value
"DOWN" means that we will try to decrease the number of coins of higher value.
At a given step, we maintain an array corresponding to the number of coins for each coin value
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
// The order of array coins is modified
std::vector<int> get_change(std::vector<int>& coins, int amount) {
std::vector<int> n_coins(coins.size(), 0);
std::vector<int> n_coins_opt(coins.size(), 0);
int n = coins.size();
std::sort(coins.begin(), coins.end(), std::greater<int>());
int sum = 0; // current sum
int i = 0; // index of the coin being examined
int n_min_coins = amount / coins[n - 1] + 1;
int n_total_coins = 0;
bool up_down = true;
while (true) { // UP
if (up_down) {
n_coins[i] = (amount - sum) / coins[i]; // max possible number of coins[i]
sum += n_coins[i] * coins[i];
n_total_coins += n_coins[i];
if (sum == amount) {
if (n_total_coins < n_min_coins) {
n_min_coins = n_total_coins;
n_coins_opt = n_coins;
}
up_down = false;
sum -= n_coins[i] * coins[i];
n_total_coins -= n_coins[i];
n_coins[i] = 0;
i--;
}
else {
if (i == (n - 1) || (n_total_coins >= n_min_coins)) { // premature abandon
sum -= n_coins[i] * coins[i];
n_total_coins -= n_coins[i];
n_coins[i] = 0;
up_down = false;
i--;
}
else {
i++;
}
}
}
else { // DOWN
if (i < 0) break;
if (n_coins[i] == 0) {
if (i == 0) break;
i--;
}
else {
sum -= coins[i];
n_coins[i] --;
n_total_coins--;
i++;
up_down = true;
}
}
}
return n_coins_opt;
}
int main() {
std::vector<int> coins = {2, 5, 10};
int amount = 1731;
auto n_coins = get_change(coins, amount);
int sum = std::accumulate (n_coins.begin(), n_coins.end(), 0);
if (sum == 0) {
std::cout << "no solution\n";
} else {
std::cout << amount << " = ";
for (int i = 0; i < n_coins.size(); i++) {
std::cout << n_coins[i] << "*" << coins[i] << " ";
}
std::cout << "\n";
}
return 1;
}

Related

Down to Zero II

This is the question:
You are given Q queries. Each query consists of a single number N . You can perform any of the operations on in each move:
If we take 2 integers a and b where N=a*b (a ,b cannot be equal to 1), then we can change N=max(a,b)
Decrease the value of N by 1 .
Determine the minimum number of moves required to reduce the value of to .
Input Format
The first line contains the integer Q.
The next Q lines each contain an integer,N .
Output Format
Output Q lines. Each line containing the minimum number of moves required > to reduce the value of N to 0.
I have written the following code. This code is giving some wrong answers and also giving time limit exceed error . Can you tell what are the the mistakes present in my code ? where or what I am doing wrong here?
My code:
public static int downToZero(int n) {
// Write your code here
int count1=0;
int prev_i=0;
int prev_j=0;
int next1=0;
int next2=Integer.MAX_VALUE;
if (n==0){
return 0;
}
while(n!=0){
if(n==1){
count1++;
break;
}
next1=n-1;
outerloop:
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i*j==n){
if (prev_i ==j && prev_j==i){
break outerloop;
}
if (i !=j){
prev_i=i;
prev_j=j;
}
int max=Math.max(i,j);
if (max<next2){
next2=max;
}
}
}
}
n=Math.min(next1,next2);
count1++;
}
return count1;
}
This is part is coded for us:
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int q = Integer.parseInt(bufferedReader.readLine().trim());
for (int qItr = 0; qItr < q; qItr++) {
int n = Integer.parseInt(bufferedReader.readLine().trim());
int result = Result.downToZero(n);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
Ex: it is not working for number 7176 ....
To explore all solution tree and find globally optimal solution, we must choose the best result both from all possible divisor pairs and from solution(n-1)
My weird translation to Java (ideone) uses bottom-up dynamic programming to make execution faster.
We calculate solutions for values i from 1 to n, they are written into table[i].
At first we set result into 1 + best result for previous value (table[i-1]).
Then we factor N into all pairs of divisors and check whether using already calculated result for larger divisor table[d] gives better result.
Finally we write result into the table.
Note that we can calculate table once and use it for all Q queries.
class Ideone
{
public static int makezeroDP(int n){
int[] table = new int[n+1];
table[1] = 1; table[2] = 2; table[3] = 3;
int res;
for (int i = 4; i <= n; i++) {
res = 1 + table[i-1];
int a = 2;
while (a * a <= i) {
if (i % a == 0)
res = Math.min(res, 1 + table[i / a]);
a += 1;
}
table[i] = res;
}
return table[n];
}
public static void main (String[] args) throws java.lang.Exception
{
int n = 145;//999999;
System.out.println(makezeroDP(n));
}
}
Old part
Simple implementation (sorry, in Python) gives answer 7 for 7176
def makezero(n):
if n <= 3:
return n
result = 1 + makezero(n - 1)
t = 2
while t * t <= n:
if n % t == 0:
result = min(result, 1 + makezero(n // t))
t += 1
return result
In Python it's needed to set recursion limit or change algorithm. Now use memoization, as I wrote in comments).
t = [-i for i in range(1000001)]
def makezeroMemo(n):
if t[n] > 0:
return t[n]
if t[n-1] < 0:
res = 1 + makezeroMemo(n-1)
else:
res = 1 + t[n-1]
a = 2
while a * a <= n:
if n % a == 0:
res = min(res, 1 + makezeroMemo(n // a))
a += 1
t[n] = res
return res
Bottom-up table dynamic programming. No recursion.
def makezeroDP(n):
table = [0,1,2,3] + [0]*(n-3)
for i in range(4, n+1):
res = 1 + table[i-1]
a = 2
while a * a <= i:
if i % a == 0:
res = min(res, 1 + table[i // a])
a += 1
table[i] = res
return table[n]
We can construct the directed acyclic graph quickly with a sieve and
then compute shortest paths. No trial division needed.
Time and space usage is Θ(N log N).
n_max = 1000000
successors = [[n - 1] for n in range(n_max + 1)]
for a in range(2, n_max + 1):
for b in range(a, n_max // a + 1):
successors[a * b].append(b)
table = [0]
for n in range(1, n_max + 1):
table.append(min(table[s] for s in successors[n]) + 1)
print(table[7176])
Results:
7
EDIT:
The algorithm uses Greedy approach and doesn't return optimal results, it just simplifies OP's approach. For 7176 given as example, below algorithm returns 10, I can see a shorter chain of 7176 -> 104 -> 52 -> 13 -> 12 -> 4 -> 2 -> 1 -> 0 with 8 steps, and expected answer is 7.
Let's review your problem in simple terms.
If we take 2 integers a and b where N=a*b (a ,b cannot be equal to 1), then we can change N=max(a,b)
and
Determine the minimum number of moves required to reduce the value of to .
You're looking for 2 factors of N, a and b and, if you want the minimum number of moves, this means that your maximum at each step should be minimum. We know for a fact that this minimum is reached when factors are closest to N. Let me give you an example:
36 = 1 * 36 = 2 * 18 = 3 * 12 = 4 * 9 = 6 * 6
We know that sqrt(36) = 6 and you can see that the minimum of 2 factors you can get at this step is max(6, 6) = 6. Sure, 36 is 6 squared, let me take a number without special properties, 96, with its square root rounded down to nearest integer 9.
96 = 2 * 48 = 3 * 32 = 4 * 24 = 6 * 16 = 8 * 12
You can see that your minimum value for max(a, b) is max(8, 12) = 12, which is, again, attained when factors are closest to square root.
Now let's look at the code:
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i*j==n){
You can do this in one loop, knowing that n / i returns an integer, therefore you need to check if i * (n / i) == n. With the previous observation, we need to start at the square root, and go down, until we get to 1. If we got i and n / i as factors, we know that this pair is also the minimum you can get at this step. If no factors are found and you reach 1, which obviously is a factor of n, you have a prime number and you need to use the second instruction:
Decrease the value of N by 1 .
Note that if you go from sqrt(n) down to 1, looking for factors, if you find one, max(i, n / i) will be n / i.
Additionally, if n = 1, you take 1 step. If n = 2, you take 2 steps (2 -> 1). If n = 3, you take 3 steps (3 -> 2 -> 1). Therefore if n is 1, 2 or 3, you take n steps to go to 0. OK, less talking, more coding:
static int downToZero(int n) {
if (n == 1 || n == 2 || n == 3) return n;
int sqrt = (int) Math.sqrt(n);
for (int i = sqrt; i > 1; i--) {
if (n / i * i == n) {
return 1 + downToZero(n / i);
}
}
return 1 + downToZero(n - 1);
}
Notice that I'm stopping when i equals 2, I know that if I reach 1, it's a prime number and I need to go a step forward and look at n - 1.
However, I have tried to see the steps your algorithm and mine takes, so I've added a print statement each time n changes, and we both have the same succession: 7176, 92, 23, 22, 11, 10, 5, 4, 2, 1, which returns 10. Isn't that correct?
So, I found a solution which is working for all the test cases -
static final int LIMIT = 1_000_000;
static int[] solutions = buildSolutions();
public static int downToZero(int n) {
// Write your code here
return solutions[n];
}
static int[] buildSolutions() {
int[] solutions = new int[LIMIT + 1];
for (int i = 1; i < solutions.length; i++) {
solutions[i] = solutions[i - 1] + 1;
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
solutions[i] = Math.min(solutions[i], solutions[i / j] + 1);
}
}
}
return solutions;
}
}

Find the maximal sum of any double slice

I'm trying to solve a problem from the Codility that I already have a solution. The problem description is provided below,
A non-empty array A consisting of N integers is given.
A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice.
The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... + A[Y − 1] + A[Y + 1] + A[Y + 2] + ... + A[Z − 1].
For example, array A such that:
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
contains the following example double slices:
double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 − 1 = 16,
double slice (3, 4, 5), sum is 0.
The goal is to find the maximal sum of any double slice.
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty array A consisting of N integers, returns the maximal sum of any double slice.
For example, given:
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
the function should return 17, because no double slice of array A has a sum of greater than 17.
Assume that:
N is an integer within the range [3..100,000];
each element of array A is an integer within the range [−10,000..10,000].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N) (not counting the storage required for input arguments)
The solution is provided below,
public static int solution(int[] A) {
int max = 0;
int N = A.length;
int[] A1 = new int[N];
int[] A2 = new int[N];
for (int i = 1; i < N - 1; i++) {
A1[i] = Math.max(A1[i - 1] + A[i], 0);
}
for (int i = N - 2; i >= 1; i--) {
A2[i] = Math.max(A2[i + 1] + A[i], 0);
}
for (int i = 1; i < N - 1; i++) {
max = Math.max(max, A1[i - 1] + A2[i + 1]);
}
return max;
}
I understand what was done in the initial 2 loops, however, the intention was not clear. My thoughts get disjointed at the time I approached the last for loop. Anyone kindly please explain the solution to me briefly?
I will base my explanation on the code from here, as it uses clearer variable names. Other than that, it's basically the same code as in your question:
class Solution {
public int solution(int[] A) {
int[] maxStartingHere = new int[A.length];
int[] maxEndingHere = new int[A.length];
int maxSum = 0, len = A.length;
for(int i = len - 2; i > 0; --i ) {
maxSum = Math.max(0, A[i] + maxSum);
maxStartingHere[i] = maxSum;
}
maxSum = 0;
for(int i = 1; i < len - 1; ++i ) {
maxSum = Math.max(0, A[i] + maxSum);
maxEndingHere[i] = maxSum;
}
int maxDoubleSlice = 0;
for(int i = 0; i < len - 2; ++i) {
maxDoubleSlice = Math.max(maxDoubleSlice, maxEndingHere[i] + maxStartingHere[i+2]);
}
return maxDoubleSlice;
}
}
The key here is that the code does not look for the maximum slice, only for its sum. The array maxStartingHere records at index i what maximum sum you'd reach if you combine contiguous items starting at i+1; maxEndingHere does the same in reverse. Let's look at an example for that:
i: 0 1 2 3 4
A: 1 -3 2 -1 ...
maxEndingHere: 0 1 0 2 1
Note that:
i=0: there are no elements left of i, so the sum is 0.
i=2: Taking A[0..1] is suboptimal, so the maximum of 0 is achieved by not summing anything at all.
i=4: Another negative element, but 2 + -1 is still better than 0. We're not considering 1 + -3 + 2 + -1 because we already know that the maximum we can reach left of the 2 is negative.
I hope you see that this array shows what can be achieved by choosing different X, but the concrete choice of X is not recorded - just its consequence. Every i corresponds to a Y, and maxEndingHere[i-1] corresponds to the consequence of choosing X optimally for a particular Y.
So we know what sums choosing X and Z optimally, for a particular Y, result in. That means it only remains to choose the best Y (or more precisely: the sum resulting from the best Y). And that is what happens in the third loop.
To reiterate:
What is the maximum you can get, ending anywhere, when starting from a particular item? That's maxStartingHere.
What is the maximum you can get, starting anywhere, when ending at a particular item? That's maxEndingHere.
What is the maximum you can get when ending/starting at a particular item? That's maxDoubleSlice.

Java : How to print heap stored as array, level by level

I have an array that represents a Max Heap. For example
84 81 41 79 17 38 33 15 61 6
so the root is max. Each mid tier node at index i can have at most two children. They would be at 2*i+1 and 2*i+2.
How can i print this heap out in a level by level fashion? like
84(0)
81(1) 41(2)
79(3) 17(4) 38(5) 33(6)
15(7) 61(8) 6(9)
the index of each element in the array is shown in paranthesis for clarification. i dont have to print the index. I was thinking it would be similar to printing a BST in level order but here, the heap is stored in an array not a list which makes it a bit tricky!
Try this code:
public class NewClass56 {
public static void main(String args[]){
int a[] = new int[] {84 ,81 ,41 ,79 ,17 ,38 ,33 ,15 ,61 ,6};
for(int i=0;i<10;i++){
for(int j=0;j<Math.pow(2,i)&&j+Math.pow(2,i)<10;j++){
System.out.print(a[j+(int)Math.pow(2,i)-1]+" ");
}
System.out.println();
}
}
}
If you have n number of numbers then replace 10 by n.
and you want the spaces then try this code:
public class NewClass56 {
public static void main(String args[]){
int a[] = new int[] {84 ,81 ,41 ,79 ,17 ,38 ,33 ,15 ,61 ,6};
StringBuilder sb = new StringBuilder();
int max=0;
for(int i=0;i<10;i++){
for(int j=0;j<Math.pow(2,i)&&j+Math.pow(2,i)<10;j++){
if(j>max){
max=j;
}
}
}
for(int i=0;i<10;i++){
for(int j=0;j<Math.pow(2,i)&&j+Math.pow(2,i)<10;j++){
for(int k=0;(k<max/((int)Math.pow(2, i)));k++){
sb.append(" ");
}
sb.append(a[j+(int)Math.pow(2,i)-1]+" ");
}
sb.append("\n");
}
System.out.println(sb.toString());
}
}
There is another way to print heap. Imagine you have the structure with the following indexes (index 0 is guardian and equals to Integer.MIN_VALUE, not shown here):
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /\ /\ /\
8 9 10 11 12 13 14 15
and it's represented by array of numbers. What do you see here? Right, 1, 3, 7, 15. If you increase it by 1 it will be 2, 4, 8, 16.
And what are these numbers? It's just 2^level. Where level is level from 1 to 4.
How we can calculate this level? It's logarithm of index with base 2.
Here is the code that implements this approach (see dump function):
package org.solutions;
import java.util.ArrayList;
import java.util.Arrays;
class Heap {
public ArrayList<Integer> arr;
public Heap() {
this.arr = new ArrayList<>();
arr.add(Integer.MIN_VALUE); // add guardian
}
public void add(int x) {
int i = arr.size();
arr.add(x);
while(arr.get(i) < arr.get(i / 2)) {
swap(i, i/2);
i = i / 2;
}
}
private void swap(int i, int j) {
int tmp = arr.get(i);
arr.set(i, arr.get(j));
arr.set(j, tmp);
}
public void dump() {
int height = log2(arr.size()) + 1;
for (int i = 1, len = arr.size(); i < len; i++) {
int x = arr.get(i);
int level = log2(i) + 1;
int spaces = (height - level + 1) * 2;
System.out.print(stringOfSize(spaces, ' '));
System.out.print(x);
if((int)Math.pow(2, level) - 1 == i) System.out.println();
}
}
private String stringOfSize(int size, char ch) {
char[] a = new char[size];
Arrays.fill(a, ch);
return new String(a);
}
// log with base 2
private int log2(int x) {
return (int)(Math.log(x) / Math.log(2)); // = log(x) with base 10 / log(2) with base 10
}
}
public class Main {
public static void main(String[] args) {
Heap heap = new Heap();
heap.add(30);
heap.add(2);
heap.add(15);
heap.add(10);
heap.add(31);
heap.dump();
}
}
The existing solutions didn't work for me so here's slightly different way of doing it that I think is also more human readable. Additionally, this doesn't use any external libraries. Note that this assumes that the first spot of the array is null, because often array-based heaps skip the array[0]. This will automatically determine the number of levels based on the input size which should be the number of nodes in the heap. It will add -- in every spot that is empty (e.g. if you have a 13-node heap the last two nodes will show up as empty).
private void printHeap(int[] heap, size) {
int maxDepth = (int) (Math.log(size) / Math.log(2)); // log base 2 of n
StringBuilder hs = new StringBuilder(); // heap string builder
for(int d = maxDepth; d >= 0; d--) { // number of layers, we build this backwards
int layerLength = (int) Math.pow(2, d); // numbers per layer
StringBuilder line = new StringBuilder(); // line string builder
for(int i = layerLength; i < (int) Math.pow(2, d + 1); i++) {
// before spaces only on not-last layer
if(d != maxDepth) {
line.append(" ".repeat((int) Math.pow(2, maxDepth - d)));
}
// extra spaces for long lines
int loops = maxDepth - d;
if(loops >= 2) {
loops -= 2;
while(loops >= 0) {
line.append(" ".repeat((int) Math.pow(2, loops)));
loops--;
}
}
// add in the number
if(i <= size) {
line.append(String.format("%-2s", heap[i])); // add leading zeros
} else {
line.append("--");
}
line.append(" ".repeat((int) Math.pow(2, maxDepth - d))); // after spaces
// extra spaces for long lines
loops = maxDepth - d;
if(loops >= 2) {
loops -= 2;
while(loops >= 0) {
line.append(" ".repeat((int) Math.pow(2, loops)));
loops--;
}
}
}
hs.insert(0, line.toString() + "\n"); // prepend line
}
System.out.println(hs.toString());
}
Example input:
int[] heap = new int[]{0, 84, 81, 41, 79, 17, 38, 33, 15, 61, 6};
int size = heap.length-1 = 10
Example output:
84
81 41
79 17 38 33
15 61 6 -- -- -- -- --
You should be able to fairly easily change this to work as a toString method instead if necessary. The spacing will have to be modified if you want to use 3-digit numbers, if someone requests it I can edit with modified code for that.
Divide & Conquer. Create the line lists of the subtrees, concatenate the lines and prepend the String for the root node of the subtree. Also make sure the lines have the same length and all are centered:
static String pad(String s, int lengthRigth, int length) {
StringBuilder sb = new StringBuilder();
for (int i = length - lengthRigth - s.length(); i > 0; i--) {
sb.append(' ');
}
sb.append(s);
for (int i = 0; i < lengthRigth; i++) {
sb.append(' ');
}
return sb.toString();
}
static StringBuilder withSpacesAppended(String s, int spaceCount) {
StringBuilder sb = new StringBuilder(s.length()+spaceCount).append(s);
for (int i = 0; i < spaceCount; i++) {
sb.append(' ');
}
return sb;
}
static void joinLists(List<String> list1, List<String> list2) {
int i;
final int size = list2.size();
for (i = 0; i < size; i++) {
list1.set(i, withSpacesAppended(list1.get(i), 2).append(list2.get(i)).toString());
}
}
static List<String> createTreeStrings(int index, int[] array) {
int child1 = 2 * index + 1;
int child2 = 2 * index + 2;
if (child1 >= array.length) {
return new ArrayList<>(Collections.singletonList(toText(index, array)));
} else {
List<String> childList1 = createTreeStrings(child1, array);
if (child2 < array.length) {
joinLists(childList1, createTreeStrings(child2, array));
}
String text = toText(index, array);
int currentLength = childList1.get(0).length();
if (currentLength >= text.length()) {
text = pad(text, (currentLength - text.length()) / 2, currentLength);
} else {
for (int i = 0, size = childList1.size(); i < size; i++) {
childList1.set(i, pad(childList1.get(i), (currentLength - text.length()) / 2, currentLength));
}
}
childList1.add(0, text);
return childList1;
}
}
static String toText(int index, int[] array) {
return Integer.toString(array[index]) + '(' + index + ')';
}
Example use:
createTreeStrings(0, new int[]{84, 81, 41, 79, 17, 38, 33, 15, 61, 6}).forEach(System.out::println);
createTreeStrings(0, new int[]{Integer.MAX_VALUE, 6}).forEach(System.out::println);
The accepted answer created many new lines and ignores last element while displaying. Hence sharing optimised code,
public void display() {
// n is number of elements in the heap
// It can be further optimised by calculating height of the heap
// and looping i only till height of the tree
for (int i = 0; i <= n / 2; i++) {
for (int j = 0; j < Math.pow(2, i) && j + Math.pow(2, i) <= n; j++) { // Each row has 2^n nodes
System.out.print(heap[j + (int) Math.pow(2, i) - 1] + " ");
}
System.out.println();
}
}
If you want to store it in a list of lists (level order) , just split it once for every power of 2, like 1,2,4,8,16 ..
private ArrayList<ArrayList<Integer>> heapParse(int[] arr) {
ArrayList<ArrayList<Integer>> heap = new ArrayList<ArrayList<Integer>>();
int j=-1;
for (int i=0; i< arr.length;i++){
if(isPowerOfTwo(i+1)){
heap.add(new ArrayList<>());
j++;
}
heap.get(j).add(arr[i]);
}
return heap;
}
private boolean isPowerOfTwo(int i){
return (i&(i-1))==0;
}
The following algorithm will print value as defined grid length.
For example, the max element equals 100, mean each digits sit in placeholder that has length == 3. If max length is even, for ex: 4. Then the placeholder value will be 5. Always odds for center alignment.
Result: [placeholder == 3] && [maxWidthLine == 31]
100 // [rear == 14] && [between == 29 -> Not Use]
15- 17- // [rear == 6] && [between == 13]
-9- -6- 13- 10- // [rear == 2] && [between == 5]
-4- -8- -3- -1- -5- --- --- --- // [rear == 0] && [between == 1]
Result: [placeholder == 5] && [maxWidthLine == 5 * 2^3 + 2 ^ 3 - 1 == 47]
1000- // [Level == 0]
-17-- -13-- // [Level == 1]
--9-- -15-- --5-- -10-- // [Level == 2]
--4-- --8-- --3-- --6-- --1-- ----- ----- ----- // [Level == 3]
TypeScript source code:
/** #example
** > format(10, 3) -> "10-"
** > format(10, 4) -> "-10-"
** > format(100, 3) -> "100"
** > format(100, 4) -> "100-"
**/
const format = <T extends string | number>(value: T, placeholder: number): string => {
if (!value && value !== 0) {
return "-".repeat(placeholder);
}
const number = Number.call(null, value).toString();
const size = number.length;
if (size > placeholder) {
throw new EvalError(">>> Place-Holder is smaller than Number Length <<<");
}
const pads = (placeholder - size) >> 1;
return "-".repeat(pads) + number + "-".repeat(placeholder - size - pads);
};
public print(): void {
const size = this.heap.length;
const maxDigit = Math.max(...this.heap as Array<number>);
/** Place holder must be odds [1, 3, 5, 7, 9, 11, ...] ~!*/
const placeholder = (Number.call(null, maxDigit).toString().length & ~1) + 1;
/** Max Depth of Binary Search Tree from [0] to [N] ~!*/
const maxDepth = Math.floor(Math.log(size) / Math.log(2)); // Min Depth = 0; [Root Level]
/** Total Spaces of Line == <The Amount of placeholders> && <The Amount of Space-1 between Placeholders> ~!*/
const totalLineSpaces = placeholder * (2 ** maxDepth) + (2 ** maxDepth - 1);
/** Calculate the spaces need to pad to the Rear-Side and Between each Placeholders ~!*/
const calculateSpace = (level: number): [number, number] => {
/** #equation: ${TotalSpaces} - ${placeholder} * (2 ^ level) == 2x + (2 ^ level - 1)(2x + 1) ~!*/
/** #constraint: ${BetweenSpaces} == (2x + 1) <- Space between each placeholders ~!*/
const rear = (totalLineSpaces - (placeholder + 1) * (2 ** level) + 1) / Math.pow(2, level + 1);
return [rear, 2 * rear + 1];
};
console.log("------------------------------------------");
console.log(">>> Array representation of Heap Array <<<");
console.log("------------------------------------------\n");
let str = ''; /** Heap string builder ~!*/
for (let level = 0; level <= maxDepth; level++) {
const [rear, middle] = calculateSpace(level);
if (level === 0) {
str += " ".repeat(rear) + this.format(this.heap[0], placeholder) + " ".repeat(rear) + "\n";
continue;
}
const elements: Array<string> = [];
/** #description: Looping through each Tree-Layer. Ranged from [2^level - 1] to [2^(level+1) - 2] ~!*/
for (let i = Math.pow(2, level) - 1; i <= Math.pow(2, level + 1) - 2; i++) {
elements.push(this.format(this.heap[i], placeholder));
}
str += " ".repeat(rear) + elements.join(" ".repeat(middle)) + " ".repeat(rear) + "\n";
}
str += "\n" + "------------------------------------------";
return console.log(str);
};

Add numbers of array until certain value

For an exercise, I have to add values of an array until a certain value is reached, showing all possible combinations.
Example: value = 4, array = {1, 2, 3}
Possible combinations are: 1+1+1+1, 1+1+2, 1+2+1, 1+3, 2+1+1, 2+2, 3+1
However, my code doesn't seem to work:
public static void main(String[] args) {
double[] array = { 1., 2., 3. };
double value = 4.;
for (int i = 0; i < array.length; i++) {
addNumber(array, value, i);
}
}
public static void addNumber(double[] array, double value, int index) {
double startNumber = array[index];
double checkSum = 0;
for (int i = 0; i < array.length; i++) {
checkSum += array[i] + startNumber;
if (checkSum == value){
System.out.println(startNumber + " + " + array[i] + " = " + checkSum);
} else if (checkSum < value){
moreNumbers(array, value, checkSum);
}
checkSum = 0;
}
}
public static void moreNumbers (double[] array, double value, double current){
if (current == value){
System.out.println(current);
} else if (current < value) {
for (int i = 0; i < array.length; i++){
current += array[i];
System.out.println("+ " + array[i] + " = " + current);
}
moreNumbers(array, value, current);
}
}
Output:
+ 1.0 = 3.0
+ 2.0 = 5.0
+ 3.0 = 8.0
+ 1.0 = 4.0
+ 2.0 = 6.0
+ 3.0 = 9.0
1.0 + 3.0 = 4.0
+ 1.0 = 4.0
+ 2.0 = 6.0
+ 3.0 = 9.0
2.0 + 2.0 = 4.0
3.0 + 1.0 = 4.0
I believe I'm having trouble finding the right algorithm, since I'm only getting some of the combinations, but not all.
And there is my question: I'm looking for an algorithm that helps me understand this exercise and it's logic, not the final code.
EDIT: In further development of this exercise, I have to use numbers like 0.5 or 0.2 too, but the numbers are always positive, so this is another problem I'm hoping to find answers for.
This seems to be solvable easily with recursion, like this :
Getting the solution for 4 and {1,2,3} (written below as solution(4, {1,2,3}) is like getting the solution for
"1 + " + solution(3, {1, 2, 3})
"2 + " + solution(2, {1, 2, 3})
"3 + " + solution(1, {1, 2, 3})
At each step, you decrease the number (if there is not 0 in the list of available numbers, of course), so you are sure that the recursion will finish.
You can have two outcome :
no possibility (like you need to produce 1, but there is not 1 in the list of available numbers)
1 or more potential solutions
There is another thing to pay attention to : floating point equality. == will not work everytime.
the code would like like :
public static void main(String[] args) {
ArrayList<String> solutions = new ArrayList<String>();
solve("", 1.0d, new Double[] {0.2d, 0.50d}, solutions);
System.out.println(solutions);
// [0.2 + 0.2 + 0.2 + 0.2 + 0.2, 0.5 + 0.5]
solutions.clear();
solve("", 4d, new Double[] {1d, 2d, 3d}, solutions);
System.out.println(solutions);
// [1.0 + 1.0 + 1.0 + 1.0, 1.0 + 1.0 + 2.0, 1.0 + 2.0 + 1.0, 1.0 + 3.0, 2.0 + 1.0 + 1.0, 2.0 + 2.0, 3.0 + 1.0]
}
public static void solve(String subSolution, Double remaining, Double[] authorizedNumbers, List<String> solutions) {
if (doubleEquals(remaining, 0d)) {
solutions.add(subSolution);
} else {
for(Double authorizedNumber : authorizedNumbers) {
if (doubleEquals(authorizedNumber, remaining)) {
solutions.add(subSolution + authorizedNumber);
} else if (authorizedNumber < remaining) {
solve(subSolution + authorizedNumber + " + ", remaining - authorizedNumber, authorizedNumbers, solutions);
}
}
}
}
public static boolean doubleEquals(double d1, double d2) {
return Math.abs(d1 - d2) < 0.000000001d;
}
Here is one of the solutions based on Combination Technique.
Algorithm:
Compute all the combination (with repetition) from length {input} to 1.
Print only those combinations which satisfy the sum condition.
For Example, if input is 4 then some of the different combinations of length = 4 will be as follows:
1 1 1 1
1 1 1 2
.
.
2 1 2 3
.
.
3 3 3 3
Now, we'll only print 1 1 1 1 since it sums up to input i.e. 4 and satisfies the condition.
Similarly, for length = 3 some of the different combinations will be as follows:
1 1 1
1 1 2
.
.
1 2 1
.
.
3 3 3
Now, we'll only print 1 1 2, 1 2 1 and 2 1 1 since they all satisfy the sum condition.
Here is a brief description of how different combinations are computed:
Combination function checks for the last element of the array and increments it if it is not MAX and branches the function.
If the last element is max then we scan through the array for next number that is not MAX.
If the above scan fails as the array is exhausted then we return the flow to our main function but, if the scan return a position which is not max then we increment the value at that position by 1 and reset all the values after that position to MIN. We again branches the function.
(It computes all the combinations for a given length using recursion)
Code Snippet:
class Combinations
{
/* Constants Array (Sorted) */
private static final double[] ARR_CNST = {0.1,0.2,0.3};
/* Size of Constant Array */
private static final int SIZE = 3;
public static void main (String[] args)
{
/* Input Number */
double input = 0.4;
/* Start Permutations {Length --> 1} */
for(int i = (int) (input/ARR_CNST[0]); i > 0; i--) {
double[] storage = new double[i];
/* Fill Array With Least Element */
Arrays.fill(storage,ARR_CNST[0]);
/* Check Sum Condition */
if(check(storage,input)) {
/* Print */
print(storage);
}
/* Calculate Rest of the Combinations */
calc(storage, input);
}
}
private static void calc(double[] arr, double input) {
/* Increment Last Element if not MAX */
if(arr[arr.length - 1] < ARR_CNST[SIZE - 1]) {
int k = 0;
while(k < SIZE && arr[arr.length - 1] != ARR_CNST[k++]);
arr[arr.length - 1] = ARR_CNST[k];
if(check(arr,input)) {
print(arr);
}
calc(arr, input);
}
/* Increment & Reset */
int i = arr.length - 1;
while(i >= 0 && arr[i] >= ARR_CNST[SIZE - 1])
i--;
if(i >= 0) {
int k = 0;
while(k < SIZE && arr[i] != ARR_CNST[k++]);
arr[i] = ARR_CNST[k];
for(int x = i + 1; x < arr.length; x++) {
arr[x] = ARR_CNST[0];
}
if(check(arr,input)) {
print(arr);
}
calc(arr, input);
}
/* Return */
return;
}
/* Check Sum Condition */
private static boolean check(double[] arr, double input) {
double sum = 0;
for(int i = 0; i < arr.length; i++) {
sum += arr[i];
}
if(sum == input) {
return true;
}
return false;
}
/* Print Array Values */
private static void print(double[] arr) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < arr.length; i++) {
sb.append(arr[i] + " + ");
}
System.out.println(sb.substring(0,sb.length() - 3));
}
}
Output:
0.1 + 0.1 + 0.1 + 0.1
0.1 + 0.1 + 0.2
0.1 + 0.2 + 0.1
0.2 + 0.1 + 0.1
0.1 + 0.3
0.2 + 0.2
0.3 + 0.1
The general approach is:
Pick one of the available numbers, and see if that equals the target.
If not, you can pick any other number from the available numbers and add it to the previously picked number; again, check if you have reached the target.
Keep going until you have reached (or gone past) the target sum.
This can be implemented like this:
public static void startRecursion(int target, int[] numbers) {
int min = numbers[0];
for (int i = 1; i < numbers.length; ++i) {
min = Math.min(min, numbers[i]);
}
// We need to choose at most ceil(target / min) numbers.
int maxPicks = (target + min - 1) / min;
recurse(new int[maxPicks], 0, 0, target, numbers);
}
private static void recurse(
int[] picked, int numPicked, int sumOfPicked,
int target, int[] numbers) {
if (sumOfPicked == target) {
// We reached the target! Print out the numbers we chose to get here.
for (int i = 0; i < numPicked; ++i) {
if (i != 0) System.out.print(" + ");
System.out.print(picked[i]);
}
System.out.println(" = " + target);
} else if (sumOfPicked < target) {
// We haven't reached the target yet.
// Go through each of the numbers that you can choose from numbers
// in turn, increasing the sum by this amount.
for (int i = 0; i < numbers.length; ++i) {
picked[numPicked] = numbers[i];
recurse(
picked, numPicked + 1, sumOfPicked + numbers[i],
target, numbers);
}
} else {
// We have overshot the target. Since no numbers are negative,
// we can't get back to the target again.
}
}

Listing the total sum of all possible sums in a set with constraints

I am keen to find out the following:
Given a set with N elements, my friend and I are playing a game.I always make the first move.
We can only remove either the first or the last element with 50% chance each.We take alternate turns in the game.If only one element remains,we can remove it for sure.What is the expected sum that I can collect?
For example:N=2 {10,20} Possible sets that I can collect are {10},{20}.
So expected sum is 0.5*10+0.5*20=15.
My approach:
Since probability of getting a possible sum is equal in all cases,we only need to compute the sum of all possible sums and then multiply it by (0.5)^N/2.
I tried to use recursion to compute the required sum:
f(i,j)-computes the sum between i and j recursively
f(i,j)=2*a[i]+func(i,j-2)+func(i+1,j-1)+func(i+1,j-1)+func(i+2,j)+2*a[j]);
Initial call f(1,N)
But the approach doesn't seem to work. What should I do?
Complete function is below:
class CandidateCode {
static long v[][] = new long[1003][1003];
public static long func(int a[], int i, int j) {
if (i == j)
return v[i][j] = a[i];
if (v[i][j] != 0)
return v[i][j];
else {
if (i > j - 2 && i + 1 > j - 1 && i + 2 > j)
return (v[i][j] += 2 * a[i] + 2 * a[j]);
else
return (v[i][j] += 2 * a[i] + func(a, i, j - 2) + func(a, i + 1, j - 1) + func(a, i + 1, j - 1)
+ func(a, i + 2, j) + 2 * a[j]);
}
}
public static void main(String args[]) {
int n;
int a[] = { 0, 6, 4, 2, 8 };
n = a.length - 1;
System.out.println(func(a, 1, 4) / Math.pow(2, n / 2));
}
}
This problem can be solved by applying dynamic programming.
First, we have the state of the game is (player ,start, end) ,which indicates the current player, and the range of values that's available in the original set. At the beginning, we start at player 0 and start is 0, end is N - 1.
Denote that the first player is 0 and the second player is 1, we have the expected value of player 0:
if(player == 0){
double result = 0.5*( set[start] + f(1, start + 1,end) ) + 0.5*(set[end] + f(1,start, end - 1));
}else{
double result = 0.5*( f(0, start + 1,end) ) + 0.5*(f(0,start, end - 1));
}
So for each state, we can store all calculated state in a dp[player][start][end] table, which reduce the time complexity to O(2*N*N) with N is number of value in set.
Pseudo code:
double expectedValue(int player, int start, int end, int[]set){
if(start == end)
if(player == 0)
return set[start];
return 0;
if(already calculated this state)
return dp[player][start][end];
double result= 0;
if(player == 0){
result = 0.5*( set[start] + f(1, start + 1,end) ) + 0.5*(set[end] + f(1,start, end - 1));
}else{
result = 0.5*( f(0, start + 1,end) ) + 0.5*(f(0,start, end - 1));
}
return dp[player][start][end] = result;
}

Categories