DP - Min cost climbing stairs - recursion

I'm trying to solve Min cost - climbing stairs problem.
This is the link: https://leetcode.com/problems/min-cost-climbing-stairs/
I've written the recursive version of the solution and it worked for the sample test cases, and obviously it showed TLE for the rest cases.
Here's the recursive version:
int solve(int[] arr, int idx, int cost) {
if(idx >= arr.length) return cost;
return Math.min(solve(arr, idx + 1, cost + arr[idx]),
solve(arr, idx + 2, cost + arr[idx]));
}
Now, the problem is when I'm trying to memoize it using 1-d array, I'm not getting correct answers for sample cases as well.
Here's the memoized version:
int[] t;
Solution() {
this.t = new int[1001];
}
public int minCostClimbingStairs(int[] arr) {
int n = arr.length;
Arrays.fill(t, -1);
return Math.min(solve(arr, 0, 0), solve(arr, 1, 0));
}
int solve(int[] arr, int idx, int cost) {
if(idx >= arr.length) return cost;
if(t[idx] != -1) return t[idx];
return t[idx] = Math.min(solve(arr, idx + 1, cost + arr[idx]),
solve(arr, idx + 2, cost + arr[idx]));
}
What am I missing?
Thanks in advance.
From a Noob in DP.

Related

Comparing DFS(recursive) + DP(memoization) vs General Recursion + DP (memoization)

I have been using DFS + memoization type approach to solve DP problems. Till now it had worked perfectly for every problem. But recently when I tried it for 0/1 knapsack problem it gave TLE in geeksforgeeks but works fine in Leetcode.
General approach is either consider current element or move forward in the array.
But the approach which I use is, I explicitly mention in a for loop where it must go. Like for eg either go to 2nd or 3rd or... or 10th element. I have analysed my approach and it seems for me. But i am unable to understand why it gives TLE.
Code of my approach which gives TLE is:
int dp[1001][1001];
int util(int indx, int cur_weight, int n,int weights[], int values[]){
if(dp[indx][cur_weight]!=-1)return dp[indx][cur_weight];
int mx_val=0;
for(int i=indx+1;i<n;i++){
if(cur_weight-weights[i]>=0)
mx_val=max(mx_val, util(i,cur_weight-weights[i],n,weights,values));
}
dp[indx][cur_weight]=mx_val+values[indx];
return dp[indx][cur_weight];
}
int knapSack(int W, int wt[], int val[], int n)
{
memset(dp, -1, sizeof(dp));
int mx_val=0;
for(int i=0;i<n;i++){
if(wt[i]<=W)
mx_val=max(mx_val,util(i,W-wt[i],n,wt,val));
dp[i][W]=mx_val;
}
return mx_val;
}
Code of another solution which uses standard DP solution and doesn't give TLE is:
int dp[1001][1001];
int answer(int w, int wt[], int val[], int n){
if(n == 0 || w == 0)
return 0;
if(dp[n-1][w] != -1)
return dp[n-1][w];
if(wt[n-1] <= w){
return dp[n-1][w] = max(val[n-1] + answer(w-wt[n-1], wt, val, n-1), answer(w, wt, val, n-1));
}
return dp[n-1][w] = answer(w, wt, val, n-1);
}
int knapSack(int W, int wt[], int val[], int n)
{
// Your code here
memset(dp, -1, sizeof(dp));
return answer(W, wt, val, n);
}
Can anyone please help?

How to find two optimal weights in a vector?

Imagine you're given an unsorted array [5,11,7,4,19,8,11,6,17] and a max weight 23. [similar to Two Sum Problem by a bit different]
One needs to find two optimal weights (by which I mean if two weights that are (almost or not) half of the weight you're trying to find) in this case [5,17], [3,19], [11,11] so I need to return [11,11].
I was taken back by the problem, and could not solve it. [I was not allowed to use structs]
I tried to sort [3, 5, 6, 7, 8, 11, 11, 17, 19] and search from both ends and store indexes of values that were <= max weight in a vector as a pair (like v[i], v[i+1] and check them later by their pairs) then return a pair with both largest vals, but got confused.
[although, weights were doubles and I did not see duplicates at that set I did not use unsorted_map(hashMap), might it've worked?]
Can anyone suggest how should I go about this problem? is it similar to "knapsack problem"? Thank you
You can use Two Pointer Approach for the problem.
Algorithm:
Sort the array.
Have two pointers startIndex and endIndex to 0 and arraySize-1.
sum = arr[startIndex] + arr[endIndex]
If sum is less than or equal to 23, increment startIndex else decrement endIndex.
keep track of closest value using a variable.
finish when startIndex == endIndex
Code in Java:
public class Solution {
private ArrayList<Integer> twoSumClosest(ArrayList<Integer> a, int s) {
// Sort the arraylist
Collections.sort(a);
// closests sum we got till now
int sumClosest = Integer.MIN_VALUE;
// indexes used to traverse
int startIndex = 0;
int endIndex = a.size() - 1 ;
// answer Indexes
int firstIndex = 1;
int secondIndex = a.size() - 1;
while( startIndex < endIndex ) {
if( a.get(startIndex) + a.get(endIndex) > s) {
endIndex--;
continue;
} else {
if( a.get(startIndex) + a.get(endIndex) > sumClosest ) {
sumClosest = a.get(startIndex) + a.get(endIndex);
firstIndex = startIndex;
secondIndex = endIndex;
}
startIndex++;
}
}
ArrayList<Integer> ans = new ArrayList<>();
ans.add(firstIndex);
ans.add(secondIndex);
return ans;
}
}
Time Complexity: O(nlogn)
O(n) if array was already sorted
Extra Space Needed: O(1)

Dynamic Programming - The wine selling with maximum profit

Let’s consider you have a collection of N wines placed next to each other on a shelf. The price of the ith wine is pi. (prices of different wines can be different). Because the wines get better every year, supposing today is the year 1, on year y the price of the ith wine will be y*pi, i.e. y-times the value that current year.
You want to sell all the wines you have, but you want to sell exactly one wine per year, starting on this year. One more constraint - on each year you are allowed to sell only either the leftmost or the rightmost wine on the shelf and you are not allowed to reorder the wines on the shelf (i.e. they must stay in the same order as they are in the beginning).
You want to find out, what is the maximum profit you can get, if you sell the wines in optimal order?
int N; // number of wines
int p[N]; // array of wine prices
int cache[N][N]; // all values initialized to -1
int profit(int be, int en) {
if (be > en)
return 0;
if (cache[be][en] != -1)
return cache[be][en];
int year = N - (en-be+1) + 1;
return cache[be][en] = max(profit(be+1, en) + year * p[be],profit(be, en-1) + year * p[en]);
}
Time Complexity: O(n^2).
I have already found this O(n^2) solution. Can we do it in O(n) ? (Better time complexity)
You are supposed to find the optimal cost by selling all the wines from the shelf. And only the constraint is that you are allowed to pick only left or right wine(you can't pick a wine bottle from the middle of the shelf).
As we are allowed to pick the left or right wine, the optimal sequence of solution will include either left or right bottle.
Let's find a recursive solution for that.
Just pick-up the left bottle and calculate it's cost
pick-up the right bottle and calculate the cost
Compare both the cost and choose the maximum cost
Write the necessary condition for the base case
Let's write a c++ program for this--
#include<bits/stdc++.h>
using namespace std;
int max_cost(int wine[], int cost, int counter, int i, int j){
// Here `counter` keeps track of the number of years
// `i` is the left indices of the shelf
// `j` is the right indices of the shelf
// `cost` is the maximum cost that we have to find
if(i > j)
return cost;
else if(i == j){
cost += counter * wine[i];
return cost;
}
else{
int cost1 = counter * wine[i] + max_cost(wine, 0, counter + 1, i + 1, j);
int cost2 = counter * wine[j] + max_cost(wine, 0, counter + 1, i, j - 1);
cost += max(cost1, cost2);
return cost;
}
}
int main(){
int n;
cin >> n;
int wine[n];
for(int j = 0; j < n; ++j)
cin >> wine[j];
cout << max_cost(wine, 0, 1, 0, n - 1) << endl;
return 0;
}
I think the above code is self exlanatory
Let's run it:
Input1:
5
1
3
1
5
2
Output:
43
Input2:
4
10
1
10
9
Output:
79
The time complexity of above code is O(2^n), where n is the no. of wine bottles in the shelf.
Can we improvise the time complexity?
Ofcourse. We are basically calculating for some sequences again and again, which can be avoided by memorization technique.
The recurrence relation will be basically same. In addition to that, we will memorize the value for the specific i and j. And hence we will not have to calculate the value for the same i and j again and again.
The c++ code will be --
#include<bits/stdc++.h>
using namespace std;
int find_cost(vector<int>& box, vector<vector<int>>& dp, int i, int j){
if(i == j) // base case
dp[i][j] = box[i] * box.size();
else if(!dp[i][j]){ // If not calculated so far
int n = box.size();
dp[i][j] = max(find_cost(box, dp, i, j - 1) + box[j] * (n - (j - i)),
find_cost(box, dp, i + 1, j) + box[i] * (n - (j - i)));
}
return dp[i][j];
}
void cost_wine(vector<int> box){
int n = box.size();
vector<vector<int>> dp(n + 1, vector<int>(n + 1)); // Initialize dp array
cout << find_cost(box, dp, 0, n - 1);
return;
}
int main(){
int n;
cin >> n;
vector<int> box(n);
for(int i = 0; i < n; ++i)
cin >> box[i];
cost_wine(box);
return 0;
}
Now the time complexity of the above code would be O(n^2), which is far better than the recursion method.

sequence of numbers using recursion

I want to compute sequence of numbers like this:
n*(n-1)+n*(n-1)*(n-2)+n*(n-1)*(n-2)*(n-3)+n*(n-1)*(n-2)*(n-3)*(n-4)+...+n(n-1)...(n-n)
For example n=5 and sum equals 320.
I have a function, which compute one element:
int fac(int n, int s)
{
if (n > s)
return n*fac(n - 1, s);
return 1;
}
Recomputing the factorial for each summand is quite wasteful. Instead, I'd suggest to use memoization. If you reorder
n*(n-1) + n*(n-1)*(n-2) + n*(n-1)*(n-2)*(n-3) + n*(n-1)*(n-2)*(n-3)*...*1
you get
n*(n-1)*(n-2)*(n-3)*...*1 + n*(n-1)*(n-2)*(n-3) + n*(n-1)*(n-2) + n*(n-1)
Notice how you start with the product of 1..n, then you add the product of 1..n divided by 1, then you add the product divided by 1*2 etc.
I think a much more efficient definition of your function is (in Python):
def f(n):
p = product(range(1, n+1))
sum_ = p
for i in range(1, n-1):
p /= i
sum_ += p
return sum_
A recursive version of this definition is:
def f(n):
def go(sum_, i):
if i >= n-1:
return sum_
return sum_ + go(sum_ / i, i+1)
return go(product(range(1, n+1)), 1)
Last but not least, you can also define the function without any explicit recursion by using reduce to generate the list of summands (this is a more 'functional' -- as in functional programming -- style):
def f(n):
summands, _ = reduce(lambda (lst, p), i: (lst + [p], p / i),
range(1, n),
([], product(range(1, n+1))))
return sum(summands)
This style is very concise in functional programming languages such as Haskell; Haskell has a function call scanl which simplifies generating the summands so that the definition is just:
f n = sum $ scanl (/) (product [1..n]) [1..(n-2)]
Something like this?
function fac(int n, int s)
{
if (n >= s)
return n * fac(n - 1, s);
return 1;
}
int sum = 0;
int s = 4;
n = 5;
while(s > 0)
{
sum += fac(n, s);
s--;
}
print sum; //320
Loop-free version:
int fac(int n, int s)
{
if (n >= s)
return n * fac(n - 1, s);
return 1;
}
int compute(int n, int s, int sum = 0)
{
if(s > 0)
return compute(n, s - 1, sum + fac(n, s));
return sum;
}
print compute(5, 4); //320
Ok ther is not mutch to write. I would suggest 2 methodes if you want to solve this recursiv. (Becaus of the recrusiv faculty the complexity is a mess and runtime will increase drasticaly with big numbers!)
int func(int n){
return func(n, 2);
}
int func(int n, int i){
if (i < n){
return n*(fac(n-1,n-i)+func(n, i + 1));
}else return 0;
}
int fac(int i,int a){
if(i>a){
return i*fac(i-1, a);
}else return 1;
}

Optimization of Fibonacci sequence generating algorithm

As we all know, the simplest algorithm to generate Fibonacci sequence is as follows:
if(n<=0) return 0;
else if(n==1) return 1;
f(n) = f(n-1) + f(n-2);
But this algorithm has some repetitive calculation. For example, if you calculate f(5), it will calculate f(4) and f(3). When you calculate f(4), it will again calculate both f(3) and f(2). Could someone give me a more time-efficient recursive algorithm?
I have read about some of the methods for calculating Fibonacci with efficient time complexity following are some of them -
Method 1 - Dynamic Programming
Now here the substructure is commonly known hence I'll straightly Jump to the solution -
static int fib(int n)
{
int f[] = new int[n+2]; // 1 extra to handle case, n = 0
int i;
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
A space-optimized version of above can be done as follows -
static int fib(int n)
{
int a = 0, b = 1, c;
if (n == 0)
return a;
for (int i = 2; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
return b;
}
Method 2- ( Using power of the matrix {{1,1},{1,0}} )
This an O(n) which relies on the fact that if we n times multiply the matrix M = {{1,1},{1,0}} to itself (in other words calculate power(M, n )), then we get the (n+1)th Fibonacci number as the element at row and column (0, 0) in the resultant matrix. This solution would have O(n) time.
The matrix representation gives the following closed expression for the Fibonacci numbers:
fibonaccimatrix
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
/*multiplies 2 matrices F and M of size 2*2, and
puts the multiplication result back to F[][] */
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
/*function that calculates F[][] raise to the power n and puts the
result in F[][]*/
static void power(int F[][], int n)
{
int i;
int M[][] = new int[][]{{1,1},{1,0}};
// n - 1 times multiply the matrix to {{1,0},{0,1}}
for (i = 2; i <= n; i++)
multiply(F, M);
}
This can be optimized to work in O(Logn) time complexity. We can do recursive multiplication to get power(M, n) in the previous method.
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
static void power(int F[][], int n)
{
if( n == 0 || n == 1)
return;
int M[][] = new int[][]{{1,1},{1,0}};
power(F, n/2);
multiply(F, F);
if (n%2 != 0)
multiply(F, M);
}
Method 3 (O(log n) Time)
Below is one more interesting recurrence formula that can be used to find nth Fibonacci Number in O(log n) time.
If n is even then k = n/2:
F(n) = [2*F(k-1) + F(k)]*F(k)
If n is odd then k = (n + 1)/2
F(n) = F(k)*F(k) + F(k-1)*F(k-1)
How does this formula work?
The formula can be derived from the above matrix equation.
fibonaccimatrix
Taking determinant on both sides, we get
(-1)n = Fn+1Fn-1 – Fn2
Moreover, since AnAm = An+m for any square matrix A, the following identities can be derived (they are obtained from two different coefficients of the matrix product)
FmFn + Fm-1Fn-1 = Fm+n-1
By putting n = n+1,
FmFn+1 + Fm-1Fn = Fm+n
Putting m = n
F2n-1 = Fn2 + Fn-12
F2n = (Fn-1 + Fn+1)Fn = (2Fn-1 + Fn)Fn (Source: Wiki)
To get the formula to be proved, we simply need to do the following
If n is even, we can put k = n/2
If n is odd, we can put k = (n+1)/2
public static int fib(int n)
{
if (n == 0)
return 0;
if (n == 1 || n == 2)
return (f[n] = 1);
// If fib(n) is already computed
if (f[n] != 0)
return f[n];
int k = (n & 1) == 1? (n + 1) / 2
: n / 2;
// Applyting above formula [See value
// n&1 is 1 if n is odd, else 0.
f[n] = (n & 1) == 1? (fib(k) * fib(k) +
fib(k - 1) * fib(k - 1))
: (2 * fib(k - 1) + fib(k))
* fib(k);
return f[n];
}
Method 4 - Using a formula
In this method, we directly implement the formula for the nth term in the Fibonacci series. Time O(1) Space O(1)
Fn = {[(√5 + 1)/2] ^ n} / √5
static int fib(int n) {
double phi = (1 + Math.sqrt(5)) / 2;
return (int) Math.round(Math.pow(phi, n)
/ Math.sqrt(5));
}
Reference: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html
Look here for implementation in Erlang which uses formula
. It shows nice linear resulting behavior because in O(M(n) log n) part M(n) is exponential for big numbers. It calculates fib of one million in 2s where result has 208988 digits. The trick is that you can compute exponentiation in O(log n) multiplications using (tail) recursive formula (tail means with O(1) space when used proper compiler or rewrite to cycle):
% compute X^N
power(X, N) when is_integer(N), N >= 0 ->
power(N, X, 1).
power(0, _, Acc) ->
Acc;
power(N, X, Acc) ->
if N rem 2 =:= 1 ->
power(N - 1, X, Acc * X);
true ->
power(N div 2, X * X, Acc)
end.
where X and Acc you substitute with matrices. X will be initiated with and Acc with identity I equals to .
One simple way is to calculate it iteratively instead of recursively. This will calculate F(n) in linear time.
def fib(n):
a,b = 0,1
for i in range(n):
a,b = a+b,a
return a
Hint: One way you achieve faster results is by using Binet's formula:
Here is a way of doing it in Python:
from decimal import *
def fib(n):
return int((Decimal(1.6180339)**Decimal(n)-Decimal(-0.6180339)**Decimal(n))/Decimal(2.236067977))
you can save your results and use them :
public static long[] fibs;
public long fib(int n) {
fibs = new long[n];
return internalFib(n);
}
public long internalFib(int n) {
if (n<=2) return 1;
fibs[n-1] = fibs[n-1]==0 ? internalFib(n-1) : fibs[n-1];
fibs[n-2] = fibs[n-2]==0 ? internalFib(n-2) : fibs[n-2];
return fibs[n-1]+fibs[n-2];
}
F(n) = (φ^n)/√5 and round to nearest integer, where φ is the golden ratio....
φ^n can be calculated in O(lg(n)) time hence F(n) can be calculated in O(lg(n)) time.
// D Programming Language
void vFibonacci ( const ulong X, const ulong Y, const int Limit ) {
// Equivalent : if ( Limit != 10 ). Former ( Limit ^ 0xA ) is More Efficient However.
if ( Limit ^ 0xA ) {
write ( Y, " " ) ;
vFibonacci ( Y, Y + X, Limit + 1 ) ;
} ;
} ;
// Call As
// By Default the Limit is 10 Numbers
vFibonacci ( 0, 1, 0 ) ;
EDIT: I actually think Hynek Vychodil's answer is superior to mine, but I'm leaving this here just in case someone is looking for an alternate method.
I think the other methods are all valid, but not optimal. Using Binet's formula should give you the right answer in principle, but rounding to the closest integer will give some problems for large values of n. The other solutions will unnecessarily recalculate the values upto n every time you call the function, and so the function is not optimized for repeated calling.
In my opinion the best thing to do is to define a global array and then to add new values to the array IF needed. In Python:
import numpy
fibo=numpy.array([1,1])
last_index=fibo.size
def fib(n):
global fibo,last_index
if (n>0):
if(n>last_index):
for i in range(last_index+1,n+1):
fibo=numpy.concatenate((fibo,numpy.array([fibo[i-2]+fibo[i-3]])))
last_index=fibo.size
return fibo[n-1]
else:
print "fib called for index less than 1"
quit()
Naturally, if you need to call fib for n>80 (approximately) then you will need to implement arbitrary precision integers, which is easy to do in python.
This will execute faster, O(n)
def fibo(n):
a, b = 0, 1
for i in range(n):
if i == 0:
print(i)
elif i == 1:
print(i)
else:
temp = a
a = b
b += temp
print(b)
n = int(input())
fibo(n)

Resources