Array with Consecutive numbers - Algorithm - java

I am trying to answer the following question: given a sorted array with some sequenced numbers and some non-sequenced numbers, write an algorithm that obtains a pair {start, end} for each group of consecutive numbers. Consecutive numbers have difference of 1 only.
So far, I can think of the brute force method only:
public static void main(String[] args) {
int[] array = { 4, 5, 6, 7, 8, 9, 12, 15, 16, 17, 18, 20, 22, 23, 24, 27 };
Map<Integer, Integer> list = new HashMap<Integer, Integer>();
list = findIndex(array);
}
// Bruteforce
private static Map<Integer, Integer> findIndex(int[] array) {
Map<Integer, Integer> list = new HashMap<Integer, Integer>();
int x = -1, y = -1;
int end = array.length;
for (int i = 0; i < end; i++) {
x = i;
while (i < end - 1) {
if (array[i] + 1 == array[i + 1]) {
i++;
y = i;
} else {
if (x != y && x >= 0) {
list.put(x, y);
System.out.println("i = " + x + " to j = " + y);
i = i + 1;
break;
}
}
}
}
return list;
}
Output :
i = 0 to j = 5
i = 7 to j = 10
i = 12 to j = 14
It works fine, but how do I improve time complexity?

You don't need to nest loops for this:
int end = array.length;
if (end > 0) {
int start = 0;
for (int i = 1; i < end; i++) {
if (array[i] != array[i - 1] + 1) {
if (i - start > 1) {
list.put(start, i - 1);
System.out.println("i = " + start + " to j = " + (i - 1));
}
start = i;
}
}
if (end - start > 1) {
list.put(start, end - 1);
System.out.println("i = " + start + " to j = " + (end - 1));
}
}

As soon as initial array sorted, you can have O(N) implementation of this algorithm like this:
private static Map<Integer, Integer> getConsecutive(final int[] array) {
final Map<Integer, Integer> list = new TreeMap<Integer, Integer>();
int startIndex = 0;
int endIndex = 0;
for (int i = 1; i < array.length; i++) {
if (array[i - 1] + 1 == array[i])
endIndex = i;
else {
if (endIndex > startIndex)
list.put(startIndex, endIndex);
startIndex = endIndex = i;
}
}
if (endIndex > startIndex)
list.put(startIndex, endIndex);
return list;
}

Related

Optimal algorithm for finding max value

I need to design an algorithm to find the maximum value I can get from (stepping) along an int[] at predefined (step lengths).
Input is the number of times we can "use" each step length; and is given by n2, n5 and n10. n2 means that we move 2 spots in the array, n5 means 5 spots and n10 means 10 spots. We can only move forward (from left to right).
The int[] contains the values 1..5, the size of the array is (n2*2 + n5*5 + n10*10). The starting point is int[0].
Example: we start at int[0]. From here we can move to int[0+2] == 3, int[0+5] == 4 or int[0+10] == 1. Let's move to int[5] since it has the highest value. From int[5] we can move to int[5+2], int[5+5] or int[5+10] etc.
We should move along the array in step lengths of 2, 5 or 10 (and we can only use each step length n2-, n5- and n10-times) in such a manner that we step in the array to collect as high sum as possible.
The output is the maximum value possible.
public class Main {
private static int n2 = 5;
private static int n5 = 3;
private static int n10 = 2;
private static final int[] pokestops = new int[n2 * 2 + n5 * 5 + n10 * 10];
public static void main(String[] args) {
Random rand = new Random();
for (int i = 0; i < pokestops.length; i++) {
pokestops[i] = Math.abs(rand.nextInt() % 5) + 1;
}
System.out.println(Arrays.toString(pokestops));
//TODO: return the maximum value possible
}
}
This is an answer in pseudocode (I didn't run it, but it should work).
fill dp with -1.
dp(int id, int 2stepcount, int 5stepcount, int 10stepcount) {
if(id > array_length - 1) return 0;
if(dp[id][2stepcount][5stepcount][10stepcount] != -1) return dp[id][2stepcount][5stepcount][10stepcount];
else dp[id][2stepcount][5stepcount][10stepcount] = 0;
int 2step = 2stepcount < max2stepcount? dp(id + 2, 2stepcount + 1, 5stepcount, 10stepcount) : 0;
int 5step = 5stepcount < max5stepcount? dp(id + 5, 2stepcount, 5stepcount + 1, 10stepcount) : 0;
int 10step = 10stepcount < max10stepcount? dp(id + 10, 2stepcount, 5stepcount, 10stepcount + 1) : 0;
dp[id][2stepcount][5stepcount][10stepcount] += array[id] + max(2step, 5step, 10step);
return dp[id][2stepcount][5stepcount][10stepcount];
}
Call dp(0,0,0,0) and the answer is in dp[0][0][0][0].
If you wanna go backwards, then you do this:
fill dp with -1.
dp(int id, int 2stepcount, int 5stepcount, int 10stepcount) {
if(id > array_length - 1 || id < 0) return 0;
if(dp[id][2stepcount][5stepcount][10stepcount] != -1) return dp[id][2stepcount][5stepcount][10stepcount];
else dp[id][2stepcount][5stepcount][10stepcount] = 0;
int 2stepForward = 2stepcount < max2stepcount? dp(id + 2, 2stepcount + 1, 5stepcount, 10stepcount) : 0;
int 5stepForward = 5stepcount < max5stepcount? dp(id + 5, 2stepcount, 5stepcount + 1, 10stepcount) : 0;
int 10stepForward = 10stepcount < max10stepcount? dp(id + 10, 2stepcount, 5stepcount, 10stepcount + 1) : 0;
int 2stepBackward = 2stepcount < max2stepcount? dp(id - 2, 2stepcount + 1, 5stepcount, 10stepcount) : 0;
int 5stepBackward = 5stepcount < max5stepcount? dp(id - 5, 2stepcount, 5stepcount + 1, 10stepcount) : 0;
int 10stepBackward = 10stepcount < max10stepcount? dp(id - 10, 2stepcount, 5stepcount, 10stepcount + 1) : 0;
dp[id][2stepcount][5stepcount][10stepcount] += array[id] + max(2stepForward, 5stepForward, 10stepForward, 2stepBackward, 5backForward, 10backForward);
return dp[id][2stepcount][5stepcount][10stepcount];
}
But your paths don't get fulled explored, because we stop if the index is negative or greater than the array size - 1, you can add the wrap around functionality, I guess.
this is a solution but i am not sure how optimal it is !
i did some optimization on it but i think much more can be done
I posted it with the example written in question
import java.util.Arrays;
import java.util.Random;
public class FindMax {
private static int n2 = 5;
private static int n5 = 3;
private static int n10 = 2;
private static final int[] pokestops = new int[n2 * 2 + n5 * 5 + n10 * 10];
public static int findMaxValue(int n2, int n5, int n10, int pos, int[] pokestops) {
System.out.print("|");
if (n2 <= 0 || n5 <= 0 || n10 <= 0) {
return 0;
}
int first;
int second;
int third;
if (pokestops[pos] == 5 || ((first = findMaxValue(n2 - 1, n5, n10, pos + 2, pokestops)) == 5) || ((second = findMaxValue(n2, n5 - 1, n10, pos + 5, pokestops)) == 5) || ((third = findMaxValue(n2, n5, n10 - 1, pos + 10, pokestops)) == 5)) {
return 5;
}
return Math.max(Math.max(Math.max(first, second), third), pokestops[pos]);
}
public static void main(String[] args) {
Random rand = new Random();
for (int i = 0; i < pokestops.length; i++) {
pokestops[i] = Math.abs(rand.nextInt() % 5) + 1;
}
System.out.println(Arrays.toString(pokestops));
//TODO: return the maximum value possible
int max = findMaxValue(n2, n5, n10, 0, pokestops);
System.out.println("");
System.out.println("Max is :" + max);
}
}
You need to calculate following dynamic programming dp[c2][c5][c10][id] - where c2 is number of times you've stepped by 2, c5 - by 5, c10 - by 10 and id - where is your current position. I will write example for c2 and c5 only, it can be easily extended.
int[][][][] dp = new int[n2 + 1][n5 + 1][pokestops.length + 1];
for (int[][][] dp2 : dp) for (int[][] dp3 : dp2) Arrays.fill(dp3, Integer.MAX_VALUE);
dp[0][0][0] = pokestops[0];
for (int c2 = 0; c2 <= n2; c2++) {
for (int c5 = 0; c5 <= n5; c5++) {
for (int i = 0; i < pokestops.length; i++) {
if (c2 < n2 && dp[c2 + 1][c5][i + 2] < dp[c2][c5][i] + pokestops[i + 2]) {
dp[c2 + 1][c5][i + 2] = dp[c2][c5][i] + pokestops[i + 2];
}
if (c5 < n5 && dp[c2][c5 + 1][i + 5] < dp[c2][c5][i] + pokestops[i + 5]) {
dp[c2][c5 + 1][i + 5] = dp[c2][c5][i] + pokestops[i + 5];
}
}
}
}
I know the target language is java, but I like pyhton and conversion will not be complicated.
You can define a 4-dimensional array dp where dp[i][a][b][c] is the maximum value that you can
get starting in position i when you already has a steps of length 2, b of length 5 and c of length
10. I use memoization to get a cleaner code.
import random
values = []
memo = {}
def dp(pos, n2, n5, n10):
state = (pos, n2, n5, n10)
if state in memo:
return memo[state]
res = values[pos]
if pos + 2 < len(values) and n2 > 0:
res = max(res, values[pos] + dp(pos + 2, n2 - 1, n5, n10))
if pos + 5 < len(values) and n5 > 0:
res = max(res, values[pos] + dp(pos + 5, n2, n5 - 1, n10))
if pos + 10 < len(values) and n10 > 0:
res = max(res, values[pos] + dp(pos + 10, n2, n5, n10 - 1))
memo[state] = res
return res
n2, n5, n10 = 5, 3, 2
values = [random.randint(1, 5) for _ in range(n2*2 + n5*5 + n10*10)]
print dp(0, n2, n5, n10)
Suspiciously like homework. Not tested:
import java.util.Arrays;
import java.util.Random;
public class Main {
private static Step[] steps = new Step[]{
new Step(2, 5),
new Step(5, 3),
new Step(10, 2)
};
private static final int[] pokestops = new int[calcLength(steps)];
private static int calcLength(Step[] steps) {
int total = 0;
for (Step step : steps) {
total += step.maxCount * step.size;
}
return total;
}
public static void main(String[] args) {
Random rand = new Random();
for (int i = 0; i < pokestops.length; i++) {
pokestops[i] = Math.abs(rand.nextInt() % 5) + 1;
}
System.out.println(Arrays.toString(pokestops));
int[] initialCounts = new int[steps.length];
for (int i = 0; i < steps.length; i++) {
initialCounts[i] = steps[i].maxCount;
}
Counts counts = new Counts(initialCounts);
Tree base = new Tree(0, null, counts);
System.out.println(Tree.max.currentTotal);
}
static class Tree {
final int pos;
final Tree parent;
private final int currentTotal;
static Tree max = null;
Tree[] children = new Tree[steps.length*2];
public Tree(int pos, Tree parent, Counts counts) {
this.pos = pos;
this.parent = parent;
if (pos < 0 || pos >= pokestops.length || counts.exceeded()) {
currentTotal = -1;
} else {
int tmp = parent == null ? 0 : parent.currentTotal;
this.currentTotal = tmp + pokestops[pos];
if (max == null || max.currentTotal < currentTotal) max = this;
for (int i = 0; i < steps.length; i++) {
children[i] = new Tree(pos + steps[i].size, this, counts.decrement(i));
// uncomment to allow forward-back traversal:
//children[2*i] = new Tree(pos - steps[i].size, this, counts.decrement(i));
}
}
}
}
static class Counts {
int[] counts;
public Counts(int[] counts) {
int[] tmp = new int[counts.length];
System.arraycopy(counts, 0, tmp, 0, counts.length);
this.counts = tmp;
}
public Counts decrement(int i) {
int[] tmp = new int[counts.length];
System.arraycopy(counts, 0, tmp, 0, counts.length);
tmp[i] -= 1;
return new Counts(tmp);
}
public boolean exceeded() {
for (int count : counts) {
if (count < 0) return true;
}
return false;
}
}
static class Step {
int size;
int maxCount;
public Step(int size, int maxCount) {
this.size = size;
this.maxCount = maxCount;
}
}
}
There's a line you can uncomment to allow forward and back movement (I'm sure someone said in the comments that was allowed, but now I see in your post it says forward only...)

Making merge sort to use only (n/2 + 1) extra space in java

I'm trying to make the merge sort to use only (n/2 + 1) extra space and still O(n log n) time. This is my homework.
The original quesetion:
Write the non-recursive version of merge sort. Your program should run
in O(n log n) time and use n/2 + O(1) extra spaces.
The program will split an array in to two like normal merge sort. The left part will be in another array, which is ceil(n/2) long, so it will fit the requirement.
The right part will be in the original array. So it will be half in-place sorting
Sorry, I don't know how to explain further.
I think this is basically correct. But I kept on facing OutOfBounds error.
I know the code is quite long and messy. But can anyone help me about that?
I spent about 5 hours to implement this. Please help me.
package comp2011.lec6;
import java.util.Arrays;
public class MergeSort {
public static void printArr(int[] arr){
for(int i = 0; i < arr.length; i++){
System.out.printf("%d ", arr[i]);
}
}
public static void mergeSort(int[] arr){
if(arr.length<2) {
return;
}
int n, lBegin, rBegin;
n = 1;
int[] leftArr = new int[arr.length - (arr.length/2)];
while(n<arr.length) {
lBegin = 0;
rBegin = n;
while(rBegin + n <= arr.length) {
mergeArrays(arr, lBegin, lBegin+n, rBegin, rBegin+n, leftArr);
lBegin = rBegin+n;
rBegin = lBegin+n;
}
if(rBegin < arr.length) {
mergeArrays(arr, lBegin, lBegin+n, rBegin, arr.length, leftArr);
}
n = n*2;
}
}
public static void mergeArrays(int[] array, int startL, int stopL, int startR, int stopR, int[] leftArr) {
// int[] right = new int[stopR - startR + 1];
// int[] left = new int[stopL - startL + 1];
// for(int i = 0, k = startR; i < (right.length - 1); ++i, ++k) {
// right[i] = array[k];
// }
System.out.println("==============");
System.out.println("stopL: " + stopL +" startL: " + startL);
for(int i = 0, k = startL; i <= (stopL - startL); ++i, ++k) {
System.out.println(leftArr[i]);
leftArr[i] = array[k];
}
// right[right.length-1] = Integer.MAX_VALUE;
leftArr[stopL - startL] = Integer.MAX_VALUE;
System.out.println("leftArr: " + Arrays.toString(leftArr));
System.out.println("RightArr: " + Arrays.toString(Arrays.copyOfRange(array, startR, stopR)));
System.out.println("before: " + Arrays.toString(array));
// for(int k = startL, m = 0, n = startR; k < stopR; ++k) {
System.out.println("StartL: " + startL + " StartR: " + stopR);
for(int k = startL, m = 0, n = startR; ( (k < stopR) ); ++k) {
System.out.println("k: " + k);
System.out.println("Left: " + leftArr[m]);
System.out.println("Right: " + array[n]);
System.out.println("Array[k] before: " + array[k]);
// if(leftArr[m] == Integer.MAX_VALUE){
// System.out.println("YES");
// }
if( (leftArr[m] <= array[n]) || (n >= stopR) ) {
System.out.println("Left is smaller than right");
array[k] = leftArr[m];
m++;
}
else {
System.out.println("Right is smaller than left");
array[k] = array[n];
System.out.println("right: " + array[k]);
n++;
}
System.out.println("Array[k] after: " + array[k]+"\n");
}
System.out.println("after " + Arrays.toString(array));
}
public static void main(String[] args) {
int[] array = new int[] { 5, 2, 4, 12, 2, 10, 13, 1, 7 };
mergeSort(array);
printArr(array);
}
}

How to increment integer Array values?

I am designing a problem in which I have to use an int array to add or subtract values. For example instead of changing 100 to 101 by adding 1, I want to do the same thing using the int array. It work like this:
int[] val = new int[3];
val[0] = 1;
val[1] = 0;
val[2] = 0;
val[2] += 1;
so, If I have to get a value of 101, I will add 1 to val[2].
The only problem I have is finding a way to make int array work like how adding and subtracting from an ordinary integer data set works.
Is this possible using a for loop or a while loop?
Any help will be appreciated!
Here's your homework:
public static int[] increment(int[] val) {
for (int i = val.length - 1; i >= 0; i--) {
if (++val[i] < 10)
return val;
val[i] = 0;
}
val = new int[val.length + 1];
val[0] = 1;
return val;
}
Make sure you understand how and why it works before submitting it as your own work.
Solution of this problem is designed by using String
You can refer to this method which will return sum of 2 nos having input in String format.
Input String should contain only digits.
class Demo {
public static String add(String a1, String b1) {
int[] a = String_to_int_Array(a1);
int[] b = String_to_int_Array(b1);
int l = a.length - 1;
int m = b.length - 1;
int sum = 0;
int carry = 0;
int rem = 0;
String temp = "";
if (a.length > b.length) {
while (m >= 0) {
sum = a[l] + b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
l--;
}
while (l >= 0) {
sum = a[l] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
l--;
}
if (carry > 0) {
temp = carry + temp;
}
} else {
while (l >= 0) {
sum = a[l] + b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
l--;
}
while (m >= 0) {
sum = b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
}
if (carry > 0) {
temp = carry + temp;
}
}
return temp;
}
public static int[] String_to_int_Array(String s) {
int arr[] = new int[s.length()], i;
for (i = 0; i < s.length(); i++)
arr[i] = Character.digit(s.charAt(i), 10);
return arr;
}
public static void main(String a[]) {
System.out.println(add("222", "111"));
}
}
Quick & dirty:
static void increment(int[] array){
int i = array.length-1;
do{
array[i]=(array[i]+1)%10;
}while(array[i--]==0 && i>=0);
}
Note the overflow when incementing e.g. {9, 9}. Result is {0, 0} here.
public static void increment() {
int[] acc = {9,9,9,9};
String s="";
for (int i = 0; i < acc.length; i++)
s += (acc[i] + "");
int i = Integer.parseInt(s);
i++;
System.out.println("\n"+i);
String temp = Integer.toString(i);
int[] newGuess = new int[temp.length()];
for (i = 0; i < temp.length(); i++)
{
newGuess[i] = temp.charAt(i) - '0';
}
printNumbers(newGuess);
}
public static void printNumbers(int[] input) {
for (int i = 0; i < input.length; i++) {
System.out.print(input[i] + ", ");
}
System.out.println("\n");
}
If someone is looking for this solution using JavaScript or if you can translate it to java, here's your optimum solution:
function incrementArr(arr) {
let toBeIncrementedFlag = 1, // carry over logic
i = arr.length - 1;
while (toBeIncrementedFlag) {
if (arr[i] === 9) {
arr[i] = 0; // setting the digit as 0 and using carry over
toBeIncrementedFlag = 1;
} else {
toBeIncrementedFlag = 0;
arr[i] += 1;
break; // Breaking loop once no carry over is left
}
if (i === 0) { // handling case of [9,9] [9,9,9] and so on
arr.unshift(1);
break;
}
i--; // going left to right because of carry over
}
return arr;
}

Coin Combinations Through Brute Force

I have some code that will brute force solve the following problem:
Given a set of x coins and a target sum to reach, what is the fewest number of coins required to reach that target?
The code so far:
import java.util.ArrayList;
import java.util.Arrays;
public class coinsSum {
public static int min = Integer.MAX_VALUE;
public static int[] combination;
public static final int TARGET = 59;
public static void main(String[] args) {
long start = System.nanoTime();
int[] validCoins = new int[] {1, 2, 5, 10, 20};
Arrays.sort(validCoins);
int len = validCoins.length;
ArrayList<Integer> maxList = new ArrayList<Integer>();
for(int c : validCoins) {
maxList.add(TARGET / c);
}
int[] max = new int[len];
for(int i = 0; i < len; i++) {
max[i] = maxList.get(i).intValue();
}
permutations(new int[len], max, validCoins, 0); // bread&butter
if(min != Integer.MAX_VALUE) {
System.out.println();
System.out.println("The combination " + Arrays.toString(combination) + " uses " + min + " coins to make the target of: " + TARGET);
} else {
System.out.println("The target was not reachable using these coins");
}
System.out.println("TOOK: " + (System.nanoTime() - start) / 1000000 + "ms");
}
public static void permutations(int[] workspace, int[] choices, int[] coins, int pos) {
if(pos == workspace.length) {
int sum = 0, coinCount = 0;
System.out.println("TRYING " + Arrays.toString(workspace));
for(int a = 0; a < coins.length; a++) {
sum += workspace[a] * coins[a];
coinCount += workspace[a];
}
if(sum == TARGET) {
// System.out.println(Arrays.toString(n)); //valid combinations
if(coinCount < min) {
min = coinCount;
combination = workspace;
System.out.println(Arrays.toString(combination)+" uses " + min + " coins");
}
}
return;
}
for(int i = 0; i <= choices[pos]; i++) {
workspace[pos] = i;
permutations(workspace, choices, coins, pos + 1);
}
}
}
This solution uses recursion, is there any way to do compute combinations in java using loops?
How else can all possible combinations be iterated through?
You can sort the array of coins. Then go from right to left, keep subtracting from the target value, untill the coin is bigger from the remaining value of target. Move left in the array of coins and repeat the process.
Example:
{1, 2, 5, 10, 20}
num = 59
Try coins from right to left:
59 - 20 = 39
So far coins used [20]
39 - 20 = 19
So far coins used [20,20]
19 - 20 = -1, Can't use 20!
19 - 10 = 9
So far coins used [20,20,10]
9 - 10 = -1, Can't use 10!
9 - 5 = 4
So far coins used [20,20,10,5]
4 - 5 = -1, Can't use 5!
4 - 2 = 2
So far coins used [20,20,10,5,2]
2 - 2 = 0
So far coins used [20,20,10,5,2,2]
Total coin used 6
Here is a solution in python that uses dynamic programming to find the minimum number of coins to reach a target value.
The algorithm works as follow
dp[i][target] = minimum number of coins required required to acheive target using first i coin
dp[i][target] = min(dp[i-1][target],dp[i-1][target-coin[i]]+1)
dp[i-1][target] denotes not using the ith coin
dp[i-1][target-coin[i]] denotes making use of ith coin
Since for each coin your are checking wheather to include it or not the algorithm is enumerating through all possible combination.
Here is an space optimized version of the above algorithm
maxvalue = 10 ** 9
def minchange(coins, target):
no_of_coins = len(coins)
dp = [maxvalue for i in range(target + 1) ]
dp[0] = 0
for i in range(no_of_coins):
for j in range(coins[i], target + 1):
dp[j] = min(dp[j], dp[j - coins[i]] + 1)
return dp[target]
I found a dynamic programming approach which is definitely not optimised, but isn't too bad for target numbers up to 10000 if anyone is interested
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;
}
public static void print(Map<Integer, Integer> map) {
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("[" + entry.getKey() + ", " + entry.getValue() + "]");
}
System.out.println();
}
}

Java: How to sum the elements of two arrays with different lengths

I am trying to add the elements of two arrays with different lengths together.
The code below is only for the same length and here is all I have so far.
//for the same lengths
int[]num1 = {1,9,9,9};
int[]num2 = {7,9,9,9};// {9,9,9}
int total = 0, carry = 1;
int capacity = Math.max(num1.length,num2.length);
int []arraySum = new int [capacity];
for (int i = capacity - 1 ; i >= 0; i--)
{
arraySum[i] = num1[i]+ num2[i];
if (arraySum[i] > 9)
{
arraySum[i] = arraySum[i] % 10;
num2[i-1] = num2[i-1] + carry;
}
}
for(int i = 0; i < arraySum.length; i++)
{
System.out.print(arraySum[i]);
}
What should I do if I change the elements in num2 and length to like {9,9,9}?
I know I probably need to put another for-loop as an inside for-loop and control the indices of the array with smaller length but how....?? One more thing... what should I do for those for-loops conditions because num1 and num2 will be eventually INPUTED by the user.
Well, you can tell that the inputs are limited because if num1[0] + num2[0] > 9 the carry has no index to be placed, then it can't be compiled. So, I need to shift the whole array to the right and place the carry from num1[0] + num2[0]. Here is the problem!! Where should I put the shifting code? I am kinda confused.......
Actually, you declare an int[] array with the capacity as Math.max(num1.length, num2.length).
It is not encough. You should set the capacity as Math.max(num1.length, num2.length) +1.
Why?
See if num1 is {1,9,9,9} and num2 is {9,9,9,9}, how can the arraySum to represent the sum {1,1,9,9,8}?
So we need to declare it as below to consider if carry is needed.
int[] arraySum = new int[capacity + 1];
Then when print the sum, check if arraySum[0] is 0 or 1, if it euqals to 0, do not print it in Console.
Modified code for reference is as follows:
package question;
public class Example {
public static void main(String[] args) {
// for the same lengths
int[] num1 = { 1,9,9,9 };
int[] num2 = { 9,9,9,9};// {9,9,9}
// 1999+9999 = 11998, its length is greater than the max
int capacity = Math.max(num1.length, num2.length);
int[] arraySum = new int[capacity + 1];
int len2 = num2.length;
int len1 = num1.length;
if (len1 < len2) {
int lengthDiff = len2 - len1;
/*
* Flag for checking if carry is needed.
*/
boolean needCarry = false;
for (int i = len1 - 1; i >= 0; i--) {
/**
* Start with the biggest index
*/
int sumPerPosition =0;
if (needCarry) {
sumPerPosition = num1[i] + num2[i + lengthDiff] +1;
needCarry = false;
}else
{
sumPerPosition = num1[i] + num2[i + lengthDiff];
}
if (sumPerPosition > 9) {
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
needCarry = true;
}else
{
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
}
}
/**
* Handle the remaining part in nun2 Array
*/
for (int i = lengthDiff - 1; i >= 0; i--) {
/*
* Do not need to care num1 Array Here now
*/
if(needCarry){
arraySum[i + 1] = num2[i]+1;
}else
{
arraySum[i + 1] = num1[i] ;
}
if (arraySum[i + 1] > 9) {
arraySum[i + 1] = arraySum[i + 1] % 10;
needCarry = true;
} else {
needCarry = false;
}
}
/*
* Handle the last number, if carry is needed. set it to 1, else set
* it to 0
*/
if (needCarry) {
arraySum[0] = 1;
} else {
arraySum[0] = 0;
}
} else {
int lengthDiff = len1 - len2;
/*
* Flag for checking if carry is needed.
*/
boolean needCarry = false;
for (int i = len2 - 1; i >= 0; i--) {
/**
* Start with the biggest index
*/
int sumPerPosition = 0;
if (needCarry) {
sumPerPosition = num2[i] + num1[i + lengthDiff] +1;
needCarry = false;
}else
{
sumPerPosition = num2[i] + num1[i + lengthDiff];
}
if (sumPerPosition > 9) {
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
needCarry = true;
}else
{
arraySum[i + lengthDiff + 1] = sumPerPosition % 10;
}
}
/**
* Handle the remaining part in nun2 Array
*/
for (int i = lengthDiff - 1; i >= 0; i--) {
/*
* Do not need to care num1 Array Here now
*/
if(needCarry){
arraySum[i + 1] = num1[i]+1;
}else
{
arraySum[i + 1] = num1[i] ;
}
if (arraySum[i + 1] > 9) {
arraySum[i + 1] = arraySum[i + 1] % 10;
needCarry = true;
} else {
needCarry = false;
}
}
/*
* Handle the last number, if carry is needed. set it to 1, else set
* it to 0
*/
if (needCarry) {
arraySum[0] = 1;
} else {
arraySum[0] = 0;
}
}
/*
* Print sum
*
* if arraySum[0] ==1, print 1
*
* Do not print 0 when arraySum[0] ==0
*/
if(arraySum[0] == 1)
{
System.out.print(1);
}
for (int i = 1; i < arraySum.length; i++) {
System.out.print(arraySum[i]);
}
}
}
An example that num1 is {1,9,9,9} and num2 is {9,9,9,9}, the sum result is as follows:
output in Console:
11998
It's quite simpe actually. Inside your loop, check that the current index is valid for both array, and replace the value to add by 0 in case of an invalid index:
int value1 = (i < num1.length) ? num1[i] : 0;
int value2 = (i < num2.length) ? num2[i] : 0;
arraySum[i] = value1 + value2;
EDIT: I didn't understand that you wanted to right-align the arrays and not left-align them. The simplest solution is probably to write and read everything in the arrays in reverse order. So if the numbers are 456 and 7658, the first array would contain 6, 5, 4 and the second one would contain 8, 5, 6, 7.
Here is more performance centric solution:
public class SumArrays {
public static void main(String[] args) {
int[] num1 = {1, 9, 9, 9};
int[] num2 = {7, 9, 9, 9, 9, 9, 9};
int[] biggerArray = num1.length > num2.length ? num1 : num2;
int[] smallerArray = num1.length <= num2.length ? num1 : num2;
int[] summedArray = new int[biggerArray.length];
System.arraycopy(biggerArray, 0, summedArray, 0, biggerArray.length);
for (int i = 0; i < smallerArray.length; i++) {
summedArray[i] += smallerArray[i];
}
for (int i = 0; i < summedArray.length; i++) {
System.out.println(summedArray[i]);
}
}
}
You can use an ArrayList instead of an array and implement a normal addition method to it:
public static ArrayList<Integer> sum(int[] arr, int[] arr2) {
ArrayList<Integer> al = new ArrayList<>();
int i = arr.length - 1;
int j = arr2.length - 1;
int c = 0;
while (i >= 0 && j >= 0) {
int temp = arr[i] + arr2[j] + c;
if (temp >= 10) {
int r = temp % 10;
al.add(0, r);
c = temp / 10;
} else {
al.add(0, temp);
c = 0;
}
i--;
j--;
}
if (i < 0 && j >= 0) {
while (j >= 0) {
al.add(0, arr2[j] + c);
c = 0;
j--;
}
} else if (j < 0 && i >= 0) {
while (i >= 0) {
al.add(0, arr[i] + c);
c = 0;
i--;
}
} else
al.add(0, c);
return al;
}
for kicks, here is an alternative:
int[] num1 =
{ 1, 9, 9, 9 };
int[] num2 =
{ 7, 9, 9, 9 };
//convert the int array to a string
StringBuilder sb = new StringBuilder(num1.length);
for (int i : num1)
{
sb.append(i);
}
String sNum1 = sb.toString();
System.out.println(sNum1);
StringBuilder sb2 = new StringBuilder(num2.length);
for (int i : num2)
{
sb2.append(i);
}
String sNum2 = sb2.toString();
System.out.println(sNum2);
try
{
//parse the string to an int
int iNum1 = Integer.parseInt(sNum1);
int iNum2 = Integer.parseInt(sNum2);
//add them together
int sum = iNum1 + iNum2;
String sSum = Integer.toString(sum);
System.out.println(sSum);
// convert num back to array
int[] sumArray = new int[sSum.length()];
for (int i = 0; i < sSum.length(); i++)
{
sumArray[i] = sSum.charAt(i) - '0';
System.out.println(sumArray[i]);
}
}
catch (Exception e)
{
// couldnt parse ints
}

Categories