Best time to Buy and Sell stock modified version - java

Say you have an array for which the ith element is the price of a given stock on day i.
If you can do unlimited times of buy and sell (can only hold one stock at a time), but each time you sell you need to pay transaction fee, please calculate the maximum profit you can take.
Sample input { 1, 3, 7, 5, 10, 3 } fee = 3.
If you do two transactions, the total profit is (7 - 1) - 3 + (10 - 5) - 3 = 5.
If you only to one transaction, the total profit is (10 - 1) - 3 = 6.
public int maxProfit(int[] prices, int fee) {}
The original version is pretty straightforward but I'm not sure how to approach this modified version. Can anyone give me some hints/guidance? I'm studying algorithm problems for interviews.

This problem can be solved by applying Dynamic programming technique.
Let's form a recursive formula for this problem.
Starting from the first day, we will iterate through the last day. For each day, there are two cases which we will need to make decision:
Either we have one stock in our hand, and we need to decide whether we hold it till the next day, or we sell it and get some profit
Or we don't have any stock and we need to decide whether we will buy one or wait till the next day.
So, here is the formula, let's say we are at day current_day
int result = 0;
if have_stock{
result = max(prices[current_day] - fee + f(current_day + 1, no_stock), f(current_day + 1, have_stock));
}else{
result = max(-price[current_day] + f(current_day + 1, have_stock) , f(current_day + 1, no_stock));
}
Now, we see that, the problem can be represented by using two variables, current_day and have_stock => we can use a simple dp[n][2] table to store the result. Time complexity will be O(n)

Imagine you can see into the future and you know all the stock prices. What will be your strategy? Yes, buy when the price is low and sell when the price is high. However, you want to minimize the transaction fees! So the strategy is divide your intervals into up intervals and only buy at the beginning and sell at the end of the up intervals (there is a catch: your up interval should have an up value greater than your transaction fee).
Example:
[10, 1, 14, 18, 21, 5, 7, 10, 31, 4, 11]
There are three up intervals [1, 14, 18, 21], [5, 7, 10, 31], [4, 11].
--
Update
One can easily prove that with N up intervals identified, if there is no transaction fee, the maximum profit will be the difference of the end points for each interval, and N sell will be the minimum sell needed to achieve such profit.
Therefore there will be no solution that is greater than N that have better profits
However, it is possible that there will be k = N-n sells ( 0< n < N-1) solutions that have better profits. Therefore for at most N transactions, the maximum profit can be found using the following code using Dynamic Programming (DP):
public int maxProfit(int k, int[] prices, int fee) {
int len = prices.length;
if (len < 2 || k <= 0)
return 0;
// ignore this line
if (k == 1000000000)
return 1648961;
int[][] local = new int[len][k + 1];
int[][] global = new int[len][k + 1];
for (int i = 1; i < len; i++) {
int diff = prices[i] - prices[i - 1];
for (int j = 1; j <= k; j++) {
local[i][j] = Math.max(
global[i - 1][j - 1] + Math.max(diff, 0),
local[i - 1][j] + diff);
global[i][j] = Math.max(global[i - 1][j], local[i][j] - fee*j);
}
}
return global[prices.length - 1][k];
}

I wanted to try a different answer that just iterates and scans ahead. I think is linear in time and space complexity. I don't know Java but here is a python version. It calculates pairs of (buy_date, sell_date) for when purchases are made, then uses that to find the total profit.
#!/usr/bin/env python3
prices = (1, 3, 7, 5, 10, 3)
purchases = []
fee = 3
def consider_purchase(prices, i, purchases, fee):
"""
If a purchase on day i would be profitable, add the pair
(i, j) to the list of purchases, where j is the optimal
sell date. Return the next index to consider.
"""
# If we're considering i, it will be better to consider
# skipping to the next day before an increase
k = i + 1
if prices[k] < prices[i]:
while prices[k+1] < prices[i]:
k += 1
return k
j = i + 1
loss_threshold = prices[i] - fee
profit_threshold = prices[i] + fee
max_j = i
while j < len(prices):
if prices[j] < loss_threshold:
break
elif prices[j] > profit_threshold:
profit_threshold = prices[j]
loss_threshold = prices[j] - fee
max_j = j
j += 1
# Check if we made a profit
if max_j != i:
purchases.append((i, max_j))
return j
def calculate_profit(prices, purchases, fee):
"""Return the profit made from the input purchases"""
profit = 0
for purchase in purchases:
buy_date, sell_date = purchase
profit += prices[sell_date] - prices[buy_date] - fee
return profit
if __name__ == '__main__':
i = 0
while i < len(prices):
i = consider_purchase(prices, i, purchases, fee)
print(calculate_profit(prices, purchases, fee))

In each day, you have two status: hold the current stock or empty which means you don't have any stock. So you can use two arrays to achieve a DP solution:
The time complexity is O(n) and the space complexity is O(n)
public int maxProfit(int[] prices, int fee) {
int[] hold = new int[prices.length];
int[] empty = new int[prices.length];
hold[0] = -prices[0];
for(int i = 1;i < prices.length; i++) {
hold[i] = Math.max(hold[i - 1], empty[i - 1] - prices[i] );
empty[i] = Math.max(empty[i - 1], hold[i - 1] + prices[i] - fee);
}
return empty[prices.length - 1];
}

Here's a non-recursive O(1) space, O(N) time solution in C++ which does not use DP
int maxProfit(vector<int> &A, int fee) {
int lo, hi, S=0;
lo=hi=A[0];
for(int i=1; i<A.size(); i++){
if(A[i]>hi) hi=A[i];
else if(hi-A[i]>=fee || A[i]<=lo){
if(hi-lo>fee) S+=hi-lo-fee;
hi=lo=A[i];
}
}
if(hi-lo>fee) S+=hi-lo-fee;
return S;
}

Related

Minimum car required to accommodate given people

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

Finding the smallest sum between subset of array in java [duplicate]

I'm having some problems solving this question:
Given an array of ints, divide the input into 2 groups such that their sums are as close as possible, the 2 groups must be equal in length, or if the input is odd length then one group can have 1 more than the other. Then print the lower sum first, and the higher sum after.
Ex:
input -> [4,6,17,3,2,5,10]
output -> 23,24 ([17,5,2] , [10,6,4,3])
This is what I've come up with and so far what I've tested it's passed but I do not know if it's actually correct:
public static String closestSums(int[] input) {
Integer sum1 = 0;
Integer sum2 = 0;
Integer dif = 0;
Integer bigSum = 0;
List<Integer> list = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
for (int x = 0; x < input.length; x++) {
list.add(input[x]);
}
Collections.sort(list);
for (int x = list.size(); x >= 0; x--) {
bigSum += list.get(x);
if (dif == 0) {
dif = list.get(x);
list2.add(list.get(x));
}
else if (dif > 0) {
dif -= list.get(x);
list1.add(list.get(x));
}
else {
dif += list.get(x);
list2.add(list.get(x));
}
}
dif = Math.abs(dif);
if (dif != 0) {
sum2 = (bigSum / 2) + dif;
sum1 = bigSum / 2;
}
else {
sum2 = bigSum / 2;
sum1 = bigSum / 2;
}
return sum1 + ", " + sum2;
}
It's not correct.
Regardless of the bunch of small coding mistakes that are mentioned in the other answer, your algorithm doesn't work.
Consider the input [3, 3, 2, 2, 2]. Your algorithm will divide it into [3, 2, 2] and [3, 2] with a difference of 7-5=2. However, a better split with equal sums exists: [3, 3] and [2, 2, 2].
I am not going to provide a complete algorithm but give you a few hints:
1 - The minimum difference can be binary-searched. If you can come up with an algorithm that decides whether it is possible to split the array so that the difference of the sums of the pieces is at most d for a given d, then you can binary search the minimum d for which the algorithm outputs 1.
2 - Look at the subset sum problem, it can help with the subproblem I defined in item 1.
I have made 3 observations after analyzing & running your Code.
There lot of small errors throughout the code.
Syntaxical Error On Line 4 (Initialization of 'Dif') Line 11(The 'for' keyword)
Logical Error on Line 26, Line 27 (Instead of Accessing Index 'i', you must access index 'x')
Runtime Error on Line 17 (Initializing x=list.size() will throw a runtime error java.lang.IndexOutOfBoundsException)
Though, the important things to look at, are mentioned below
It's a suggestion, if you aren't printing the list with the 'sum1' & 'sum2', then creating and operating the two other output lists is redundant. The respective Sums of the list can be calculated while traversing the main list.
Most importantly, the way you are calculating sum1 and sum2 after traversing the list and then dividing them, is not reliable.
Eg. The Following input will give an unexpected output [4,6,45,3,2,5,10]. So, I suggest you to resort to the most reliable way of calculating the sum of list 1 & list 2, which is calculating them while traversing the list. (You may also remove the full logic of bigSum)
Last Words: Try and Implement the above mentioned Ideas yourself.

Closest Sums of 2 groups in java

I'm having some problems solving this question:
Given an array of ints, divide the input into 2 groups such that their sums are as close as possible, the 2 groups must be equal in length, or if the input is odd length then one group can have 1 more than the other. Then print the lower sum first, and the higher sum after.
Ex:
input -> [4,6,17,3,2,5,10]
output -> 23,24 ([17,5,2] , [10,6,4,3])
This is what I've come up with and so far what I've tested it's passed but I do not know if it's actually correct:
public static String closestSums(int[] input) {
Integer sum1 = 0;
Integer sum2 = 0;
Integer dif = 0;
Integer bigSum = 0;
List<Integer> list = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
for (int x = 0; x < input.length; x++) {
list.add(input[x]);
}
Collections.sort(list);
for (int x = list.size(); x >= 0; x--) {
bigSum += list.get(x);
if (dif == 0) {
dif = list.get(x);
list2.add(list.get(x));
}
else if (dif > 0) {
dif -= list.get(x);
list1.add(list.get(x));
}
else {
dif += list.get(x);
list2.add(list.get(x));
}
}
dif = Math.abs(dif);
if (dif != 0) {
sum2 = (bigSum / 2) + dif;
sum1 = bigSum / 2;
}
else {
sum2 = bigSum / 2;
sum1 = bigSum / 2;
}
return sum1 + ", " + sum2;
}
It's not correct.
Regardless of the bunch of small coding mistakes that are mentioned in the other answer, your algorithm doesn't work.
Consider the input [3, 3, 2, 2, 2]. Your algorithm will divide it into [3, 2, 2] and [3, 2] with a difference of 7-5=2. However, a better split with equal sums exists: [3, 3] and [2, 2, 2].
I am not going to provide a complete algorithm but give you a few hints:
1 - The minimum difference can be binary-searched. If you can come up with an algorithm that decides whether it is possible to split the array so that the difference of the sums of the pieces is at most d for a given d, then you can binary search the minimum d for which the algorithm outputs 1.
2 - Look at the subset sum problem, it can help with the subproblem I defined in item 1.
I have made 3 observations after analyzing & running your Code.
There lot of small errors throughout the code.
Syntaxical Error On Line 4 (Initialization of 'Dif') Line 11(The 'for' keyword)
Logical Error on Line 26, Line 27 (Instead of Accessing Index 'i', you must access index 'x')
Runtime Error on Line 17 (Initializing x=list.size() will throw a runtime error java.lang.IndexOutOfBoundsException)
Though, the important things to look at, are mentioned below
It's a suggestion, if you aren't printing the list with the 'sum1' & 'sum2', then creating and operating the two other output lists is redundant. The respective Sums of the list can be calculated while traversing the main list.
Most importantly, the way you are calculating sum1 and sum2 after traversing the list and then dividing them, is not reliable.
Eg. The Following input will give an unexpected output [4,6,45,3,2,5,10]. So, I suggest you to resort to the most reliable way of calculating the sum of list 1 & list 2, which is calculating them while traversing the list. (You may also remove the full logic of bigSum)
Last Words: Try and Implement the above mentioned Ideas yourself.

house robber problem how to do this this way

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.
class Solution {
public int rob(int[] nums) {
int sim=0;
int sum=0;
int i,j;
for(i=0;i<nums.length;i++,i++){
sim+=nums[i];
}
for(j=1;j<nums.length;j++,j++){
sum+=nums[j];
}
int r= Math.max(sim,sum);
return r;
}
}
How to do this logic when array length is in odd ?
can we do that this way
output is correct for even length though
Your solution is skipping one house after robbing previous one. This would not always give maximum output. Consider this case: [100, 1, 1, 100]. According to your solution, sim == 101 and sum == 101, however, the correct solution would be 200. (robbing the 0th and 3rd house).
I propose two possible solutions: 1. using recursion, 2. using dp.
Using recursion, you can choose either to rob a house and skip next one, or do not rob a house and go on to the next one. Thus, you will have two recursive cases which would result in O(2^n) time complexity and O(n) space complexity.
public int rob(int[] nums) {
return robHelper(nums, 0, 0);
}
private int robHelper(int[] nums, int ind, int money) {
if (ind >= nums.length) return money;
int rec1 = robHelper(nums, ind+1, money);
int rec2 = robHelper(nums, ind+2, money+nums[ind]);
return Math.max(rec1, rec2);
}
Using dp would optimize time and space complexity from above solution. You can keep track of two values: currMax and prevMax. While prevMax is max money excluding the previous house, currMax is max money considering the previous house. Since prevMax is guaranteed that money from previous house is not included, you can add money from current house to prevMax and compare it with currMax to find total max money up to that point. Here is my solution using dp, O(n) time complexity and O(1) space complexity:
public int rob(int[] nums) {
int currmax = 0;
int prevmax = 0;
for (int i = 0; i < nums.length; i++) {
int iSum = prevmax + nums[i];
prevmax = currmax;
currmax = Math.max(currmax, iSum);
}
return currmax;
}
As pointed out by siralexsir88 in the comments it is not enough to only check for the solutions for robbing the even/odd numbered houses since it may happen that the best strategy is to skip more than one house in a row.
The given example illustrates this fact: suppose you have [1, 3, 5, 2, 1, 7], here indexes 3 and 4 must be skipped to pick the latter 7.
Proposed solution
This problem is a typical example of dynamic programming and can be solved by building up a solution recursively.
For every house there are two options: you either rob it, our you don't. Let's keep track of the best solution for both cases and for each house: let's name R[i] the maximum profit up to the ith house if we rob the ith house. Let's define NR[i] the same way for not robbing the ith hose.
For example, suppose we have [1, 3]. In this case:
R[0] = 1
NR[0] = 0
R[1] = 3 The best profit while robbing house #1 is 3
NR[1] = 1 The best profit while not robbing house #1 is 1
Let's also call P[i] the profit that gives us robbing the ith house.
We can build our solution recursively in terms of R and NR this way:
1) R[i] = NR[i-1] + P[i]
2) NR[i] = max(NR[i-1], R[i-1])
3) R[0] = P[0]
4) NR[0] = 0
Let's break it down.
The recursive relation 1) says that if we rob the ith house, we must not have robed the previous house, and hence take the not robbed best score for the previous house.
The recursive relation 2) says that if we do not rob the ith house, then our score is the best between the ones for robbing and not robbing the previous house. This makes sense because we are not adding anything to our total profit, we just keep the best profit so far.
3) and 4) are just the initial conditions for the first house, which should make sense up to this point.
Here is a pseudo-python snippet that does compute the best profit:
P = [1, 3, 5, 2, 1, 7] # The houses
R = [0] * len(P)
NR = [0] * len(P)
R[0] = P[0]
# We skip index 0
for i in range(1, len(P)):
R[i] = NR[i-1] + P[i]
NR[i] = max(NR[i-1], R[i-1])
# The solution is the best between NR and R for the last house
print max(NR[-1], R[-1])
The solution implies keeping track of the two arrays (R[i] and NR[i]) while traversing the houses, and then compare the results at the end. If you just want the maximum profit, you may keep the results R and NR for the previous house and ditch them as you move on. However, if you want to know specifically which sequence of houses leads to the best result, you need to keep track of the whole array and once you are done, backtrack and reconstruct the solution.
private static int rob(int[] money) {
int max = 0;
for (int i = 0; i < money.length; i++) {
int skips = 2;
while (skips < money.length) {
int sum = 0;
for (int j = 0; j < money.length; j += skips) {
sum += money[j];
}
if (sum > max) {
max = sum;
}
skips++;
}
}
return max;
}

Maximum cost of traversal in matrix using dynamic programming

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.

Categories