Daily Dose of DSA - Day 21

Daily Dose of DSA - Day 21

Ninja's Training using RecursiveDP(Top-Bottom)(TC:O(3*4*n)&SC:O(4*n)+O(n)call stack)&Using Iterative DP(Bottom-Up)(TC:O(3*4*n)&SC:O(4*n) O(1)(sp.opt)

·

6 min read

Question Link: https://www.codingninjas.com/studio/problems/ninja-s-training_3621003?leftPanelTab=0

Using Recursive DP(Top-Bottom):

  1. The function rec is defined to find the maximum score up to a specific index given that the task at i+1 index was done last.

  2. The function uses a memoization technique with the help of the dp array. The dp array stores the maximum scores calculated for each index, allowing us to reuse the results and avoid redundant recursive calls.

  3. The base case of the recursion is when index is 0. In this case, the function calculates the maximum score for the first index by considering all possible tasks (0, 1, and 2) except the one done at the next index (last). The maximum score is stored in the dp array at the corresponding index and returned.

  4. If the maximum score for the current index has already been calculated and stored in the dp array, the function directly returns the stored value, eliminating the need for further recursive calls.

  5. Inside the function, a variable maxi is initialized to keep track of the maximum score obtained up to the current index.

  6. The function iterates over the three possible tasks (0, 1, and 2) excluding the task done at the index+1 position (last).

  7. For each task, it calculates the score by adding the points obtained for the task at the current index (points[index][i]) with the maximum score obtained recursively for the previous index (rec(index-1, i, points, dp)).

  8. The function updates maxi by taking the maximum value between maxi and the calculated score. This step ensures that maxi stores the maximum score obtained by considering different tasks at the current index.

  9. The function stores maxi in the dp array at the corresponding index (dp[index]) for future use.

  10. Finally, the function returns the maximum score obtained at the last index (dp[n-1]), where n is the total number of indices in the given input.


int rec(int index , int last, vector<vector<int>> &points,vector<int>&dp)
{

    if(index==0) //base case 
    {
        int maxi2 = 0;
        for(int i=0;i<=2;i++)
        {
            if(i!=last)
            maxi2 = max(maxi2,points[0][i]);
        }
       dp[index] =  maxi2;
       return dp[index];
    }

    if(dp[index]!=-1) return dp[index]; //To avoid redundancies

    int maxi = 0 ;
    for(int i=0;i<=2;i++)
    {
        if(i!=last)
        {
        int score = points[index][i] + rec(index-1,i,points,dp);
        maxi = max(maxi,score);
        }
    }
    dp[index]= maxi;
    return dp[index];
}

Using Iterative DP (Bottom-Up):

  1. The ninjaTraining function receives the number of rows n and the 2D vector points representing the points scored for different tasks at each index.

  2. It initializes a 2D dynamic programming array dp of size n by 4, where dp[i][j] represents the maximum score up to index i with the task at index i+1 done last.

  3. The initial values of the dp array are set based on the points scored in the first row of the points vector. For example, dp[0][0] is set to the maximum value between points[0][1] and points[0][2], dp[0][1] is set to the maximum value between points[0][0] and points[0][2], dp[0][2] is set to the maximum value between points[0][0] and points[0][1], and dp[0][3] is set to the maximum value among points[0][0], points[0][1], and points[0][2].

  4. The function iterates from index 1 to n-1, representing the remaining rows of the points vector.

  5. For each index and each possible last task, represented by the variable last (ranging from 0 to 3), the maximum score is calculated. The maximum score is determined by iterating over the three possible tasks (0, 1, and 2) and adding the points obtained for the task at the current index (points[index][i]) with the maximum score obtained previously for the task at index i (dp[index-1][i]). The maximum of these scores is stored in the maxi variable.

  6. The dp[index][last] value is updated with the maximum score obtained for the current last.

  7. After calculating the maximum scores for all possible last tasks at the current index, the function moves on to the next index.

  8. Finally, the function returns dp[n-1][3], which represents the maximum score considering any task done last at the last index.

#include<bits/stdc++.h>
using namespace std;
int ninjaTraining(int n, vector<vector<int>>&points)
{

   vector<vector<int>> dp(n,vector<int>(4,0));
   dp[0][0] = max(points[0][1],points[0][2]);
   dp[0][1] = max(points[0][0],points[0][2]);
   dp[0][2] = max(points[0][0],points[0][1]);
   dp[0][3] = max({points[0][0],points[0][1],points[0][2]});

   for(int index=1;index<n;index++)
   {
       for(int last=0;last<4;last++)
       {
           dp[index][last] = 0;
           int maxi = 0;
           for(int i=0;i<3;i++)
           {
               if(i!=last)
               {
                   int score = points[index][i] + dp[index-1][i];
                   maxi = max(maxi,score);
               }
           }
           dp[index][last] = maxi;
       }
   }

   return dp[n-1][3];

}

Using Sp.Optimization in Iterative DP:

  1. The ninjaTraining function receives the number of rows n and the 2D vector points representing the points scored for different tasks at each index.

  2. It initializes a vector dp of size 4, where dp[i] represents the maximum score considering the task done at index i+1 last.

  3. The initial values of the dp vector are set based on the points scored in the first row of the points vector. For example, dp[0] is set to the maximum value between points[0][1] and points[0][2], dp[1] is set to the maximum value between points[0][0] and points[0][2], dp[2] is set to the maximum value between points[0][0] and points[0][1], and dp[3] is set to the maximum value among points[0][0], points[0][1], and points[0][2].

  4. The function iterates from index 1 to n-1, representing the remaining rows of the points vector.

  5. For each index, a temporary vector temp is created to store the updated maximum scores.

  6. For each possible last task, represented by the variable last (ranging from 0 to 3), the maximum score is calculated. The maximum score is determined by iterating over the three possible tasks (0, 1, and 2) and adding the points obtained for the task at the current index (points[index][i]) with the maximum score obtained previously for the task at index i (dp[i]). The maximum of these scores is stored in the maxi variable.

  7. The value of temp[last] is updated with the maximum score obtained for the current last.

  8. After calculating the maximum scores for all possible last tasks at the current index, the dp vector is updated by assigning temp to it. This ensures that the maximum scores for the next iteration are calculated correctly based on the updated values.

  9. Finally, the function returns dp[3], which represents the maximum score considering any task done last at the last index.

#include <bits/stdc++.h>
using namespace std;

int ninjaTraining(int n, vector<vector<int>>& points)
{
    vector<int> dp(4, 0);
    dp[0] = max(points[0][1], points[0][2]);
    dp[1] = max(points[0][0], points[0][2]);
    dp[2] = max(points[0][0], points[0][1]);
    dp[3] = max({ points[0][0], points[0][1], points[0][2] });

    for (int index = 1; index < n; index++)
    {
        vector<int> temp(4, 0);
        for (int last = 0; last < 4; last++)
        {
            int maxi = 0;
            for (int i = 0; i < 3; i++)
            {
                if (i != last)
                {
                    int score = points[index][i] + dp[i];
                    maxi = max(maxi, score);
                }
            }
            temp[last] = maxi;
        }

        dp = temp;
    }

    return dp[3];
}