Project Euler Problem 18 - Pascal's Triangle - java

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];
}

Related

How to realign numbers from an Integer array to a Jtable?

Sorry for bad expression to make people confused, i edit my question again.
There is Integer array , it contains 29 numbers, These 29 numbres are made up of 0 to 10.
For example: Integer [ ] num ={ 0,3,4,5,6,1,3,10,4,3,1,0,2,2,3,4,1,0,8,7,6,6,5,8,9,0,5,10,8} I want to realign these numbers into Jtable(limits 6 rows,10 columns).
if 0 <= number < 5,i will call them "Small" number;
if 5 <= number < 10,i will call them “Big" number;
if number = 10, i will call them "P"number.
In a word, the 29 numbers are made up of 3 type number("Samll","Big","P").
In the array num, we can see first three number is belong to "Small" number,so they show one by one in c1,the fourth is 5,it is "Big"number,so it jump to next column, it goes c2,the remaining cells of c1 will not be used again. if the same type number is over 6,it wil turn right to next nearest cell to contiune showing(See 2nd sample image).others array numbers are the same logic,loop the array num and then show the numbers according to the number type in jtable.
The final result what i want in Jtable ,you can see below sample images i post. Anybody posts sample code will be very helpful to me,Thanks in advance!
Below sencond sample image, the red underline number total 10 "Small" numbers over 6, so turn to the right nearest cell to contiune showing. The green underline total 7 "Big" numbers ,because the sixth cell in c6 has been occupied, so it turns right to contiune showing after fifth cell
I wrote code just to create the 6 x 10 int matrix.
Here's the output from one of my many tests.
0 5 1 10 4 8 0 5 10 8
3 6 3 3 7
4 1 6
0 6
2 5 8 9
2 3 4 1 0
Oracle has a helpful tutorial, Creating a GUI With JFC/Swing, that will help you learn how to create a Swing GUI. Skip the Netbeans section.
You will want to use a JTable to display your matrix.
When tackling a problem like creating your matrix, it helps to break it down into steps. Keep breaking it down into steps until you can code each step.
This task was so complicated, I had to print debug output to make sure I was making progress. Don't be afraid to put many System.out.print and System.out.println statements in your code. You can use a DEBUG boolean like I did to turn the extra print statements off.
Here's the complete runnable code to create the 6 x 10 matrix. I didn't check for more than 10 subsets of values. I left that for you.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RealignNumbers {
private static final boolean DEBUG = false;
public static void main(String[] args) {
RealignNumbers rn = new RealignNumbers();
int[] numbers = { 0, 3, 4, 5, 6, 1, 3, 10, 4, 3, 1, 0, 2, 2, 3, 4, 1, 0,
8, 7, 6, 6, 5, 8, 9, 0, 5, 10, 8 };
int[][] matrix = rn.realignNumbers(numbers);
printMatrix(matrix);
}
private static void printMatrix(int[][] matrix) {
for (int row = 0; row < matrix.length; row++) {
for (int column = 0; column < matrix[row].length; column++) {
if (matrix[row][column] >= 0) {
String display = String.format("%3d", matrix[row][column]);
System.out.print(display);
} else {
System.out.print(" ");
}
}
System.out.println();
}
}
public int[][] realignNumbers(int[] numbers) {
List<List<Integer>> matrixList = splitInput(numbers);
printList(matrixList);
int[][] matrix = fillMatrix(matrixList);
return matrix;
}
private List<List<Integer>> splitInput(int[] numbers) {
List<List<Integer>> matrixList = new ArrayList<>();
int number = numbers[0];
boolean isSmall = number < 5;
List<Integer> numberList = new ArrayList<>();
numberList.add(Integer.valueOf(number));
for (int index = 1; index < numbers.length; index++) {
if (numbers[index] == 10) {
// Finish prior List if exists
if (numberList.size() > 0) {
matrixList.add(numberList);
numberList = new ArrayList<>();
}
// Create numberList for 10
numberList.add(Integer.valueOf(numbers[index]));
matrixList.add(numberList);
// Start new List
numberList = new ArrayList<>();
} else {
boolean small = numbers[index] < 5;
if (isSmall == small) {
// Add number to List
numberList.add(Integer.valueOf(numbers[index]));
} else {
// Number is different; end list and start new List
matrixList.add(numberList);
numberList = new ArrayList<>();
numberList.add(Integer.valueOf(numbers[index]));
isSmall = small;
}
}
}
if (numberList.size() > 0) {
matrixList.add(numberList);
}
return matrixList;
}
private void printList(List<List<Integer>> matrixList) {
if (DEBUG) {
int count = 1;
for (List<Integer> numberList : matrixList) {
String display = String.format("%2d", count++);
System.out.print("List " + display + " ");
for (int number : numberList) {
display = String.format("%3d", number);
System.out.print(display);
}
System.out.println();
}
}
}
private int[][] fillMatrix(List<List<Integer>> matrixList) {
int masterColumn = -1;
int length = 6;
boolean firstTimeSwitch = true;
int[][] matrix = new int[length][10];
for (int[] row : matrix) {
Arrays.fill(row, -1);
}
for (List<Integer> numberList : matrixList) {
masterColumn++;
int column = masterColumn;
int row = 0;
for (int number : numberList) {
if (DEBUG) {
System.out.println("row " + row + " column " + column);
}
matrix[row][column] = number;
// Check if we hit the last row
// If so, increment columns
if (row < (length - 1)) {
row++;
} else {
if (firstTimeSwitch) {
length--;
firstTimeSwitch = false;
}
column++;
}
}
if (length < 6) {
firstTimeSwitch = true;
}
}
return matrix;
}
}
If you really want to do this, then think of a jTable much like a 2D array, for example, int[][] yourArray = new int[6][10];.
So the first number in your list goes at yourArray[0][0] = 0, and the next two go on the same column yourArray[1][0] = 3 and yourArray[2][0] = 4, and the next number 5 goes into a new column yourArray[0][1] = 5 and so on.
So when it comes to turning you could do something like this inside the loop that places numbers into the jTable:
if(row > rowCount) {
col++;
yourTableModel.setValueAt(number, row, col);
}
But to make sure that nothing overlaps when turning also use:
//Insert value if able
if(yourTableModel.getValueAt(row, col) != null){
row++;
yourTableModel.setValueAt(number, row, col);
}
//Move to next col if not able to fit the number within the row
else{
col++;
yourTableModel.setValueAt(number, row, col);
}

DFS method not producing expected output

So the goal is to print all possible numbers whose digits can be formed by a sequence of adjacent characters on a board using dfs. By adjacent I mean next to each other, either vertically, horizontally or diagonally. There are 8 total movement directions. Ex: the board below
1 2
3 4
To make it simpler let's say that we always have to start at row0 column0, which is 1. So the possible numbers are: 1, 12, 13, 14, 123, 124, 132, 134, 142, 143, 1234, etc (this case is pretty trivial because all numbers are directly adjacent to each other)
So I have the following code:
static char[][] grid;
static int rows;
static int columns;
public static void main(String[] args) {
//test grid. made it small so that solutions are easy to count
grid = new char[][]{
new char[]{'1', '2'},
new char[]{'3', '4'},
};
rows = grid.length;
columns = grid[0].length;
dfs(0, 0, new boolean[rows][columns], new StringBuilder());
}
public static void dfs(int row, int col, boolean[][] visited, StringBuilder builder){
visited[row][col] = true;
builder.append(grid[row][col]);
System.out.println(builder.toString());
//the 2 loops are for the 8 movement directions
for(int x = -1; x <= 1; x++){
for(int y = -1; y <= 1; y++){
//index bounds check
if((row + x >= 0) && (row + x < rows) && (col + y >= 0) && (col + y < columns)){
if(!visited[row + x][col + y]){
dfs(row + x, col + y, visited, builder);
// I tried changing it so that it passes a COPY of 'visited' and 'builder',
// but output still the same
dfs(row + x, col + y, Arrays.copyOf(visited, visited.length), new StringBuilder(builder));
}
}
}
}
}
My code's output is not right. Here's what it prints:
1
12
123
1234
Those numbers are part of the solution, but are a lot more numbers than that. The error probably has something to do with passing the same object into the recursive dfs() call, but I tried changing it so that it only copies the object, and it still gives the same output.
Any ideas?
You should be able to do achieve the expected output without creating a copy of the visited matrix.
The important thing is to set visited[row][col] to false after each COMPLETE visit down a path.
Example:
Let's say you've traversed '12' and now have '3' and '4' left to visit. In the current state, visited matrix's values for '1' and '2' are set to true and for '3' and '4' are set to false. Once you have finished generating all strings that begin with '12', you will start looking at all strings beginning with '13'.
But look at what happens here! You had set the visited value of '2' to true, and so no future strings containing '2' will ever be generated.
This is why you must set visited[row][col] to false after you are done generating all paths from that point onward.
To truly understand this, trace your code with pen and paper and you will remember it better.
Note:
In reality, in the example described above, you will never generate strings beginning with '13' because visited[1][1] would have been set to true before and so 3 would have never been reached again. I ignored that fact to illustrate a point.
Why do I suggest not making a deep copy of visited each recursive call? Simple, to save time and space. Each call will take O(m*n) space and time to generate and store a new visited matrix.
Here is one variant of the correct code:
import java.util.*;
public class DFS{
static char[][] grid;
static int rows;
static int columns;
public static void main(String[] args) {
//test grid. made it small so that solutions are easy to count
grid = new char[][]{
new char[]{'1', '2'},
new char[]{'3','4'},
};
rows = grid.length;
columns = grid[0].length;
ArrayList<String>list = new ArrayList<>();
dfs(0, 0, new boolean[rows][columns], new StringBuilder());
//System.out.println(list);
}
public static void dfs(int row, int col, boolean[][] visited, StringBuilder builder){
visited[row][col] = true;
builder.append(grid[row][col]);
System.out.println(builder);
for(int x = -1; x <= 1; x++){
for(int y = -1; y <= 1; y++){
//index bounds check
if((row + x >= 0) && (row + x < rows) && (col + y >= 0) && (col + y < columns)){
if(!visited[row + x][col + y]){
dfs(row + x, col + y, visited, builder);
}
}
}
}
visited[row][col]=false;
builder.deleteCharAt(builder.length()-1);
}
}
EDIT: I forgot to highlight the last line of code added where I delete the last character of the current StringBuilder. This is the backtracking bit so that after all '12xx' strings are generated, you delete '2', replace it with '3' and now start exploring the '13xx' family of strings.

Java how to find the middle of a 2d array

I'm writing a function that tries to find the middle of a 2d array, and here's what I have so far:
int findMiddle(int[][] grid,int [] m) {
int[] list = new int[grid.length*grid[0].length];
int listPos = 0;
for(int i = 0 ; i < grid.length; i++) {
for(int j = 0; j < grid.length; j++) {
list[listPos++] = grid[i][j];
}
}
int middle = m.length/2;
if (m.length%2 == 1) {
return m[middle];
} else {
return (m[middle-1] + m[middle]) / 2.0;
}
}
Suppose I have an array of
{{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 0, 1}}
It should return 6, as it is integer division.
Also, the definition of middle in this code is the middle integer of the whole original array (needless to say if it is sorted or not).
How would I do this? ( my code also doesn't compile)
This compiles, and will give you the middle number in your sequence, or the average of the middle two if it splits the middle:
static double findMiddle(int[][] grid) {
int[] list = new int[grid.length*grid[0].length];
int listPos = 0;
for(int i = 0 ; i < grid.length; i++) {
for(int j = 0; j < grid[i].length; j++) {
list[listPos++] = grid[i][j];
}
}
int middle = list.length/2;
if ((list.length%2) == 1) {
return list[middle];
}
return (list[middle-1] + list[middle]) / 2.0;
}
However, I suspect you'll want to sort you numbers after you combine them into a single array, before you find the middle numbers. (as piyush121 commented)
Assuming your definition of 'median' is correct (the middle number of an odd length set or the average of the two middle numbers of an even length set), and if grid[][] is sorted, and if grid[][] is a square array (i.e. grid.length = grid[i].length for all i in 0..length-1, then you don't need to copy data to another array. The following should suffice:
static int findMiddle(int[][] grid) {
int l = grid.length;
if (l%2 == 1) {
return grid[l/2][l/2];
} else {
return (grid[l/2-1][l-1]+grid[l/2][0])/2;
};
Looking at your existing code it seems you are defining 'median' as the middle value in the matrix if all values were put into a single row-wise list. In other words you don't need to cope with odd numbers of rows (when two numbers from the same column are in the middle) or odd numbers of rows and columns (when there are four numbers in the middle).
If that definition is correct then you can cope with all the complexity of uneven rows by streaming all values and then selecting the middle ones.
For your interest, here's a Java 8 solution that does that:
int[] flat = Arrays.stream(grid).flatMapToInt(Arrays::stream).toArray();
double middle = Arrays.stream(flat).skip(flat.length / 2).limit(1 + flat.length % 2)
.average().getAsDouble();

Need help iterating through smaller 2D "subarrays" found in larger 2D array

I am working on a project that requires finding some smaller 2d int arrays contained within a larger 2d int array.
To be more specific, I will be provided with a text file for input. The text file will contain an N, M, and K value, as well as integers to populate a "large" MxN grid. I will then need to find all "small" KxK grids within that larger MxN grid, and return the largest int within each KxK grid.
So, for example:
m = 3; n = 4; k = 2
MxN:
3 4 2
2 3 1
8 3 2
7 8 1
The 1st KxK grid to analyze would be:
3 4
2 3
return 4;
The 2nd:
4 2
3 1
return 4;
The 3rd:
2 3
8 3
return 8;
etc, etc.
Is there a slick way of iterating through these KxK grids with the mod operator or something? I feel like there is a simple solution for this, but it's not obvious to me.
I know this is more of a math problem than a programming one, but any help would be appreciated.
Thanks.
I've tried to write little code here:
private int[] getMaxFromGrids(int k, int[][] yourArray){
int m = yourArray.length; //height of grid
int n = yourArray[0].length; //width of grid, assuming that all inner array have same length!
//argument k is size of smaller grid
//computing max possibilities to fit smaller grid to larger one
int maxPossibilities = (m - k + 1) * (n - k + 1);
if(maxPossibilities < 1 || k < 1) return null;
int[] maxValuesSmallGrid = new int[maxPossibilities];
for (int i = 0; i < (maxPossibilities); i++) {
//computing actual start element for small grid
int colStartElement = i % (n - (k - 1));
int rowStartElement = i / (n - (k - 1));
//creating smaller grid
int[] smallGrid = new int[k * k];
int o = 0; //index of smaller grid
for (int j = colStartElement; j < colStartElement + k; j++) {
for (int l = rowStartElement; l < rowStartElement + k; l++) {
smallGrid[o++] = yourArray[j][l];
}
}
maxValuesSmallGrid[i] = getMax(smallGrid);
}
return maxValuesSmallGrid;
}
//method for getting max number from given array
private int getMax(int[] numbers) {
int max = Integer.MIN_VALUE;
for(int num : numbers) {
if(num > max) max = num;
}
return max;
}
Given that K<=N && K<=M, you can easily find all subarray2d by moving their top left corner from 0,0 to N-K,M-K (use 2 for loops)
Then make a function taking the coordinates of the top left corner of a K*K subarray2d and returning its higher value :)

Android - Compute times a two numbers appear in cell number

Could anyone help me. I am trying to compute the number of times certain numbers appear in a table layout row - vertically and Horizontally, in other words. I would like to fill an array of numbers between say (4 and 5) to make it so that the number say 4 appears only 4times and 5 only twice (vertically & Horizontally) in say 6 * 6..take note
How can I work with any of this?
public boolean hasRepeatedNumbers(int[] x) {
int[] y = new int[x.length];
System.arraycopy(x, 0, y, 0, y.length);
Array.sort(y);
int i;
for (i = 1; i < y.length; i++) {
if (y[i] == y[i-1]) return true;
}
return false;
}
or
private int[] calculateUsedCells(int x, int y) {
int c[] = new int[2];
// horizontal
for (int i = 0; i < 2; i++) {
if (i == y)
continue;
int t = getCell(x, i);
if (t != 0)
c[t - 1] = t;
}
}
Any advice would be great, thanks.
Consider taking an int array and increase the element in the array at index of the value in the cell, at the end check the values in the array. You will get the number of times each number appeared.
Ex:
Number 4 has appeared in 1, 2, 5, 6 cells
array[content of the cell]++;
So at the end array[4] gives the number of times 4 appeared.

Categories

Resources