Related
I had one coding round where question statement was like this
*You have a given number of friends and seating capacity of their cars now you need to find minimum number of cars required to accommodate them all.
Example:
People = [1, 4, 1]
SeatingCapacity = [1, 5, 1]
In this case we need minimum 2 cars as number of people on 0th index can adjust with index 1 car.
Example 2:
People = [4, 4, 5, 3]
SeatingCapacity = [5, 5, 7, 3]
This case answer will be as index 3 people can be accommodate into 0,1,2 or 1,2 index car*
I wrote code like this
int numberOfCars(int[] p, int[] s) {
int noOfCars=p.length;
Int extraSeats=0;
for(int i=0;i<p.length;i++) {
extraSeats+= (s[i] - p[i])
}
for(int i=0;i<p.length;i++) {
if(extraSeats-p[i] >=0){
extraSeats-= p[i] ;
noOfCars--;
}
}
return noOfCars;
}
However my code failed for many cases as well as it was saying some performance issue.
Can anyone please tell me which cases I missed?
This can be solved by just greedy approach. Like below:
people = [1,4,1]
p = sum(people) //6
cars = [1,5,1]
sort(cars, descending) //cars = [5,1,1]
idx = 0
while(p > 0) { p -= cars[idx]; idx += 1 }
answer = idx
Handle the corner case where total capacity in cars is less than number of people.
Complexity : sorting cars O(n log n) + while loop O(n) = O(n log n)
This would be my solution in Javascript:
function peopleCars (persons, seats) {
let numberOfCars = 0;
let people = persons.reduce((previousValue, currentValue) => previousValue + currentValue, 0); //Calculate total number of persons
seats.sort((a,b) => {return b-a}); //Rearrange the total number of seats in each car in ascending order to fill the seats starting from the one that can take the most persons
while(people > 0) {
people -= seats[numberOfCars]; //subtract the numbers of seats of each car from the number of persons available. This will now leave us with the remaining people
numberOfCars += 1 //increment the number of cars to be used.
}
return numberOfCars
}
// console.log (peopleCars( [2,1,2,2], [5,4,2,5]));
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am trying to find the O(N) solution with Divide & Conquer for the next problem:
Given a circularly sorted array, I need the sum of the positive numbers on it. i.e:
If the array is: {-2, 0, 3, 4, 11, 13, -23, -15, -8}
Then the algorithm should return 31.
I think I'm close to it with the following code, but it's weirdly returning -17 and I cannot find the problem debugging:
public class Main {
private static final int[] TEST_VECTOR = new int[]{-2, 0, 3, 4, 11, 13, -23, -15, -8};
public static int sumPositives2(int[] vector) {
return maximumSum(vector,0, vector.length - 1);
}
// Function to find Maximum subarray sum using
// divide and conquer
public static int maximumSum(int[] A, int left, int right)
{
// If array contains only one element
if (right == left) {
return A[left];
}
// Find middle element of the array
int mid = (left + right) / 2;
// Find maximum subarray sum for the left subarray
// including the middle element
int leftMax = Integer.MIN_VALUE;
int sum = 0;
for (int i = mid; i >= left; i--)
{
if(A[i] > 0) {
sum += A[i];
}
}
// Find maximum subarray sum for the right subarray
// excluding the middle element
int rightMax = Integer.MIN_VALUE;
sum = 0; // reset sum to 0
for (int i = mid + 1; i <= right; i++)
{
if(A[i] > 0) {
sum += A[i];
}
}
// Recursively find the maximum subarray sum for left
// subarray and right subarray and tale maximum
int maxLeftRight = maximumSum(A, left, mid) +
maximumSum(A, mid + 1, right);
// return maximum of the three
return maxLeftRight + leftMax + rightMax;
}
public static void main(String[] args)
{
System.out.println("The Maximum sum of the subarray is " +
maximumSum(TEST_VECTOR, 0, TEST_VECTOR.length - 1));//Should be 31
}
}
Edit: Would this solution be O(N)?
Thank you for your time.
You can easily get an O(n) solution if you go through the array once and sum up only positive numbers. An enhanced for loop seems suitable:
public static void main(String[] args) {
int[] circularlySortedArray = {-2, 0, 3, 4, 11, 13, -23, -15, -8};
// define a variable for the sum
int sumOfPositives = 0;
// go through all numbers in the array (n numbers)
for (int number : circularlySortedArray) {
// check if the number is positive
if (number >= 0) {
// and add it to the sum variable
sumOfPositives += number;
}
}
// then print the result
System.out.println("The sum of positive numbers is " + sumOfPositives);
}
The output in this case is
The sum of positive numbers is 31
The sorting does not have any influence on the algorithm.
Your solution would be O(n) if it was working, but you don't really have to divide and conquer here because it cannot be done in less than O(n) anyway, it's not a binary search.
EDIT
Since the text and code above seems not to be satisfying enough, I re-thought my statement about divide and conquer here. The task may be done in less than n steps, but O(n) will still be correct. The sorting does provide a possibility of not going through all elements of the array, but that won't be achievable in every case.
Imagine the following arrays, which are all circularly sorted, and please have a look at the patterns below them, they may be the key to a divide-and-conquer solution here and/or to a solution with an average case (Big Theta) of less than n, while the worst case (Big O) will still stay O(n)…
The examples all have n = 7 elements and each one has p = 4 positive elements (including 0) and l = 3 negative elements. Iterating through all of them will always be O(n), which would be O(6) here. In some of the cases, the sorting provides information about what's at the end of the array, which enables a programmer to reduce the best case (Big Omega) to O(p + 1) = O(p) = O(4) in some of the situations:
The following array takes n steps because one has to check every element
{-3, -2, -1, 0, 1, 2, 3}
n n n p p p p
The next example takes n - 1 steps, because there is are two negative numbers after all the positives and you only have to find the first one in order to meet a break condition. That's because there was a negative number already at a lower index.
{-1, 0, 1, 2, 3, -2, -3}
n p p p p n n
This next one takes only p + 1 (which means O(p + 1) = O(p)) steps because you can break the loop at the first negative number found. Why? Because the array starts with the smallest possible number that is positive (by definition) and the first negative number found indicates no need for further processing.
{0, 1, 2, 3, -1, -2, -3}
p p p p n n n
This last example requires n steps again, because you are looking for positive numbers which are at the beginning and at the end of the array. There is no chance of directly knowing at which index they are.
{3, -3, -2, -1, 0, 1, 2}
p n n n p p p
The only way (I know) to optimize the average case would be implementing the break conditions of the loop according to the possible patterns. So store indexes and do checks based on them, but I think the effect won't be that huge.
This is my first approach, may be optimized in several ways, I have only tried it with the examples of this edit:
public static void main(String[] args) {
int[] circularlySortedArray = { 0, 1, 2, 3, -1, -2, -3 };
// define a variable for the sum of positive values
int sumOfPositives = 0;
// define a variable for the lowest index of a positive number
int firstPositiveIndex = -1;
// define a variable for the lowest positive number found
int smallesPositiveNumber = 0;
// start iterating the array
for (int i = 0; i < circularlySortedArray.length; i++) {
System.out.println("Current index: " + i
+ ", current value: " + circularlySortedArray[i]);
// provide a variable for the current number to make this code a little more
// readable
int number = circularlySortedArray[i];
// check if the current number is positive
if (number >= 0) {
// add it to the sum
sumOfPositives += number;
System.out.println("Added " + number
+ " to sumOfPositives (now: " + sumOfPositives + ")");
// check if it is the first positive number found
if (firstPositiveIndex < 0) {
// if yes, set the variable value accordingly
System.out.println("First and smallest positive number ("
+ number
+ ") found at index "
+ i);
firstPositiveIndex = i;
smallesPositiveNumber = number;
}
System.out.println("————————————————————————————————");
} else {
// break conditions based on index & value of the smallest positive number found
if (i > firstPositiveIndex && firstPositiveIndex > 0) {
System.out.println("Stopped the loop at index " + i);
break;
} else if (smallesPositiveNumber == 0 && firstPositiveIndex == 0) {
System.out.println("Stopped the loop at index " + i);
break;
}
System.out.println(number + " is not positive, skip it");
System.out.println("————————————————————————————————");
continue;
}
}
System.out.println("The sum of positive numbers is " + sumOfPositives);
}
What you're asking for is impossible.
The input array could potentially be all positive values which means you have to at least read and sum all elements. That's O(n).
Even if not all elements are positive, unless it's defined that no more than O(log n) elements are positive the same conclusion remains.
How would I go about calculating the big O of a DP algorithm. I've come to realize my methods for calculating algorithms doesn't always work. I would use simple tricks to extract what the Big O was. For example if I were evaluating the none memoized version of the algorithm below (removing the cache mechanism) I would look at the number of times the recursive method called itself in this case 3 times. I would then raise this value to n giving O(3^n). With DP that isn't right at all because the recursive stack doesn't go as deep. My intuition tells me that the Big O of the DP solution would be O(n^3). How would we verbally explain how we came up with this answer. More importantly what is a technique that can be used to find the Big O of similar problems. Since it is DP I'm sure the number of sub problems is important how do we calculate the number of sub problems.
public class StairCase {
public int getPossibleStepCombination(int n) {
Integer[] memo = new Integer[n+1];
return getNumOfStepCombos(n, memo);
}
private int getNumOfStepCombos(int n, Integer[] memo) {
if(n < 0) return 0;
if(n == 0) return 1;
if(memo[n] != null) return memo[n];
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
return memo[n];
}
}
The first 3 lines do nothing but compare int values, access an array by index, and see if an Integer reference is null. Those things are all O(1), so the only question is how many times the method is called recursively.
This question is very complicated, so I usually cheat. I just use a counter to see what's going on. (I've made your methods static for this, but in general you should avoid static mutable state wherever possible).
static int counter = 0;
public static int getPossibleStepCombination(int n) {
Integer[] memo = new Integer[n+1];
return getNumOfStepCombos(n, memo);
}
private static int getNumOfStepCombos(int n, Integer[] memo) {
counter++;
if(n < 0) return 0;
if(n == 0) return 1;
if(memo[n] != null) return memo[n];
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
return memo[n];
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
counter = 0;
getPossibleStepCombination(i);
System.out.print(i + " => " + counter + ", ");
}
}
This program prints
0 => 1, 1 => 4, 2 => 7, 3 => 10, 4 => 13, 5 => 16, 6 => 19, 7 => 22, 8 => 25, 9 => 28,
so it looks like the final counter values are given by 3n + 1.
In a more complicated example, I might not be able to spot the pattern, so I enter the first few numbers (e.g. 1, 4, 7, 10, 13, 16) into the Online Encyclopedia of Integer Sequences and I usually get taken to a page containing a simple formula for the pattern.
Once you've cheated in this way to find out the rule, you can set about understanding why the rule works.
Here's how I understand where 3n + 1 comes from. For each value of n you only have to do the line
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
exactly once. This is because we are recording the results and only doing this line if the answer has not already been calculated.
Therefore, when we start with n == 5 we run that line exacly 5 times; once for n == 5, once with n == 4, once with n == 3, once with n == 2 and once with n == 1. So that's 3 * 5 == 15 times the method getNumOfStepCombos gets called from itself. The method also gets called once from outside itself (from getPossibleStepCombination), so the total number of calls is 3n + 1.
Therefore this is an O(n) algorithm.
If an algorithm has lines that are not O(1) this counter method cannot be used directly, but you can often adapt the approach.
Paul's answer is technically not wrong but is a bit misleading. We should be calculating big O notation by how the function responds to changes in input size. Paul's answer of O(n) makes the complexity appear to be linear time when it really is exponential to the number of bits required to represent the number n. So for example, n=10 has ~30 calculations and m=2 bits. n=100 has ~300 calculations and m=3 bits. n=1000 has ~3000 calculations and m=4 bits.
I believe that your function's complexity would be O(2^m) where m is number of bits needed to represent n. I referred to https://www.quora.com/Why-is-the-Knapsack-problem-NP-complete-even-when-it-has-complexity-O-nW for a lot of my answer.
Suppose I've a m x n matrix in Java.
I want to find the maximum traversal cost from first column to last column. Each value represents the cost incurred. I'm allowed to travel in up, down and right directions across the matrix. Each cell can be visited only once. Transitions are allowed from a top cell of a column to the bottom of the same and vice-versa.
For simplicity, consider the following matrix:
2 3 17
4 1 -1
5 0 14
If I'm supposed to find the maximum cost, my answer would be 46 (2 → 5 → 4 → 1 → 3 → 0 → 14 → 17).
I've tried to solve this problem using dynamic approach using the following recursive relation:
maxCost(of destination node) = max{ maxCost(at neighbouring node 1), maxCost(at neighbouring node 2), maxCost(at neighbouring node 3) } + cost(of destination node)
In this case, it would be something like:
maxCost(17) = max{ maxCost(3), maxCost(-1), maxCost(14) } + 17;
Since, each cell is allowed to be visited only once, I understand that I would need to maintain a corresponding m x n isVisited matrix. However, I can't figure out how to maintain isVisited matrix. The matrix would be modified when maxCost(3) is calculated; but for maxCost(-1) and maxCost(14), I would require its initial status (which would be lost).
Is my approach correct for this problem? Also, I can't figure out how should my functions look like.
(This is my first attempt at dynamic programming).
It's a tough one. Notice that since your path cannot repeat visited cells your possible paths would have 'snake'-like behavior such as:
The idea is to store in f[j][i] the maximum length of paths that end at the cell (j, i). Lets say now that we want to transition from f[j][i-1] to f[j'][i]. We can, then, either choose to go from cell (j, i) to cell (j', i) directly or we could go from cell (j, i) to cell (j', i) by wrapping around the top/botton edge. So the update for f[j][i], then, could be calculated as:
where
Here a is the given array.
The problem now is how to calculate sum(a[j..j'][i] effectively since otherwise the runtime would be O(m^3n). You can solve this by using a temporary variable tmp_sum for the sum(a[j..j'][i]) which you increment as you increment j. The runitme of algorithm then would be O(m^2 n).
Here is an sample implementation:
package stackoverflow;
public class Solver {
int m, n;
int[][] a, f;
public Solver(int[][] a) {
this.m = a.length;
this.n = a[0].length;
this.a = a;
}
void solve(int row) {
f = new int[m][n];
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
f[i][j] = Integer.MIN_VALUE;
for (int i = 0; i < n; ++i) {
int sum = 0;
for (int j = 0; j < m; ++j)
sum += a[j][i];
for (int j1 = 0; j1 < m; ++j1) {
int tmp_sum = 0;
boolean first = true;
for (int j2 = j1; j2 != j1 || first; j2 = (j2+1)%m) {
if (first)
first = false;
tmp_sum += a[j2][i];
int best_sum = Math.max(tmp_sum, sum - tmp_sum +a[j1][i]+a[j2][i]);
if (j1 == j2)
best_sum = a[j1][i];
int prev = 0;
if (i > 0)
prev = f[j1][i-1];
f[j2][i] = Math.max(f[j2][i], best_sum + prev);
}
}
}
System.out.println(f[row][n-1]);
}
public static void main(String[] args) {
new Solver(new int[][]{{2, 3, 17}, {4, 1, -1}, {5, 0, 14}}).solve(0); //46
new Solver(new int[][]{{1, 1}, {-1, -1}}).solve(0); //2
}
}
This is a nice and slightly tricky problem. For a DP solution, we must phrase it in a way that comports with the principle of optimality.
This requires us to define a "state" so that the problem can be written in terms of an n-way decision that takes us to a new state that, in turn, is a new, smaller version of the same problem.
A suitable choice for state is the current position of the traversal plus a signed integer f that says where and how many untraversed (I'll call them "free") rows there are in the current column. We can write this as a triple [i,j,f].
The value of f tells us whether it's okay to move up and/or down. (Unless we're in the right column, it's always possible to move right, and it's never possible to move left.) If f is negative, there are f free rows "above" the current position, which may wrap around to the matrix bottom. If positive, there are f free rows below. Note that f=m-1 and f=1-m mean the same thing: all rows are free except the current position's. For simplicity, we'll use f==m-1 to represent that case.
The single integer f is all we need to describe free spaces because we can only only traverse in steps of size 1, and we never move left. Ergo there can't be non-contiguous groups of free spaces in the same column.
Now the DP "decision" is a 4-way choice:
Stand pat at the current square: only valid in the last column.
Move up: only valid if there's free space above.
Move down: only valid if there's free space below.
Move right: valid except in the last column.
Let, C(t) be the max cost function in the DP, where t is a triple [i,j,f]. Then the max cost we can achieve is the cost A[i,j] from the matrix added to the cost of the rest of the traversal after making the optimum decision 1 to 4 above. The optimum decision is just the one that produces the highest cost!
All this makes C the max of a set where all the elements are conditional.
C[i,j,f] = max { A[i,j] if j==n-1, // the "stand pat" case
{ A[i,j]+C[i,j+1,m-1] if j<n-1 // move right
{ A[i,j]+C[i+1,j,f-1] if f>0 // move down
{ A[i,j]+C[i-1,j,2-m] if f==m-1 // first move in col is up
{ A[i,j]+C[i-1,j,f+1] if f<0 // other moves up
Sometimes words are clearer than algebra. The "down" case would be...
One potential max path cost from position [i,j] to the goal (right column) is the matrix value A[i,j] plus the max cost obtainable by moving down to position [i+1,j]. But we can move down only if there are free spaces there (f>0). After moving down, there's one less of those (f-1).
This explains why the recursive expression is C[i+1,j,f-1]. The other cases are just variations of this.
Also note that the "base cases" are implicit above. In all states where f=0 and j=n-1, you have them. The recursion must stop.
To get the final answer, you must consider the max over all valid starting positions, which are the first column elements, and with all other elements in the column free: max C[i,0,m-1] for i=0..m-1.
Since you were unsuccessful with finding a DP, here is a table-building code to show it works. The dependencies in the DP require care in picking the evaluation order. Of course the f parameter can be negative, and the row parameter wraps. I took care of these in 2 functions that adjust f and i. Storage is O(m^2):
import java.util.Arrays;
public class MaxPath {
public static void main(String[] args) {
int[][] a = {
{2, 3, 17},
{4, 1, -1},
{5, 0, 14}
};
System.out.println(new Dp(a).cost());
}
}
class Dp {
final int[][] a, c;
final int m, n;
Dp(int[][] a) {
this.a = a;
this.m = a.length;
this.n = a[0].length;
this.c = new int[2 * m - 2][m];
}
int cost() {
Arrays.fill(c[fx(m - 1)], 0);
for (int j = n - 1; j >= 0; j--) {
// f = 0
for (int i = 0; i < m; i++) {
c[fx(0)][i] = a[i][j] + c[fx(m - 1)][i];
}
for (int f = 1; f < m - 1; f++) {
for (int i = 0; i < m; i++) {
c[fx(-f)][i] = max(c[fx(0)][i], a[i][j] + c[fx(1 - f)][ix(i - 1)]);
c[fx(+f)][i] = max(c[fx(0)][i], a[i][j] + c[fx(f - 1)][ix(i + 1)]);
}
}
// f = m-1
for (int i = 0; i < m; i++) {
c[fx(m - 1)][i] = max(c[fx(0)][i],
a[i][j] + c[fx(m - 2)][ix(i + 1)],
a[i][j] + c[fx(2 - m)][ix(i - 1)]);
}
System.out.println("j=" + j + ": " + Arrays.deepToString(c));
}
return max(c[fx(m - 1)]);
}
// Functions to account for negative f and wrapping of i indices of c.
int ix(int i) { return (i + m) % m; }
int fx(int f) { return f + m - 2; }
static int max(int ... x) { return Arrays.stream(x).max().getAsInt(); }
}
Here's the output. If you understand the DP, you can see it building optimal paths backward from column j=2 to j=0. The matrices are indexed by f=-1,0,1,2 and i=0,1,2.
j=2: [[31, 16, 14], [17, -1, 14], [17, 13, 31], [31, 30, 31]]
j=1: [[34, 35, 31], [34, 31, 31], [34, 32, 34], [35, 35, 35]]
j=0: [[42, 41, 44], [37, 39, 40], [41, 44, 42], [46, 46, 46]]
46
The result shows (j=0, column f=m-1=2) that all elements if the first column are equally good as starting points.
Thank you everyone for your contributions.
I've come up with a solution using recursive technique using system stack. I think that my solution is relatively easier to understand.
Here's my code:
import java.util.Scanner;
public class MatrixTraversal {
static int[][] cost;
static int m, n, maxCost = 0;
public static void solve(int currRow, int currCol, int[][] isVisited, int currCost) {
int upperRow, lowerRow, rightCol;
isVisited[currRow][currCol] = 1;
currCost += cost[currRow][currCol]; //total cost upto current position
if( currCol == (n - 1) //if we have reached the last column in matrix
&& maxCost < currCost ) //and present cost is greater than previous maximum cost
maxCost = currCost;
upperRow = ((currRow - 1) + m) % m; //upper row value taking care of teleportation
lowerRow = (currRow + 1) % m; //lower row value taking care of teleportation
rightCol = currCol + 1; //right column value
if( isVisited[upperRow][currCol] == 0 ) //if upper cell has not been visited
solve(upperRow, currCol, isVisited, currCost);
if( isVisited[lowerRow][currCol] == 0 ) //if lower cell has not been visited
solve(lowerRow, currCol, isVisited, currCost);
if( rightCol != n && //if we are not at the last column of the matrix
isVisited[currRow][rightCol] == 0 ) //and the right cell has not been visited
solve(currRow, rightCol, isVisited, currCost);
isVisited[currRow][currCol] = 0;
}
public static void main(String[] args) {
int[][] isVisited;
int i, j;
Scanner sc = new Scanner(System.in);
System.out.print("Enter the no.of rows(m): ");
m = sc.nextInt();
System.out.print("Enter the no.of columns(n): ");
n = sc.nextInt();
cost = new int[m][n];
isVisited = new int[m][n];
System.out.println("Enter the cost matrix:");
for(i = 0; i < m; i++)
for(j = 0; j < n; j++)
cost[i][j] = sc.nextInt(); //generating the cost matrix
for(i = 0; i < m; i++)
solve(i, 0, isVisited, 0); //finding maximum traversal cost starting from each cell in 1st column
System.out.println(maxCost);
}
}
However, I'm not sure whether this is the best and the fastest way to compute the solution.
Please let me know your views. I'll accept this as answer accordingly.
One possible optimization is that we only need to calculate different options (other than a full sum) for columns with negative numbers or sequences of non-negative columns less than m in length, enclosed by columns with negatives. We need one column and a (conceptual) matrix to compute the max for a sequence of such columns; a matrix for the current column that converts into a column of maximums for each exit point. Each matrix represents the maximum sum for entry at y and exit at y' combined with the previous max just preceding the entry point (there are two possibilities for each, depending on the path direction). The matrix is symmetrically reflected along the diagonal (meaning sum entry...exit = sum exit...entry) until the various previous maximums for each entry point are added.
Adding an additional column with negative numbers to the example, we can see how the cummulative sums may be applied:
2 3 17 -3
4 1 -1 15
5 0 14 -2
(We'll ignore the first two non-negative columns for now and add 15 later.)
Third column:
y' 0 1 2
y
0 17 30 31
1 30 -1 30
2 31 30 14
For the fourth column matrix, each entry point needs to be combined with the maximum for the same exit point from the previous column. For example, entry point 0 is added with max(17,30,31):
y' 0 1 2
y
0 -3 12 10 + max(17,30,31)
1 12 15 13 + max(30,-1,30)
2 10 13 -2 + max(31,30,14)
=
28 43 41
42 45 43
41 44 29
We can see the final max has (entry,exit) (1,1) and solution:
15 + (0,1) or (2,1) + (1,1)
Let's see how the dynamic programming answers here differ from the brute-force approach in your answer, and how we may tweak yours. Take the simple example,
a = {{17, -3}
,{-1, 15}}
Brute-force will traverse and compare all paths:
17,-3
17,-3,15
17,-1,15
17,-1,15,-3
-1,15
-1,15,-3
-1,17,-3
-1,17,-3,15
The dynamic-programming solutions take advantage of the choice-point between columns since there is only one possibility there - move right. At each move between columns, the dynamic-programming solutions apply a pruning method, using the max function, that limits the search to proven higher cost paths over others.
The up-down choices in the recursive solution offered by Gene, lead to a similar traversal found in the loops in svs' solution, meaning choices between entry and exit in the same column will be pruned. Look again at our example:
a = {{17, -3}
,{-1, 15}}
f(-1) -> max(15,15 - 3)
-> 17 -> max(-3,-3 + 15)
f(17) -> max(-3,-3 + 15)
-> -1 -> max(15,15 - 3)
There's no need to check the full path sum -1,15,-3 or to check both 17 - 1 + 15 and 17 - 1 + 15 - 3 since in each case we already know which ending would be greater, thanks to the max function: 17 - 1 + 15.
The matrix array solutions work slightly differently to the recursive but with a similar effect. We focus only on the move between columns, j to j + 1, which can only happen in one place, and we choose to add only the best sum so far up to j when we calculate j + 1. Look at the example:
a = {{17, -3}
,{-1, 15}}
Calculate the matrix of best sums for exit points along column j = 0, in O(m^2) time:
17
16
Now for j = 1, we calculate the best paths achievable only along column j = 1 with exit points along column j = 1, remembering to add to these paths' entry points the previous best (meaning the number from the column immediately to the left, denoted with *):
best exit at -3 = max(-3 + 17*, 15 - 3 + 16*) = 28
best exit at 15 = max(15 + 16*, -3 + 15 + 17*) = 31
Now to tweak your version, think about how you could alter it so the recursion chooses at each step the greatest sum returned from among its subsequent calls.
I hate to have to ask, but I'm pretty stuck here.
I need to test a sequence of numbers to find the first which has over 500 factors:
http://projecteuler.net/index.php?section=problems&id=12
-At first I attempted to brute force the answer (finding a number with 480 after a LONG time)
-I am now looking at determining the prime factors of a number and then use them to find all other factors.
I am currently at the stage where I can get an array of prime factors for any number I input - i.e 300 has the prime factors 2 2 3 5 5
Using this array of prime factors I need to be able to calculate the remaining factors - This is the part I am stuck on. Basically, as I understand it, I need to calculate ALL possible combinations of the numbers in the array...
i.e
2 * 2
2 * 2 * 3
2 * 2 * 3 * 5
2 * 3
2 * 3 * 3
...and so forth - But where it gets interesting is with things like...
2 * 5
2 * 3 * 5
...i.e Numbers which are not adjacent to each other in the array
I can't think of a way to code this in a generic fashion for any length array...
I need help! P.S - I am working in Java
EDIT: My brute force code - As it has been suggested brute forcing the problem will work and so there may be an error in my code :(
package euler.problem12;
public class Solution {
public static void main(String[] args) {
int next = 1;
int triangle = 0;
int maxFactors = 0;
while(true) {
triangle = triangle + next;
int factors = 1;
int max = (int) triangle / 2;
for(int i = 1; i <= max; ++i) {
if(triangle % i == 0) {
factors ++;
}
}
if(factors > maxFactors) {
maxFactors = factors;
System.out.println(triangle + "\t" + factors);
}
next++;
}
}
}
OK, second attempt as I was making things far too difficult.
Answer is given here: Link
If you factor a number into its prime
power factors, then the total number
of factors is found by adding one to
all the exponents and multiplying
those results together. Example: 108 =
2^2 * 3^3, so the total number of
factors is (2+1) * (3+1) = 3 * 4 = 12.
Sure enough, the factors of 108 are 1,
2, 3, 4, 6, 9, 12, 18, 27, 36, 54, and
108. This happens because to be a factor, a number must have the same
primes, and raised to the same or lower powers.
So if you know the prime factors, you just need to count the repeated ones and use the above calculation to work out the number of factors.
As far as I can tell, question 12 doesn't mention anything about prime numbers? Is this the one you're looking at?
The sequence of triangle numbers is generated by adding the natural numbers...
If so, then perhaps not thinking about primes will help? ;)
Possibly 3 months too late, but here goes...
I see that answer two has privided the function to give you the answer you require, but in answer to your original question on how you generate all the factors assuming you need to for some reason, then here's how you do it:
Assuming that you have the factors in an array:
int[] primeFactors = new int[] {2, 2, 3, 5, 5};
What you need to do is recurse every in-order permutation for each possible depth, and then reduce the resulting result set to just the unique values.
I'll explain what I mean:
"In-order permutation": assuming you start at position 0 of the array, the next element must be 1, 2, 3 or 4, if you start from 1 then the next one must be 2, 3 or 4 and so on.
"Each possible depth": each single factor, then any two factors, then any three factors and so on until you get to all five factors.
"Reduce the set": If you take two elements, say 0&3, 0&4, 1&3 or 1&4 they all give you 2 * 5 = 10, they all provide the factor 10, so you need to winnow your set to just distinct values. (Phew, this is getting longer than I expected... :))
The way to do this is to use two methods, one to select the maximum depth of recursion, kick off the recustion and the winnow the final results, and the other to recurse the values:
public static void main(String[] args) {
int[] primeFactors = new int[] {2, 2, 3, 5, 5};
List<Integer> allFactors = getAllFactors(primeFactors);
for (int factor : allFactors) {
System.out.println("Factor: " + factor);
}
}
private static List<Integer> getAllFactors(int[] primeFactors) {
Set<Integer> distinctFactors = new HashSet<Integer>();
for (int maxDepth = 0; maxDepth <= primeFactors.length; maxDepth++) {
permutatPrimeFactors(0, maxDepth, 0, 1, primeFactors, distinctFactors);
}
List<Integer> result = new ArrayList<Integer>(distinctFactors);
Collections.sort(result);
return result;
}
private static void permutatPrimeFactors(int depth, int maxDepth, int minIndex, int valueSoFar, int[] primeFactors, Set<Integer> distinctFactors) {
if (depth == maxDepth) {
distinctFactors.add(valueSoFar);
return;
}
for (int index = minIndex; index < primeFactors.length; index++) {
permutatPrimeFactors(depth + 1, maxDepth, index + 1, valueSoFar * primeFactors[index], primeFactors, distinctFactors);
}
}
The getAllFactors uses a Set to make sure we only get distinct values, than adds them to a list and sorts that so that we can display the factors in order.
While permutatPrimeFactors, generates from zero terms (factor = 1) though to all terms (factor = 1 * 2 * 2 *3 * 5 * 5 = 300).
Hope that helps.