I have a simple question that I've tried whiteboarded multiple times but still can't understand. How come for the inner for loop, we have to set column = row + 1; I was under the impression you should initialize column = 0 and then simply just swap the row into columns and columns into rows for the transposing of the matrix, but I keep failing the test cases. Thank you
public static void transposeMatrix(int[][] matrix) {
for (int row = 0; row < matrix.length; row++)
{
for (int column = row + 1 ; column < matrix.length; column++)
{
int temp = matrix[row][column];
matrix[row][column] = matrix[column][row];
matrix[column][row] = temp;
}
}
}
You only need to swap the upper or lower triangle of the matrix once.
1 2 3
4 5 6
7 8 9
you consider 2, 3, 6 and swap it with 4, 7, 8 respectively. Diagonal does not need to be swapped. Hence you don't start with 0 always.
Related
EDIT 2
I separated out the offset code into a new method at Gavin's suggestion:
private static int getOffset(int offset, int row, int col, ArrayList<ArrayList<Integer>> triangle, ArrayList<ArrayList<Integer>> p_triangle, ArrayList<Integer> sums) {
int row_num = (row+1); //= 1-indexed row #
int p_value = p_triangle.get(row).get(col); // number from pascal's triangle
if (col > 1) {
// element is in the left half of Pascal's Triangle
if (col <= (row_num/2)) offset++;
// penultimate element
else if (col == row_num - 2) offset = sums.size() - p_value;
// elements halfway until penultimate;
// [-2, -3] all work up until row 10 and fail thereafter
else offset = sums.size() - p_value - (row_num - col - 2);
}
return offset;
}
And found that, oddly enough, subtracting 2 or 3 both work when calculating the offset for an element in the latter half of the given row (between halfway and antepenultimate). And I have no idea why that's the case.
Even stranger is that I modified Oleg's answer
public static int findMaxSum(ArrayList<ArrayList<Integer>> data) {
for (int row = data.size() - 2; row >= 0; row--)
for (int col = 0; col < data.get(row).size(); col++)
data.get(row).set(col, data.get(row).get(col) + Math.max(data.get(row + 1).get(col), data.get(row + 1).get(col + 1)));
return data.get(0).get(0);
}
and found that the behavior of algorithm appears to be correct up to a triangle of size 10. However, it starts to breakdown after that with the following discrepancies in rows 11-15:
size = 11 [correct:772 | mine:752]
size = 12 [correct:850 | mine:830]
size = 13 [correct:908 | mine:921]
size = 14 [correct:981 | mine:961]
size = 15 [correct:1074 | mine:1059]
Unfortunately, I still can't discern a pattern from this.
EDIT
I'd like to emphasize that I'm not looking for a better way to solve this particular Project Euler problem; instead, I just want to know if it's possible to use Pascal's Triangle to do it in the way I described (or in some slightly modified way) and if someone can see the logic in my code I may be blind to.
ORIGINAL QUESTION
I am trying to solve Project Euler problem 18.
The goal is to find the max sum of all the 2^14 paths down a triangle of numbers.
I was struck by the similarity with Pascal's Triangle and wondered if it could be used to solve the problem.
My logic is as follows:
1.) Calculate the sums by row.
2.) Use Pascal's triangle to determine how many there must be (as each row adds up to a power of two) and to determine the offset from the start of the of the previous rows sums.
Ex.
Pascal's Triangle
1
1 1
1 2 1
1 3 3 1
Triangle To Process
3
7 4
2 4 6
8 5 9 3
Sums
[3]
[10, 7]
[12, 14, 11, 13]
[20, 17, 19, 16, 23, 20, 22, 16]
For row 3, we see Pascal's Triangle informs us that there will be 1 + 2 + 1 or 4 values. Furthermore, it describes how to build the sums because it's the first and last element added to the sum directly preceding them and the middle value added to both of those sums as it has contact with both the preceding chains.
By extension, the fourth row shows that the second number in the Triangle to Process should be added to the first three sums from row three and the third number should be added to the final three.
The way I get the offset is kind of ugly (and maybe the source of the trouble):
if (i > 1) {
if (i < (p_triangle.get(row).size()/2)) offset++;
else if (i == triangle.get(row).size()-2) offset = sums.size() - p_triangle.get(row).get(i);
else offset = sums.size() - p_triangle.get(row).get(i) - (p_triangle.get(row).size() - i - 2);
}
Where p_triangle.get(row) is the current Pascal's Triangle row being used, sums is the array of cumulative sums (2^(row-1) in length), offset is where to start the summations from, and the Pascal's Triangle number is how many elements from the sum list starting at the offset to sum the number at index i in the Triangle to Process, i.e., triangle.get(row).get(i).
I know this may not be the most efficient algorithm to solve the problem, but it seems like it could be a nice one. The thing is, I can't get it to work.
SPOILER ALERT ON THE ANSWER TO THE PROBLEM
The correct answer is apparently 1074
Can anyone tell me where in the code or in my logic for using Pascal's Triangle, I might have messed up?
THE FULL CODE:
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.lang.Math;
public class MaxPathSum {
private static ArrayList<ArrayList<Integer>> pascalsTriangle(int n_rows) {
ArrayList<ArrayList<Integer>> triangle = new ArrayList<>();
triangle.add(new ArrayList<Integer>(){{add(1);}});
triangle.add(new ArrayList<Integer>(){{add(1); add(1);}});
for (int row = 2; row < n_rows; row++) {
ArrayList<Integer> next_row = new ArrayList<>();
next_row.add(1);
for (int i = 1; i < triangle.get(row-1).size(); i++) {
next_row.add(triangle.get(row-1).get(i-1) + triangle.get(row-1).get(i));
}
next_row.add(1);
triangle.add(next_row);
}
return triangle;
}
private static ArrayList<ArrayList<Integer>> buildTriangle(int n_rows) {
Scanner sc = new Scanner(System.in);
ArrayList<ArrayList<Integer>> triangle = new ArrayList<>();
for (int row = 1; row <= n_rows; row++) {
ArrayList<Integer> row_arr = new ArrayList<>();
for (int elem = 1; elem <= row; elem++) {
row_arr.add(sc.nextInt());
}
triangle.add(row_arr);
}
return triangle;
}
private static int findLargestSum(ArrayList<ArrayList<Integer>> triangle, ArrayList<ArrayList<Integer>> p_triangle) {
ArrayList<Integer> sums = new ArrayList<>();
sums.add(triangle.get(0).get(0));
// traverse the rows
for (int row = 1, offset = 0; row < triangle.size(); row++, offset = 0) {
ArrayList<Integer> new_sums = new ArrayList<>();
// traverse each element in each row
new_sums.add(sums.get(0) + triangle.get(row).get(0));
for (int i = 1; i < triangle.get(row).size()-1; i++) {
int n_times = p_triangle.get(row).get(i);
for (int j = 0; j < n_times; j++) {
new_sums.add(triangle.get(row).get(i) + sums.get(j+offset));
}
if (i > 1) {
if (i < (p_triangle.get(row).size()/2)) offset++;
else if (i == triangle.get(row).size()-2) offset = sums.size() - p_triangle.get(row).get(i);
else offset = sums.size() - p_triangle.get(row).get(i) - (p_triangle.get(row).size() - i - 2);
System.out.println("Row: " + row + " | Offset: " + offset);
}
}
new_sums.add(sums.get(sums.size()-1) + triangle.get(row).get(triangle.get(row).size()-1));
sums = new_sums;
}
Collections.sort(sums);
return sums.get(sums.size() - 1);
}
public static void main(String[] args) {
int n_rows = Integer.parseInt(args[0]);
// build pascalsTriangle
ArrayList<ArrayList<Integer>> p_triangle = pascalsTriangle(n_rows);
// build triangle from input
ArrayList<ArrayList<Integer>> triangle = buildTriangle(n_rows);
// traverse triangle finding largest sum
int largest_sum = findLargestSum(triangle, p_triangle);
// display results
System.out.println(largest_sum);
}
}
Just be simple!
public static int findMaxSum(int[][] data) {
for (int row = data.length - 2; row >= 0; row--)
for (int col = 0; col < data[row].length; col++)
data[row][col] += Math.max(data[row + 1][col], data[row + 1][col + 1]);
return data[0][0];
}
if we have these numbers in
array [][]
{1, 2, 3, 4},
{1, 2, 20, 4},
{1, 20, 2, 4},
{1, 2, 3, 4},};
it should looks like this
1 0 0 4
0 0 0 0
0 0 0 0
1 0 0 4
but i could output code only like this...
1 0 3 4
1 0 20 4
0 0 0 0
1 0 3 4
and i don't understand how to correct it, please help me,
this is my code.Thanks!
package com.company;
public class Main {
public static void main(String[] args) {
int[][] array2 = {{1, 2, 3, 4},
{1, 2, 20, 4},
{1, 20, 2, 4},
{1, 2, 3, 4},};
int countMax = 0;
int countIndexHorizontal = 0;
int countIndexVertical = 0;
int max = Integer.MIN_VALUE;
int m, k,x;
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
if (array2[i][j] > max) {
max = array2[i][j];
}
}
}
for (k = 0; k < array2.length; k++) {
for (m = 0; m < array2[k].length; m++) {
if (array2[k][m] == max) {
countIndexHorizontal = k;
countIndexVertical = m;
for (x = 0; x < array2.length; x++) {
for (int j = 0; j < array2[x].length; j++) {
if (countIndexVertical == x || j == countIndexHorizontal) {
array2[x][j] = 0;
}
}
}
}
}
}
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.print(array2[i][j] + " ");
}
System.out.println();
}
}
}
it looks like there are a lot of code and a little of words and site don't allow me to finally post my question and i'm really angry, maybe this text will help me to solve this problem.
Algorithm
This is the part when you only use pen and paper. Basically, I understood the problem as follow:
Given a matrix with n rows and m columns of Integer1:
Find the highest value
All entries in the rows and columns holding the highest value must have its value set at 0
Print the updated matrix
Assumption
I made the following assumptions:
In n is not necessarily equal to m. For example, you can have the array:
Valid Input
1 2 3 4 5 6
7 8 9 10 11 12
7 8 12 5 6 4
which must give, as 12 is the highest value:
Output
1 2 0 4 5 0
0 0 0 0 0 0
0 0 0 0 0 0
The matrix is consistent: every row has m columns and every column has n rows. For example, such input is incorrect:
Incorrect input
1 2 3
7 8 9 10
7 8
Logic
At this stage, you're still using pen, paper and Google only!
In my problem understanding, I splitted in three parts as I thought this is how you understood the problem. This is the mathematics understanding. Now let's convert it into a more Java understanding. First of all, we need to translate some vocabulary:
Mathematics wording | Java wording
--------------------|---------------------
matrix | 2-dimensional array
Integer | int (primitive type)
which gives in Java way:
Given an 2-dimensional int[][] array:
Find the highest value
Find the rows and columns holding the highest value
Update the array by setting the value to 0 for the rows and columns found in 2.
Print the array
In the specific case of my solution, I combine 1. + 2. and I combined 3. + 4.
What you did
Let's open your favorite IDE and compare my analysis with your input:
Find the highest value: OK here: : you use the variable max and scan the matrix to find the maximum value. You also assumed that the matrix could be rectangle (n rows and m columns with n != m). So it's good
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
if (array2[i][j] > max) {
max = array2[i][j];
}
}
}
Find the rows and columns: ERROR here, as mentioned by ccp-beginner, when you found a the highest value, you erase (set to zero) the value for the whole column and whole row but maybe the same highest value was stored somewhere else in this row or column
for (k = 0; k < array2.length; k++) {
for (m = 0; m < array2[k].length; m++) {
if (array2[k][m] == max) {
countIndexHorizontal = k;
countIndexVertical = m;
// additional operation defined in 3.
}
// in ccp-beginner example of
// 2, 2
// 1, 1
// if k=0 and m=0, you'll update the value
// of the first row and first column giving:
// 0, 0
// 0, 1
// but when k=0, m=1, you'll find 0 instead
// of 2 so your program will consider that
// this row / column does not contain the
// highest value
}
}
I assume here the
countIndexHorizontal = row
countIndexVertical = column
So you need to keep track of the rows and columns when you're setting the values to 0.
Update the array: ERROR here (cf ccp-beginner's answer)
for (x = 0; x < array2.length; x++) {
for (int j = 0; j < array2[x].length; j++) {
if (countIndexVertical == x || j == countIndexHorizontal) {
array2[x][j] = 0;
// In your example:
// 1 2 3 4
// 1 2 20 4
// 1 20 2 4
// 1 2 3 4
// and if countIndexVertical=2 and countIndexHorizontal=1
// (the 20 of the second row between 2 and 4), you'll have
// 1 0 3 4
// 1 0 20 4
// 0 0 0 0
// 1 0 3 4
// instead of
// 1 2 0 4
// 0 0 0 0
// 1 20 0 4
// 1 2 0 4
}
}
}
you got confused between countIndexVertical and countIndexHorizontal, as you have
x = row
j = column
You should had (please notice the swapping)
if (countIndexHorizontal == x || j == countIndexVertical) {
array2[x][j] = 0;
}
Print the array: OK here, nothing special to mention
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.print(array2[i][j] + " ");
}
System.out.println();
}
The problem
Basically, what you need is how to store the rows and the columns containing the highest value. At first, we could be tempted to use array again right, like
int[] rowsContainingHighestValue;
int[] columnsContainingHighestValue;
But you don't know how many highest value you'll encounter so you need something to store multiple value with a dynamic size: I'll use List.
Some Java point
The rowsContainingHighestValue and columnsContainingHighestValue become:
List<Integer> rowsContainingHighestValue = new ArrayList<>();
List<Integer> columnsContainingHighestValue = new ArrayList<>();
You may want to have a look at the following point:
Why List instead of array?
My objects are declared as List but I instantiate2 with ArrayList: What is a Interface and what is a Class
Why I used List<Integer> instead of List<int>
What is the difference between Integer and int
One solution
loop through for the matrix to fetch the maximum value and store all rows and columns holding this value instead of a single row/column combination (countIndexHorizontal and countIndexVertical)
If a new maximum value is found, store it (like you did) AND store the current row and column index
If a value is identical to the current maximum value (e.g. you have 20 twice), then append the row and column index to the existing respective row / column list
loop a second time for updating and printing the value
it's basically combining your two last double-loop: if the scanned element belongs to a row or a column holding the maximum value, then the value must be set at 0 (exactly the way you did but shorter as I already have the list of rows / columns)
once the values are properly updated, just proceed to a simple printing
Which in code gives:
public static void main(String[] args) {
int[][] array2 = {
{1, 2, 3, 4},
{1, 2, 20, 4},
{1, 20, 2, 4},
{1, 2, 3, 4}
};
// find the maximum value and store its position:
// It's List instead of a single value as multiple
// rows and columns can hold the same maximum value
List<Integer> rowsWithMaxValue = new ArrayList<>();
List<Integer> colsWithMaxValue = new ArrayList<>();
int maxValue = Integer.MIN_VALUE;
// First matrix-scan to fetch the maximum value and the
// row(s) and column(s) to set the value at 0
for (int row = 0; row < array2.length; row++) {
for (int col = 0; col < array2[row].length; col++) {
// get the current value
int value = array2[row][col];
// found a new maximum or an existing one?
if (value > maxValue) {
// this is a new maximum value, we can reset
// the list as the previous rows and columns
// are not relevant anymore
maxValue = value;
rowsWithMaxValue = new ArrayList<>();
colsWithMaxValue = new ArrayList<>();
rowsWithMaxValue.add(row);
colsWithMaxValue.add(col);
} else if (value == maxValue) {
// The same value (like 20) is found again
// so multiple rows and columns will have
// their value set at 0
rowsWithMaxValue.add(row);
colsWithMaxValue.add(col);
}
}
}
// Second matrix-scan for updating the values and printing
for (int row = 0; row < array2.length; row++) {
for (int col = 0; col < array2[row].length; col++) {
// is it in a forbidden row? If yes, set the value
// at zero. One of the condition (row or column) is
// enough to have its value set at 0
if (rowsWithMaxValue.contains(row) || colsWithMaxValue.contains(col)) {
array2[row][col] = 0;
}
// Simply print the value
System.out.print(array2[row][col] + " ");
}
System.out.println();
}
}
1Integer in the mathematics meaning: positive or negative number without decimal
2I won't explain instantiation here. Feel free to google it
You can improve the program by changing the condition to
if (countIndexHorizontal == x || j == countIndexVertical)
Your program is deleting the wrong lines for the first 20 it finds (including the other 20).
This change will get you the correct answer for your specific case, but the program is still broken for examples like this
2 2
1 1
The correct output is
0 0
0 0
but it won't work because when it finds the first 2 it will delete the second 2, but the second 2 is still needed to clear the 0 in the bottom right corner. You're going to have to keep a separate data structure for the positions you want to clear. I'll leave that for you to figure out.
I'm trying to add all of the values for each column in a 2D array and these sums become values that overwrite the last row of the array
for example:
4 5 6 7 8
1 2 3 4 5
0 0 0 0 0 //this row will be replaced by the sum of each column
4 5 6 7 8
1 2 3 4 5
5 7 9 11 13
public static void fillTotals(int[][] scores)
{
int count = 0;
for (int r = 0; r < scores.length - 1; r++)
{
scores[r][0] += count;
scores[scores.length - 1][scores[0].length - 1] = count;
}
}
I thought I could keep the columns the same and add it down with the changing rows but it isn't rewriting the last row. Also I don't know how to change the values at the bottom
You need to iterate once over all rows and columns, actually iterate over all rows, for every column. If you assume that the number of columns is the same for every row, then you can use scores[0].length as a fixed value.
public static void fillTotals(int[][] scores) {
for (int c=0; c < scores[0].length; ++c) {
int sum = 0;
for (int r=0; r < scores.length - 1; ++r) {
sum += scores[r][c];
}
scores[scores.length - 1][c] = sum;
}
}
This assumes that the final row of the 2D array is not part of the sum and is available to be overwritten with the sum of all preceding values, for each column.
Well, the reason that nothing is being updated is that you never change count, so you just end up adding 0 to everything. I think what you want instead of:
scores[r][0] += count;
is:
count += scores[r][0];
That way count will contain the summation of every element in the first column.
To be clear, scores[r][0] += count; is the same as scores[r][0] = scores[r][0] + count;, whereas I think you probably want count = scores[r][0] + count;
That being said, Im still pretty sure this code isnt actually going to work (sorry), since you only ever actually sum values from the first column. However, for the sake of not just doing way may be a school assignment for you, Im just going to leave it there. If you're still stuck let me know, and I'll try to help!
So I want to add the rows and columns in this 2D array right here.
The array looks like this:
int[][] array = new int[3][3];
array[0][0] = 0;
array[1][0] = 0;
array[2][0] = 0;
array[1][0] = 0;
array[1][1] = 1;
array[1][2] = 2;
array[2][0] = 0;
array[2][1] = 2;
array[2][2] = 4;
So I have this set up in a 3x3 matrix on a sheet of paper and the first row should print out 0, second row should print out 3, third row should print out 6
first column should print out 0, second column should print out 3, third column should print out 6.
I have no clue where to start and I just need to see how to do this problem, because I have a few questions after this that involve this, so if you can just give me code that I can read it would be really helpful! Thanks!
The simplest way is to create two for loops - outer one goes through the rows, inner one goes through the columns. Then sum up the values for every column of a given row.
int[] colSums = {0,0,0};
for (int c=0;c<array.length;c++) {
int rowSum = 0;
for (int c2=0;c2<array[c].length;c2++) {
rowSum += array[c][c2];
colSums[c2] += array[c][c2];
}
System.out.println("Sum of row "+c+": "+rowSum);
}
for (int c=0;c<colSums.length;c++) {
System.out.println("Sum of column "+c+": "+colSums[c]);
}
This should be a fairly straight-forward question but I cannot seem to figure out how to get all diagonals of a non-square matrix.
I already have what I consider the anti-diagonals (examples at: https://stackoverflow.com/a/33769730), but I need the opposite diagonal lines too.
Example Array:
1 2 3 4
5 6 7 8
9 10 11 12
Current output:
[1], [2,5], [3,6,9], [4,7,10], [8,11], [12]
Expected additional output:
[4], [3,8], [2,7,12], [1,6,11], [5,10], [9]
I'm looking more for pseudocode so I can understand this better.
EDIT: Code I have to get anti-diagonals (since no one seems to want to follow link)
int ndiags = width + height - 1;
System.out.println("---");
for (int diag = 0; diag < ndiags; diag++) {
int row_stop = Math.max(0, diag - width + 1);
int row_start = Math.min(diag, height - 1);
for (int row = row_start; row >= row_stop; row--) {
// on a given diagonal row + col = constant "diag"
// diag labels the diagonal number
int col = diag - row;
System.out.println(col + "," + row);
relax(col, row);
}
System.out.println("---");
}
I tried the following, but I'm still just getting anti-diagonals:
int ndiags = width + height - 1;
System.out.println("---");
for (int diag = 0; diag < ndiags; diag++) {
int row_stop = Math.max(0, diag - height + 1);
int row_start = Math.min(diag, width - 1);
for (int row = row_start; row >= row_stop; row--) {
// on a given diagonal row + col = constant "diag"
// diag labels the diagonal number
int col = diag - row;
System.out.println(col + "," + row);
relax(col, row);
}
System.out.println("---");
}
You can generalize this code for any matrix...for now it prints correct output for above specified matrix
output: [4 ] [3 8 ] [2 7 12 ] [5 10 ] [9 ]
class Diagonal
{
public static void main(String[] args)
{
int r=3,c=4;
int Mat[][]={{1,2,3,4},{5, 6 ,7 ,8},{9,10,11,12}};
int x,y;
for(int i=c-1;i>0;i--)
{
y=i;x=0;
System.out.print("[");
while(y<c)
{
System.out.print(Mat[x][y]+" ");
x++;y++;
}
System.out.print("] ");
}
for(int i=1;i<r;i++)
{
x=i;y=0;
System.out.print("[");
while(x<r)
{
System.out.print(Mat[x][y]+" ");
x++;y++;
}
System.out.print("] ");
}
}
}
For anti-diagonal:
output: [1 ] [2 5 ] [3 6 9 ] [4 7 10 ] [8 11 ] [12 ]
class Diagonal
{
public static void main(String[] args)
{
int r=3,c=4;
int Mat[][]={{1,2,3,4},{5, 6 ,7 ,8},{9,10,11,12}};
int x,y;
for(int i=0;i<c;i++)
{
y=i;x=0;
System.out.print("[");
while(y>=0 && x<r)
{
System.out.print(Mat[x][y]+" ");
x++;y--;
}
System.out.print("] ");
}
for(int i=1;i<r;i++)
{
x=i;y=c-1;
System.out.print("[");
while(x<r)
{
System.out.print(Mat[x][y]+" ");
x++;y--;
}
System.out.print("] ");
}
}
}
Each diagonal going in top-left to bottom-right direction is defined by j - i value where i is a row number and j is column number. Note that some of identifiers can be negative.
So pseudocode may be like this:
Create a dictionary with int keys and Linst<int> values.
Iterate over each element of the array.
Append current element to the list identified by j - i value from dictionary.
In the end you can extract your lists from the dictionary in either way as items are sorted by integer key key. The sorting corresponds to the way of taking top-right or bottom-left diagonal first.
An advantage of this method is that you don't need to deal with your rectangular matrix dimensions and apply any checks. Just a single matrix traversal.
could you show an example of what the list might look like?
The dictionary might look like this:
keys: -2 -1 0 1 2 3
-------------------------------
lists: 9 5 1 2 3 4
10 6 7 8
11 12
List elements are visualized from top to bottom.