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 :)
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];
}
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
example:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.
**Constraints**:
n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105
The issue with this is that it is outputting 0 for when the input is [2,0,2] but the code should be setting the index 1 to have a leftMax of 2 and rightMax of 2 so 2-0=2 should be the output
class Solution {
public int trap(int[] height) {
if(height == null || height.length == 0){
return 0;
}
int ans = 0;
int size = height.length;
int[] leftMax = new int[size];
int[] rightMax = new int[size];
leftMax[0] = height[0];
for(int i = 1; i < size; i++){
leftMax[i] = Math.max(leftMax[i-1],height[i]);
}
rightMax[0] = height[size-1];
for(int i = size-2; i >= 0; i--){
rightMax[i] = Math.max(rightMax[i+1],height[i]);
}
for(int i = 1; i < size-1; i++){
ans+= Math.min(leftMax[i],rightMax[i])-height[i];
}
return ans;
}
}
The problem is that your rightMax initialization is wrong, it initializes "on the wrong side". It initializes the [0] which was probably copied from the leftMax section. But the leftMax then iterates from the left, the rightMax iterates from the right and therefore the rightmost index should be initialized. Note that you already initialized with the correct height index but for the wrong rightMax - it should look like:
rightMax[size-1] = height[size-1]
This previously worked because the very right was (probably) not part of a water trap and therefore its wrong value did not have any impact. But in the very simply case of 2,0,2 it is part of the trap and messed up the result.
Now the code properly calculates the two given samples:
System.out.println(trap(new int[] {0,1,0,2,1,0,1,3,2,1,2,1})); // 6
System.out.println(trap(new int[] {2,0,2})); // 2
I've came across the following problem statement.
You have a list of natural numbers of size N and you must distribute the values in two lists A and B of size N/2, so that the squared sum of A elements is the nearest possible to the multiplication of the B elements.
Example:
Consider the list 7 11 1 9 10 3 5 13 9 12.
The optimized distribution is:
List A: 5 9 9 12 13
List B: 1 3 7 10 11
which leads to the difference abs( (5+9+9+12+13)^2 - (1*3*7*10*11) ) = 6
Your program should therefore output 6, which is the minimum difference that can be achieved.
What I've tried:
I've tried Greedy approach in order to solve this problem. I took two variables sum and mul. Now I started taking elements from the given set one by one and tried adding it in both the variables and calculated current
square of sum and multiplication. Now finalize the element in one of the two sets, such that the combination gives minimum possible value.
But this approach is not working in the given example itselt. I can't figure out what approach could be used here.
I'm not asking for exact code for the solution. Any possible approach and the reason why it is working, would be fine.
EDIT:
Source: CodinGame, Community puzzle
Try out this:
import java.util.Arrays;
public class Test {
public static void main(String [] args){
int [] arr = {7, 11, 1, 9, 10, 3, 5, 13, 9, 12};
int [][] res = combinations(5, arr);
int N = Arrays.stream(arr).reduce(1, (a, b) -> a * b);
int min = Integer.MAX_VALUE;
int [] opt = new int [5];
for (int [] i : res){
int k = (int) Math.abs( Math.pow(Arrays.stream(i).sum(), 2) - N/(Arrays.stream(i).reduce(1, (a, b) -> a * b)));
if(k < min){
min = k;
opt = i;
}
}
Arrays.sort(opt);
System.out.println("minimum difference is "+ min + " with the subset containing this elements " + Arrays.toString(opt));
}
// returns all k-sized subsets of a n-sized set
public static int[][] combinations(int k, int[] set) {
int c = (int) binomial(set.length, k);
int[][] res = new int[c][Math.max(0, k)];
int[] ind = k < 0 ? null : new int[k];
for (int i = 0; i < k; ++i) {
ind[i] = i;
}
for (int i = 0; i < c; ++i) {
for (int j = 0; j < k; ++j) {
res[i][j] = set[ind[j]];
}
int x = ind.length - 1;
boolean loop;
do {
loop = false;
ind[x] = ind[x] + 1;
if (ind[x] > set.length - (k - x)) {
--x;
loop = x >= 0;
} else {
for (int x1 = x + 1; x1 < ind.length; ++x1) {
ind[x1] = ind[x1 - 1] + 1;
}
}
} while (loop);
}
return res;
}
// returns n choose k;
// there are n choose k combinations without repetition and without observance of the sequence
//
private static long binomial(int n, int k) {
if (k < 0 || k > n) return 0;
if (k > n - k) {
k = n - k;
}
long c = 1;
for (int i = 1; i < k+1; ++i) {
c = c * (n - (k - i));
c = c / i;
}
return c;
}
}
Code taken from this stackoverflow answer, also take a look at this wikipedia article about Combinations.
I am not sure if there is any exact solution in polynomial time. But you could try a simulated annealing based approach.
My approach would be:
Initialize listA and listB to a random state
With probability p run greedy step, otherwise run a random step
Keep track of the state and corresponding error (with a HashMap)
Greedy step: Find one element you can move between the list that optimizes the error.
Random Step: Pick a random element from either of these two sets and calculate the error. If the error is better, keep it. Otherwise with probability of q keep it.
At either of these two steps make sure that the new state is not already explored (or at least discourage it).
Set p to a small value (<0.1) and q could depend on the error difference.
How can i proceed to calculate the number of fragments in a N level Triangle
fragment is a straight line that contains one or more match.
Notice that actually we can count the fragments for one orientation and multiply by 3 as they are symmetric (as shown as 3 different colors in the graph)
Let's count for one orientation:
Each level x has x matches, and we can choose x length 1 fragments, x-1 length 2 fragments, x-2 length 3 fragments ... and so on.
So for each level x, there is 1+2+3+...+x = x*(x+1)/2 fragments
So we can simply loop for all level x for one orientation, and multiply by 3.
Here is a sample C++ code:
#include<bits/stdc++.h>
using namespace std;
int n, ans = 0;
int main() {
cin >> n;
for(int i=1; i<=n ;i++){
ans += (1+i)*i / 2;
}
ans *= 3;
cout << ans << endl;
return 0;
}
int n = n;
int con = 3;
int frag = 0;
for(int i =0; i<= n; i++)
{
frag += i*con;
}
return frag;
notice that for a row of matches of size n, there are (n*(n+1))/2 (or n+1 choose 2) fragments.
lets just think about the rows which are horizontal. we start from the smallest horizontal row (size 1) and go up to the largest horizontal row (size n). Thats how we construct our loop. Now notice that for the diagonally oriented rows, the number of fragments in them will be the same as the number of fragments in the horizontal rows.
Given there are three orientations with we can take the result of our loop and multiply it by 3. theres your answer.
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += (i * (i + 1))/2;
}
sum *= 3;
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.