Can anyone help me out? I can't understand this programming question in Java? What does the greatest sum mean here in the matrix? In case 1, if I add each number from 5 in first row to 1 in last row, it doesn't add to 15. So why the output resulted in: 15 1 and 12 1 for case 2?
Problem#1
You will be given a square matrix of N rows and N columns (1 == N<= 1000) containing positive and negative integers with absolute value not larger than 1000.
You are required to compute the greatest sum achievable by walking a path, starting at any cell of the matrix and always moving downwards or rightwards.
Additionally, you have to report the number of times that value is achievable. N will be in the first line of the input. N lines follow with N integers each. You should output a single line with two integers separated by a single blank space: first one is the greatest sum, second one is the number of times this value can be reached.
Case 1:
For the input provided as follows:
5
3 1 -2 1 1
-6 -1 4 -1 -4
1 1 1 1 1
2 2 2 2 2
1 1 1 1 1
Output of the program will be:
15 1
Case 2:
For the input provided as follows:
3
1 1 1
2 2 2
3 3 3
Output of the program will be:
12 1
The first 3 and 5 input is the size of the matrix 3 x 3 and 5 x 5 is should not counted for addition
as the rule says that you are not allowed to turn left or move up when traversing, below is a simple traversal right direction and bottom direction
12 means 1 + 2 + 3 + 3 + 3 times should be 1, because only in one path this values can be reached
15 means 3 + 1 -1 + 4 + 1 + 2 + 2 + 2 + 1 times should be 1, because only in path this value can be achieved
you need to program 2 x 2 kernel loop which will find the 2 biggest sum number and identify the direction of flow, then jump follow that direction and choose another 2 x 2 and keep on looping, no need to random direction
but, there is a trick here, if you get 2 big numbers there is a possibility that a second path you need to follow
to achieve the second path either you can go for double iteration or single iteration by processing two direction within a singe loop, a simple example of two directions
1 1 0 0 0
2 1 1 0 0
0 2 1 0 0
0 2 1 1 1
0 2 2 2 1
This is only a random solution I provided, but finding weights of the each 2x2 matrices and use tree based traversal, Convolution kernels.... etc should be the best way
This answer is a modification of the algorithm for the "Unique Paths" problem I wrote here: Trying to solve the “Unique Paths” problem, but getting the wrong answer. That other challenge had the same constraint, you can only move down and right, which is why a similar algorithm works.
In this case, we can start at the top-left. We need to maintain 2 arrays, one for the sum achievable for a given cell, and one for the count of paths to get that sum. We also need two variables for the highest sum/count achievable overall (maxSum and maxCount). All of these are initialized to 0's.
For each cell, there are 3 "paths" leading here, and we calculate what the sum/count would be for each of those paths (if possible), where row is an array of the matrix values for the current row being processed:
From above:
The sum/count values are currently the accumulated values from the previous row. Since sum/count values were initialized to 0's, they can be used even when processing the first row.
sumAbove = sum[col] + row[col]
countAbove = count[col]
From the left:
The sum/count values are currently the accumulated values from the previous cell of the current row, because we just updated that when iterating from left to right.
sumLeft = sum[col - 1] + row[col] or row[col] if col == 0
countLeft = count[col - 1] or 0 if col == 0
Starting here:
sumStart = row[col]
countStart = 1
We then find the highest sum of the three, and set the new sum[col] to that value. The new count[col] value will be the sum of the counts where the sum is the max, e.g. if all 3 sums are the same, then count[col] = countAbove + countLeft + countStart.
If the new sum[col] is higher than maxSum, then we update maxSum/maxCount to these new values. If the new sum[col] equals maxSum, we add the new count[col] to maxCount.
Let us use the following matrix as an example:
3 1 -4 1 3
-6 -1 4 -1 -4
1 1 1 1 1
-1 2 2 1 1
12 -5 1 1 0
We start with all 0's.
sum = { 0, 0, 0, 0, 0 }, count = { 0, 0, 0, 0, 0 }, maxSum = 0, maxCount = 0
Process the first row:
row: { 3, 1, -4, 1, 3 }
bestPath: { start, left, left, left/start, left }
sum = { 3, 4, 0, 1, 4 }, count = { 1, 1, 1, 2, 2 }, maxSum = 4, maxCount = 2
For the first three, there is one path to get those sums, i.e. starting at 0,0. For the last two, there are two paths to get those sums, i.e. starting at 0,0 or 3,0 (col,row). To clarify that, we showed the which path lead to the new values labeled bestPath.
Process the second row:
row: { -6, -1, 4, -1, -4 }
bestPath: { above, above, left, left, left }
sum = { -3, 3, 7, 6, 2 }, count = { 1, 1, 1, 1, 1 }, maxSum = 7, maxCount = 1
Process the third row:
row: { 1, 1, 1, 1, 1 }
bestPath: { start, above, above, above, above }
sum = { 1, 4, 8, 7, 3 }, count = { 1, 1, 1, 1, 1 }, maxSum = 8, maxCount = 1
Process the fourth row:
row: { -1, 2, 2, 1, 1 }
bestPath: { above, above, above, left, left }
sum = { 0, 6, 10, 11, 12 }, count = { 1, 1, 1, 1, 1 }, maxSum = 12, maxCount = 1
Process the fifth row:
row: { 12, -5, 1, 1, 0 }
bestPath: { start/above, left, above, above/left, above/left }
sum = { 12, 7, 11, 12, 12 }, count = { 2, 2, 1, 2, 3 }, maxSum = 12, maxCount = 9
Final result:
12 9
With an N x N matrix, this code has excellent O(m) time complexity, where m = N², i.e. the number of cells in the matrix, and O(N) aka O(sqrt m) storage complexity.
Here's the code of implementation using python.
Two matrices are used for testing.
def findMaximumPath(mat):
rows = cols = len(mat)
count_list = []
for i in range(rows):
summ = 0
mat_index = [rows-1, cols-1]
curr_index = [0, i]
summ = mat[curr_index[0]][curr_index[1]]
while curr_index[0] != rows-1 and curr_index[1] != cols-1:
if mat[curr_index[0]][curr_index[1]+1] > mat[curr_index[0]+1][curr_index[1]]:
curr_index[1] = curr_index[1] + 1
else:
curr_index[0] = curr_index[0] + 1
summ += mat[curr_index[0]][curr_index[1]]
#print(str(curr_index) + " Sum: " + str(summ))
if curr_index[0] != rows-1 and curr_index[1] == cols-1:
for i in range(curr_index[0]+1, rows):
summ += mat[i][cols-1]
#print(str(i) + " Sum1: " +str(summ))
if curr_index[0] == rows-1 and curr_index[1] != cols-1:
for i in range(curr_index[1]+1, cols):
summ += mat[rows-1][i]
#print(str(i) + " Sum2: " +str(summ))
count_list.append(summ)
max_sum = max(count_list)
count = 0
for element in count_list:
if(element == max_sum):
count+= 1
print(count_list)
print("Maximum Sum: " + str(max_sum))
print("Number of Occurrences: " + str(count) + "\n")
mat1 = ([[3, 1, -2, 1, 1],
[-6, -1, 4, -1, -4],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[1, 1, 1, 1, 1]])
mat2 = ([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
findMaximumPath(mat1)
findMaximumPath(mat2)
Output:
Matrix 1:
[15, 12, 10, 2, 1]
Maximum Sum: 15
Number of Occurrences: 1
Matrix 2:
[12, 9, 6]
Maximum Sum: 12
Number of Occurrences: 1
Related
I've been doodling around with this little piece of code that's supposed to calculate and print out which powers of 2 are summarized into a given number. It works fine with small odd numbers but gets lost when I want it to calculate even numbers or bigger ones.
I don't even know what I could try, the code looks alright, but I probably keep failing to notice.
System.out.println("Give a number");
int gigaInt = si.nextInt();
String gigaBit = Integer.toBinaryString(gigaInt);
String[] gigaBitArray = gigaBit.split("");
System.out.println("Binary: " + gigaBit);
List<Integer> powers = new ArrayList<Integer>();
for(int counter = gigaBitArray.length-1; counter >= 0; counter--){
if (gigaBitArray[counter].equals("1"))
powers.add((int)Math.pow(2,counter));
else if(gigaBitArray[counter].equals("0")){
powers.add(0);
}
}
System.out.println("Powers: " + powers);
So, obviously, the program is supposed to calculate the powers, and it does! in some cases... here, when given 9
Give a number
9
Binary: 1001
Powers: [8, 0, 0, 1]
But when I want it to calculate an even number, it always shows "1" as the only component, like this:
Give a number
8
Binary: 1000
Powers: [0, 0, 0, 1]
And whenever asked to deal with a big number, it just goes completely crazy:
Give a number
542
Binary: 1000011110
Powers: [0, 256, 128, 64, 32, 0, 0, 0, 0, 1]
I would be amazingly grateful for any kind of advice on this. It's probably just an infantile kind of mistake, so please, do point it out.
As per the comment by Dawood ibn Kareem, you are testing the low order bits first. If you want the high order powers listed first you will need an index variable and a power variable. Also, no need to check for "0". If it is not "1" then it must be "0".
int iIndex;
int iLength = gigaBitArray.length;
int iPower = iLength - 1;
for ( iIndex = 0; iIndex < iLength; ++iIndex, --iPower )
{
if ( gigaBitArray[iIndex].equals("1") )
{
powers.add((int)Math.pow(2, iPower));
}
else
{
powers.add(0);
}
}
The problem with your code is the array index you are looking at.
When you input the number 8, its binary representation is 1000. And when you split it into an array you get:
index: 0 1 2 3
value: 1 0 0 0
Because you are starting at the end of the list, index 0 will be processed last (and will be the same as 2^0).
All you need to do to fix this is to inverse the order of the elements you are looking at while keeping the same order of the for loop.
Eg:
Instead of:
gigaBitArray[counter]
It should be:
gigaBitArray[gigaBitArray.length -1 - counter]
In addition to both answers above you could also get rid of the if else by multiplying the 0s and 1s:
int len = gigaBitArray.length;
for (int i = 0; i < gigaBitArray.length; i++) {
powers.add((int)Math.pow(2, --len)*Integer.parseInt(gigaBitArray[i]));
}
Here is one way to do it. Comments in code where not obvious. The idea here is that all information inside a computer is binary. Characters and numbers are printed out based on context. Since all information is in binary it can be shifted left or right to move the field of bits the same direction. This permits detecting a 1 or 0 bit without resorting to the overhead of String manipulation.
for (int number : new int[] { 8, 10, 23, 11, 2, 4, 99
}) {
List<Integer> powers = new ArrayList<>();
// starting bits to shift
int shift = 0;
// save number for printout
int save = number;
while (number > 0) {
// ANDing the number with 1 will mask the
// low order bit to a 1 or 0.
// Then shift that bit "shift" number
// of bits (first time thru is 0) and store
// the power in p. Then increment # of bits
// to shift.
int p = (number & 1) << shift++;
//add power to beginning of list.
powers.add(0, p);
// now shift the number right by 1 to position
// for next bit.
number >>= 1;
}
System.out.printf("%3d -> %s%n", save, powers);
}
The above prints the following:
8 -> [8, 0, 0, 0]
10 -> [8, 0, 2, 0]
23 -> [16, 0, 4, 2, 1]
11 -> [8, 0, 2, 1]
2 -> [2, 0]
4 -> [4, 0, 0]
99 -> [64, 32, 0, 0, 0, 2, 1]
So I have a random 15-puzzle, or any N-puzzle with even width, and I also have a random goal-state. That is, the blank tile and other tiles are also randomly placed.
I am able to check if the 15 puzzle is solvable with the standard goal state of having the tiles in order and blank in the bottom right, but randomizing the goal state seems to be more tricky than the standard 8 puzzle.
Example:
Start State
8 4 1 6
11 2 3 10
15 12 0 9
14 5 7 13
Goal State:
11 4 1 0
8 2 3 10
5 15 6 9
12 9 7 13
The rules for the standard 15-puzzle solvabilty are:
If the width is odd, then every solvable state has an even number of inversions.
If the width is even, then every solvable state has
An even number of inversions if the blank is on an odd numbered row
counting from the bottom;
An odd number of inversions if the blank is on an even numbered row
counting from the bottom;
I don't think different goal have any effect on solvability.
The simplest solution I can think of is to map numbers in the custom goal state to the numbers in the standard goal state. E.g: For the first row you treat 11 as if it was 0, 4-> 1, 1->2, 0->3 and so on.
The algorithm is the same as for standard puzzle, but you need a little change.
In general, the algorithm for reachability from start position S to goal position G is:
Calculate number of inversions in G - I(G)
Calculate number of inversions in S - I(S)
If:
width is odd and I(G) and I(S) have the same parity, G is reachable from S (in other words, S is solvable)
width is even:
Find the row number where blank is located in G - B(G)
Find the row number where blank is located in S - B(S)
If I(G)
is even and I(S) and abs(B(G) - B(S)) have the same parity, G is reachable from S
is odd and I(S) and abs(B(G) - B(S)) have different parity, G is reachable from S
In other cases G is unreachable from S.
Now let's see on your example. Represent a state as a list:
List<Integer> start = Arrays.asList(
8, 4, 1, 6,
11, 2, 3, 10,
15, 12, 0, 9,
14, 5, 7, 13);
List<Integer> goal = Arrays.asList(
11, 4, 1, 0,
8, 2, 3, 10,
5, 15, 6, 9,
12, 14, 7, 13); // in your example there's a second 9 instead of 14
A function, which will count number of inversions:
int inversions(List<Integer> numbers) {
int inversions = 0;
for (int i = 0; i < numbers.size(); i++) {
int n = numbers.get(i);
if (n <= 1) {
continue;
}
for (int j = i + 1; j < numbers.size(); j++) {
int m = numbers.get(j);
if (m > 0 && n > m) {
inversions++;
}
}
}
return inversions;
}
Finally, check the solvability:
boolean isSolvable(List<Integer> start, List<Integer> goal) {
int inversions = inversions(start);
int goalInversions = inversions(goal);
if (width % 2 == 0) {
int goalZeroRowIndex = goal.indexOf(0) / width;
int startZeroRowIndex = start.indexOf(0) / width;
// a little optimization is possible since we're only interested in parity
return (goalInversions % 2) == ((inversions + goalZeroRowIndex + startZeroRowIndex) % 2);
} else {
// for odd width just compare parity of inversions
return (inversions % 2) == (goalInversions % 2);
}
}
This function will work on both standard and random variations, regardless of 0 position.
For a given start and goal positions:
I(G) = 32
I(S) = 36
B(G) = 0
B(S) = 2
abs(B(G) - B(S)) = 2
I(G) is even and both I(S) and abs(B(G) - B(S)) have the same parity, so the puzzle is solvable. In fact, it is solvable in 31 moves:
12, 2, 11, 15, 2, 12, 9, 10, 6, 1, 4, 11, 15, 2, 12, 5, 14, 12, 5, 15, 2, 8, 11, 4, 3, 6, 10, 9, 6, 3, 1
I wanna create a program that generates sets of consecutive numbers that add up to form a number. For example. if the input number is 15, it should give -
7, 8
4, 5, 6
1, 2, 3, 4, 5
Some formula/algorithm/loop that can do something that fits in. It could generate an array or print it. This may seem a math problem or silly question but I can't actually figure out how to do that programmatically in Java.
Please try to give exact code that can do the thing.
Say your input is N. You know each set of k consecutive numbers will be centered around N/k. A solution exists for even k if N/k ends with 0.5, and odd k if N/k is an integer. The solution, if one exists, is the k integers centered around N/k.
k=1: 15/1 = 15, so 15 (trivial; may want to omit)
k=2: 15/2 = 7.5, so 7,8
k=3: 15/3 = 5, so 4,5,6
k=4: 15/4 = 3.75, so no solution
k=5: 15/5 = 3, so 1,2,3,4,5
k=6: 15/6 = 2.5, so 0,1,2,3,4,5
etc...
k=15: 15/15 = 1, so -6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8
You can easily modify this to limit to positive or nonnegative solutions.
I'll expand on #MBo's answer as it conveys a very clean algorithm. Wiki provides a good intro on arithmetic progressions, copied below for your convenience.
Sum
Derivation
The sum of a sequence starting with number a and consisting of n consecutive numbers:
S = (n/2) * [2 * a + (n-1) * d]
For consecutive numbers the step d is 1.
S = (n/2) * [2 * a + (n-1)]
Here we can transition to #MBo's post.
P = 2 * S = n * [2 * a + (n-1)]
We can iterate all possible counts of consecutive numbers n and check if the resulting a is valid (i.e. a is an integer).
Let's factor out a.
Say P = n * q => q = 2 * a + (n-1) => 2 * a = q - n + 1 => a = (q - n + 1) / 2
Filters
1) we mentioned we could iterate all possible counts of consecutive numbers n, but given p = n * q it's safe to say n needs to be a divisor of p.
p % n == 0
nMax = (int)Math.sqrt(p)
2) a is an integer and a = (q - n + 1) / 2 => (q - n + 1) is even => q - n is odd.
((q - n) & 1) == 1
Implementation
import java.util.*;
import java.lang.Math;
import java.util.stream.IntStream;
import static java.util.stream.Collectors.toList;
public class Progressions
{
public static void main(String[] args)
{
List<List<Integer>> list = Calculate(15);
System.out.print(list);
}
public static List<List<Integer>> Calculate(int s)
{
List<List<Integer>> list = new ArrayList<>();
int p = 2*s;
int nMax = (int)Math.sqrt(p);
for (int n=2; n<=nMax; n++) {
if(p % n == 0) {
int q = p / n;
if(((q - n) & 1) == 1) {
int a = (q - n + 1) / 2;
list.add(range(a,n));
}
}
}
return list;
}
public static List<Integer> range(int a, int n) {
return IntStream.range(a, a+n)
.boxed()
.collect(toList());
}
}
Consecutive numbers form arithmetic progression. If it starts from number a and has n members, it's sum is
S = n * (2 * b + (n-1)) / 2
so
P = 2 * S = n * (2 * b + (n-1))
So for given input S we can factorize 2*S into all possible pairs of integer factors P = n * q where n<=q, then get starting number
a = (q - n + 1) / 2
If a is integer (oddity of q and n differs) then pair (a, n) represents valid sequence starting from a with n members
Example for S = 15, 2S = 30:
30 = 2 * 15 => n = 2, a = 7 => (7,8)
30 = 3 * 10 => n = 3, a = 4 => (4,5,6)
30 = 5 * 6 => n = 5, a = 1 => (1,2,3,4,5)
Simple Python example:
import math
def getseqs(s):
print(s)
p = 2 * s
for n in range(2, math.ceil(math.sqrt(p))):
if (p % n == 0):
q = p // n
if (((q - n) & 1) == 1): #compare parity
a = (q - n + 1) // 2
seq = list(range(a, a+n))
print(seq, sum(seq))
getseqs(17)
getseqs(15)
getseqs(72)
17
[8, 9] 17
15
[7, 8] 15
[4, 5, 6] 15
[1, 2, 3, 4, 5] 15
72
[23, 24, 25] 72
[4, 5, 6, 7, 8, 9, 10, 11, 12] 72
Consider the int input is your input number (ex. 15) and List<int[]> list as a storage of the result consecutive numbers, here you go:
List<int[]> list = new ArrayList<>();
int lower = 1; // Start searching from 1
int upper = (int) Math.floor(input + 1 / 2); // Up to the half of input (8+9 > 15)
while (lower < upper) { // Iterate between the bounds
int sum = 0;
for (int i = lower; i <= upper; i++) { // Iterate and sum the numbers
sum += i;
if (sum == input) { // If it matches the input
// Add the range to the List
// You have to loop them by one and add to the
// List before version Java-8
list.add(IntStream
.range(lower, i + 1)
.toArray());
break; // Found, no reason to continue
}
if (sum > input) { // Terminate the loop if the sum overlaps
break;
}
lower++; // Increment and try the sums from
// a higher starting number
sum = 0; // Reset the sum
}
The result for the input 15 is a List of these arrays:
[1, 2, 3, 4, 5]
[4, 5, 6]
[7, 8]
Here's a suggestion:
For an input number N:
you only have to consider numbers between 1 and N.
you can maintain an interval that represents the current subset of [1,...,N]. Maintain the sum of the current interval. The first interval will be [1,1], and its sum is 1.
As long as the sum < N, increase the right end of the interval by one (for example, you start with the interval [1,1]. Since 1 < N, you extend it to [1,2].
If the sum of the current interval is equal to N, you add that interval to the output, remove the left end of the interval (also removing it from the current sum), and continue.
If the sum exceeds N, you also remove the left end of the interval (also removing it from the current sum), and continue.
You finish when the interval becomes [N,N] (which is the final interval you should add to the output).
For the input 15, here's how the interval will change over time:
Interval Sum
[1] 1
[1,2] 3
[1,2,3] 6
[1,2,3,4] 10
[1,2,3,4,5] 15 -> output [1,2,3,4,5]
[2,3,4,5] 14
[2,3,4,5,6] 20
[3,4,5,6] 18
[4,5,6] 15 -> output [4,5,6]
[5,6] 11
[5,6,7] 18
[6,7] 13
[6,7,8] 21
[7,8] 15 -> output [7,8]
[8] 8
[8,9] 17
[9] 9
[9,10] 19
[10]
...
[15] 15 -> output 15
You can probably make some optimization once the sum of two consecutive numbers becomes higher than the target sum, at which point you can terminate the loop, and just add the final set (which contains just the target sum).
It used a Window Sliding Technique/Algorithm. You can also google sliding window algorithm sum.
I am writing Implementation of the #Dave solution.
Try to Solve before asking... That's how we learn. (only if we can't get then ask)
Scanner s = new Scanner(System.in);
int inputNumber = s.nextInt();
int k = 1;
while(inputNumber/k >= .5){
Float sequenceMid = (float) inputNumber/k;
if( k%2 == 0 && (sequenceMid *2 == Math.ceil(sequenceMid *2)) ){
for(int i = ((int)Math.floor(sequenceMid) - (k/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}else if( (k%2 == 1) && (sequenceMid == Math.ceil(sequenceMid))){
for(int i = (Math.round(sequenceMid) - ((k-1)/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}
k++;
}
Here is an idea that is similar to Eran's solution.
Since we're dealing with consecutive numbers, a cummulative sum (cumsum) can usually help. The basic idea is that we want to find the difference between two cummulative sums that gives exactly K, where K is 15 in your example.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
differences:
15 - 0 = 15 -> [1, 2, 3, 4]
21 - 6 = 15 -> [4, 5, 6]
36 - 21 = 15 -> [7, 8]
The cummulative sum starts from 0 so we can do 15 - 0 subtraction. The number included as the solution will be left-exclusive and right-inclusive. That just means add 1 to the left index (index starts from 0). Hopefully the pattern is quite clear.
The next task is to create an algorithm that does some sliding window with varying width across the cummulative sum. The idea is to search for the difference with the exact value of K. We can start at the beginning where the left and right side of the window points to 0. While the difference is <= K, we want to increase the right side of the window, enlarging the window and the difference.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (] -> 0 - 0 = 0
2nd: (---] -> 3 - 0 = 3
3rd: (------] -> 6 - 0 = 0
Once the algorithm hit 15, it will print out the first answer, and then it will increase it one more time. However, once we have the difference > K, we want to increase the left number, reducing the difference.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (-----------------] -> 15 - 0 = 15 <print>
2nd: (---------------------] -> 21 - 0 = 21
3rd: (-----------------] -> 21 - 1 = 20
Notice that the left side is bounded to be < K/2 since K//2 + (K//2 + 1) >= K (where the equality is possible due to integer division denoted by //). So we can stop the loop early when the left side reaches K//2 (due to left-exclusive).
public static int cumsum(int index) {
return index * (index + 1) / 2;
}
public static String printRange(int left, int right) {
StringBuilder buffer = new StringBuilder();
buffer.append('[');
for (int i=left+1;i<=right;i++) {
buffer.append(i);
buffer.append(',');
}
buffer.deleteCharAt(buffer.length()-1);
buffer.append(']');
return buffer.toString();
}
public static void main(String[] args) {
int K = 15;
int K_ov_2 = K/2;
int left_index = 0;
int right_index = 0;
int diff;
while (left_index < K_ov_2) {
diff = cumsum(right_index) - cumsum(left_index);
System.out.println("diff = " + diff + ", left = " + left_index + ", right = " + right_index);
if (diff == K) {
System.out.println(printRange(left_index,right_index));
}
if (diff <= K) {
right_index++;
} else {
left_index++;
}
}
}
I added the debug line so the output can become more obvious.
diff = 0, left = 0, right = 0
diff = 1, left = 0, right = 1
diff = 3, left = 0, right = 2
diff = 6, left = 0, right = 3
diff = 10, left = 0, right = 4
diff = 15, left = 0, right = 5
[1,2,3,4,5]
diff = 21, left = 0, right = 6
diff = 20, left = 1, right = 6
diff = 18, left = 2, right = 6
diff = 15, left = 3, right = 6
[4,5,6]
diff = 22, left = 3, right = 7
diff = 18, left = 4, right = 7
diff = 13, left = 5, right = 7
diff = 21, left = 5, right = 8
diff = 15, left = 6, right = 8
[7,8]
diff = 24, left = 6, right = 9
I am looking for a way to search for a subsequence in a given sequence that sums up to a given number (sum, here 4) with a lexicographical priority.
Take for instance the following example:
1,2,2,4,1,1
Different subsequences can sum up to 4. For instance 1,2,1, 2,2 2,1,1. In case multiple of such sequences exists, the lexicographical first of the corresponding index-array should be returned: so if it is possible to find such sequence with the first element, one has to returned that one, if not, aim for the second and so one (both iterative (take the next one), and recursively (after selecting the first, the next but first should be closest to the head of the sequence as well).
So for this example, we select 1,2,1. Now 2,4,1 is left. If we repeat this problem we cannot make a match with 2: 2,4 is greater than 4 and 2,1 is less than 4. Thus we select 4. Finally we have to select 2 and 1.
A practical application of this concept is a queue of a roller coaster. You need 4 people for a ride, but some people are in groups with their friends and would like to all get on the same ride together.
In this example 1 is a single person at the front of the line, 2 is a group of 2 friends behind him. Now we need a total of 4 people for this ride and we already have 3, so we cut the line (2 and 4) and take the first single person, which gives us 4 people total.
If I understand the problem correctly, what you basically try to do is grouping the numbers such that the sum is 4 and you give priority to adding numbers in the queue first.
You can do this using a dynamic programming approach. I'm here using a int[] and an int as sum, but the problem can be generalized to work with most datastructures.
First you must define a comparator that compares lists of indices for instance a lexicographical one:
public class LexComp<T extends Comparable<T>> implements Comparator<List<T>> {
#Override
public int compare (List<T> la, List<T> lb) {
Iterator<T> ita = la.iterator();
Iterator<T> itb = lb.iterator();
while(ita.hasNext() && itb.hasNext()) {
T ea = ita.next();
T eb = itb.next();
int cr = ea.compareTo(eb);
if(cr != 0x00) {
return cr;
}
}
if(itb.hasNext()) {
return 1;
} else if(ita.hasNext()) {
return -1;
}
return 0;
}
}
Next you can use the following method:
public ArrayList<Integer> groupSum (int[] values, int sum) {
ArrayList[] memory = new ArrayList[sum+1];
memory[0] = new ArrayList<Integer>();
LexComp<Integer> lc = new LexComp<Integer>();
int index = 0;
for(int val : values) {
for(int i = sum-val; i >= 0 ; i--) {
if(memory[i] != null) {
ArrayList<Integer> tmp = (ArrayList<Integer>) memory[i].clone();
tmp.add(index);
if(memory[i+val] == null || lc.compare(tmp,(ArrayList<Integer>) memory[i+val]) < 0) {
memory[i+val] = tmp;
}
}
}
index++;
}
return memory[sum];
}
This method returns an ArrayList<Integer> of indices whose corresponding elements will sum up to sum and null if no such group can be created. It will give priority to some groups according to the LexComp comparator.
For your given input:
groupSum(new int[] {1,2,2,4,1,1},4);
groupSum(new int[] {1,2,3,2,2,2},4);
groupSum(new int[] {1,2,2,3},4);
groupSum(new int[] {1,2,2,3,1},4);
It results in:
[0, 1, 4]
[0, 2]
[0, 3]
[0, 1, 4]
So you should pick the first, second and fifth element which indeed sum up to 4. You then will have to remove these items out of the array yourself and rerun the process. In case no such sum can be constructed, or there are not enough elements to sum up to 4 - as said before - the algorithm will return null. In that case you have to invent a fallback mechanism. Perhaps returning the group the differs the least from sum.
Background
This is a dynamic programming approach. You generate a memory which stores - for each sum - the thus far best found solution. Initially we haven't seen any values so all items contain null except memory[0] which contains an empty arraylist (because the sum of zero elements is 0). So the memory looks like:
Mem
4 -> null
3 -> null
2 -> null
1 -> null
0 -> []
Now the algorithm iterates over the values. The first value we encounter for the example case is a 1. Now we look for lists already defined and the only one is memory[0] we can upgrade that list into a list [0] (the arrays store indices) whose sum results in 1. Since at that moment the value for that list is null there is no alternative, thus we add this list to to memory[1]:
Mem
4 -> null
3 -> null
2 -> null
1 -> [0]
0 -> []
The next item is 2: we can upgrade two lists [] -> [1] and [0] -> [1] these will results in lists with sums 2 and 3 respectively, so we store them at these indices of the memory:
Mem
4 -> null
3 -> [0,1]
2 -> [1]
1 -> [0]
0 -> []
The next item is again a 2. Now we can upgrade 4 lists: [] -> [2], [0] -> [0,2], [1] -> [1,2] and [0,1] -> [0,1,2]. A first problem is that the sum of [0,1,2] is 5 which is higher than sum. That's not interesting, so we drop that one. The problem is however, that some of the places contain already lists:
Mem
4 -> null
3 -> [0,1] <> [0,2]
2 -> [1] <> [2]
1 -> [0]
0 -> []
For the conflicting lists, we need to look for a resolution. In that case the comparator - in this case the LexComp resolves the errors. Since we do this lexicographically, [0,1] wins from [0,2] and [1] from [2]. After resolution the lists looks like:
Mem
4 -> [3]
3 -> [0,1]
2 -> [1]
1 -> [0]
0 -> []
The next element is a 4. The only list we can upgrade such that the sum is still less than or equal to sum is [] -> [3]
Mem
4 -> [3]
3 -> [0,1]
2 -> [1]
1 -> [0]
0 -> []
The next element is 1. We can upgrade all lists except the one 4 -> [3] (otherwise the sum would be larger than 4). But again this results in a lot of conflicts:
Mem
4 -> [3] <> [0,1,4]
3 -> [0,1] <> [1,4]
2 -> [1] <> [0,4]
1 -> [0] <> [4]
0 -> []
Now if we run the lexicographically comparator, it will sometimes accept new lists and sometimes the old lists. After resolution, the memory looks like:
Mem
4 -> [0,1,4]
3 -> [0,1]
2 -> [0,4]
1 -> [0]
0 -> []
Now our current best solution to generate a group that sums up to four has changed from [3] to [0,1,4]. Finally the last element 1 won't change much to the game:
Mem
4 -> [0,1,4] <> [0,1,5]
3 -> [0,1] <> [0,4,5]
2 -> [0,4] <> [0,5]
1 -> [0] <> [5]
0 -> []
Which after resolution reads:
Mem
4 -> [0,1,4]
3 -> [0,1]
2 -> [0,4]
1 -> [0]
0 -> []
Now we have considered all elements and the best solution to generate 4 is memory[4] or [0,1,4].
Different order
This approach can be generalized in the sense that providing a different Comparator on List<T> (here the LexComp<T>) will give priority to another index array. The comparator should always fulfill at least the transitivity constraint: if x is less than y and y is less than z: x must be less than z. Furthermore the list of indices will always increase. An index array of [4,1,0] is thus impossible.
The correct answer to this question depends a lot on how you define your priorities.
Should we always pick the first group in the line if possible or is the optimal solution to have as many people from the front of the queue?
I.e. given
1, 2, 2, 3, 3, 4, 2, 2, 3, 1
is the optimal solution
1, 2, 1
or
1, 3
To get you started, here's a recursive solution that does the first:
private static List<Integer> getSumIndices(int sum, List<Integer> queue) {
return getSumIndices(sum, new ArrayList<>(queue), 0);
}
private static List<Integer> getSumIndices(int sum, List<Integer> queue, int offset) {
System.out.printf("Looking for sum %s in values of %s with offset %s%n", sum, queue, offset);
if(sum == 0) {
//Base case
return new ArrayList<>();
}
for(int i = 0; i < queue.size(); i++) {
int value = queue.get(i);
// Can we actually use this group
if(value <= sum) {
try {
// See if we can find the remainder if we use this group
ArrayList<Integer> list = new ArrayList<>();
list.add(i + offset);
list.addAll(getSumIndices(sum - value, queue.subList(i + 1, queue.size()), offset + i + 1));
return list;
} catch(IllegalArgumentException e) {
// We couldn 't, continue looking
}
}
}
// We could not construct the sum using the values in the queue
System.out.printf("Failed to construct sum %s from values in %s%n", sum, queue);
throw new IllegalArgumentException(String.format("Could not construct sum %s from values in %s%n", sum, queue));
}
Results:
q=[1, 2, 2, 3, 3, 4, 2, 2, 3, 1]
Looking for sum 4 in values of [1, 2, 2, 3, 3, 4, 2, 2, 3, 1] with offset 0
Looking for sum 3 in values of [2, 2, 3, 3, 4, 2, 2, 3, 1] with offset 1
Looking for sum 1 in values of [2, 3, 3, 4, 2, 2, 3, 1] with offset 2
Looking for sum 0 in values of [] with offset 10
Index: Group Size
0: 1
1: 2
9: 1
Remaining q=[2, 3, 3, 4, 2, 2, 3]
q=[1, 2, 3, 2, 3, 4, 2, 2, 3, 2]
Looking for sum 4 in values of [1, 2, 3, 2, 3, 4, 2, 2, 3, 2] with offset 0
Looking for sum 3 in values of [2, 3, 2, 3, 4, 2, 2, 3, 2] with offset 1
Looking for sum 1 in values of [3, 2, 3, 4, 2, 2, 3, 2] with offset 2
Failed to construct sum 1 from values in [3, 2, 3, 4, 2, 2, 3, 2]
Looking for sum 0 in values of [2, 3, 4, 2, 2, 3, 2] with offset 3
Index: Group Size
0: 1
2: 3
Remaining q=[2, 2, 3, 4, 2, 2, 3, 2]
q=[1, 2, 2]
Looking for sum 4 in values of [1, 2, 2] with offset 0
Looking for sum 3 in values of [2, 2] with offset 1
Looking for sum 1 in values of [2] with offset 2
Failed to construct sum 1 from values in [2]
Looking for sum 1 in values of [] with offset 3
Failed to construct sum 1 from values in []
Failed to construct sum 3 from values in [2, 2]
Looking for sum 2 in values of [2] with offset 2
Looking for sum 0 in values of [] with offset 3
Index: Group Size
1: 2
2: 2
Remaining q=[1]
q=[2, 3, 3]
Looking for sum 4 in values of [2, 3, 3] with offset 0
Looking for sum 2 in values of [3, 3] with offset 1
Failed to construct sum 2 from values in [3, 3]
Looking for sum 1 in values of [3] with offset 2
Failed to construct sum 1 from values in [3]
Looking for sum 1 in values of [] with offset 3
Failed to construct sum 1 from values in []
Failed to construct sum 4 from values in [2, 3, 3]
Could not construct sum 4 from values in [2, 3, 3]
You can loop through the list and add in order until it is larger than the value you are looking for.
Code:
public static int addListValues(int[] list, int num){//Returns number which can not be added by anything else in the list to be <= num.
boolean b[] = new boolean[list.length];//List of numbers already taken care of. True for not, false for cleared.
for(int i = 0; i < b.length; i++){
b[i] = true;
}
int count = 0;//Amount of numbers in int[] list which have been added to equal less than or equal to num.
int total = 0;
while(true){//loops until values left can not be added to equal or be less than num.
int check = 0;
for(int i = 0; i < list.length; i++){//Loops through list.
if(b[i]){//If the number has not been added already.
System.out.println("CHECKING: " + i);
if(total + list[i] > num){//Adds to check if the number is greater than num.
check++;
}
if(total + list[i] <= num){//Adds numbers together to equal num or less than num.
System.out.println("TEST: " + list[i] + " TOTAL: " + total);
if(total + list[i] != num){
boolean contains = false;
int index = 0;
for(int o = 0; o < list.length; o++){
if(list[o] == num - total && b[o] && o != i){
contains = true;
index = o;
break;
}
}
if(contains){
System.out.println("1: " + index + ", " + list[index]);
b[index] = false;
count++;
total = 0;
}else{
System.out.println("2");
b[i] = false;
count++;
total+= list[i];
}
}else{
System.out.println("3");
b[i] = false;
count++;
total = 0;
}
}else if(check == list.length - count){//Check if "check" is equal to the amount left over. In other words, if the numbers left are higher than the number you are looking for.
System.out.println("FINAL: 3");
int t = 0;
for(int j = 0; j < list.length; j++){
if(b[j]){
t += list[j];
}
}
return t;//More than one number is left and is higher than num. Returns numbers left added together
}else if(count == list.length-1){
System.out.println("FINAL: 2");
return list[i];//returns list[i] if it is the only number left over.
}
}else if(count >= list.length){
System.out.println("FINAL: 1");
return total;//Returns total if there is nothing left over. The total may be anything less than the "num".
}
}
}
}
I have tested this method with multiple sets of numbers and it works. I was unsure what to return if more than one value were left over and were higher than 4, so I added the left over values and returned this.
This code does not require any imports.
Let's say the number is 2 and n is 3.
The output should be:
[2, 0, 0][0, 2, 0][0, 0, 2][1, 1, 0][1, 0, 1][1, 0, 1][0, 1, 1]
if n is 2, the output should be:
[2, 0][0, 2][1, 1]
Well, I tried writing a method using recursion and I've pretty much written it successfully.
Here is the method.
public static void divideANumberIntoNNumbers(int number, int n) {
try {
for (int i = number; i >= 0; --i) {
System.out.print(i + " ");
int x = n - 1;
if (x > 0) {
divideANumberIntoNNumbers(number - i, x);
} else {
return;
}
}
} finally {
System.out.println();
}
}
The following are the outputs I got.
When number = 4 and n = 2:
4 0
3 1
2 2
1 3
0 4
When number = 4 and n = 3:
4 0 0
3 1 0
0 1
2 2 0
1 1
0 2
1 3 0
2 1
1 2
0 3
0 4 0
3 1
2 2
1 3
0 4
In the second output, if you see the highlighted part, the permutations are 2 2 0 and 2 1 1 and 2 0 2.
I would like to know what modifications I need to make to the method so that I can store the permutations in the data structure List<List<Integer>>
Without blindly giving you your homework answer, I would suggest using a recursive method to do this. Basically, you need every combination of every whole number that adds up, so you can assume that 5,3 would be:
? + 5
? + 4
? + 3
? + 2
? + 1
? + 0
where ? is now equal to the original total (5) minus the right side. Recurse the ? figuring out all those combination.
if (n == 2) {
System.out.println("[2, 0][0, 2][1, 1]");
}
else if (n==3) {
System.out.println("[2, 0, 0][0, 2, 0][0, 0, 2][1, 1, 0][1, 0, 1][1, 0, 1][0, 1, 1]");
}
But I don't think this will count as a solution to your homework !