Last Updated: 7 Aug, 2022

Maximum Score of Stones

Moderate

Problem statement

You and your friend are playing a game. You are given ‘N’ stones. Each stone has a value associated with it. The value of each stone is given by a 0-indexed array ‘NUMS’ where ‘NUMS[ i ]’ denotes the value of the ‘i’th stone.

The game starts with you and your friend are standing on the ‘K’th stone. The game consists of two parts:

First part consists of you jumping forward and collecting the value of stones. From any ‘i’th stone you can jump to (‘i’ + 1)th stone or (‘i’ + 2)th stone and then collect the value of that stone. You can stop at any stone anytime. You can make 0 or more than 0 moves of this kind.

Second part consists of your friend jumping backward. The stone at which you stopped, your friend will start jumping backward from that stone and collect the value of the stones. From any ‘i’th stone your friend can jump to (‘i’ - 1)th stone or (‘i’ - 2)th stone and then collect the value of that stone. Your friend can make 0 or more than 0 moves of this kind.

The index value after the jump should be inside the boundary of 0 to ‘N’-1 inclusive.

The game ends when your friend reaches the ‘0’th stone. Find the maximum score you and your friend can collect.

Note: You don’t count the value of starting stone ‘K’ at which you are initially standing but if after some operation you again return to the ‘K’th stone then you add that value to your answer.

Example:
Input: ‘N’ = 4,  ‘NUMS’ = {2, 1, -2, 3}, ‘K’ = 1.

Output: 6.

You are standing on the stone with index 1. You can jump from stone with index 1 to stones with index 2 or 3. Jump to stone 3 and collect the value of stone 3, total score = 3.
Now you cannot make any forward jump, your friend starts his backward turn now, he can jump to stone 1 or stone 2. Jump to stone 1 and collect the value of stone 1, total score = 4.
Jump from stone 1 to stone 0 and collect the value of stone 0, total score = 6.
Hence, the maximum score that you and your friend can collect is 6.
Input Format :
The first line will contain the integer 'T', denoting the number of test cases.

The first line of each test case contains an integer ‘N’ and ‘K’ denoting the length of the array ‘NUMS an arbitrary integer. 

The second line of each test case contains ‘N’ space-separated integers.
Output format :
For each test case, you don’t need to print anything just return the maximum value you and your friend can collect.
Note :
You don't need to print anything. It has already been taken care of. Just implement the given function.
Constraints :
1 <= T <= 10
1 <= N <= 10^6 
-1000 <= NUMS[ i ] <= 1000
Sum of N Over all the Test cases <= 10^6

Time Limit: 1 sec

Approaches

01 Approach

In this approach, we will use recursion to solve the problem. If you are standing at any stone then you can either jump 1 or 2 steps forward or stop there and let your friend jump backward. We can recursively explore all the possible moves available to you and your friend and then finally calculate the maximum sum.


 

Let us define our recursive function as ‘F’, the parameters on which this function depends are (index of the stone, who is on that stone you or your friend). We can use a flag variable to determine who is on the stone. 0 means you are on the stone and 1 means your friend is on the stone. Now the recurrence relation can be given as:


 

If flag = 0 then

F(idx, flag) = maximum of 

‘NUMS[ idx ]’ + max( F(idx+1, 0), F(idx + 2, 0)) // i.e move forward.

and 

‘NUMS[ idx ]’ + max( F(idx-1, 1), F(idx -2, 1)) // i.e move backward.

else 

F(idx, flag) = ‘NUMS[ idx ]’ + max( F(idx-1, 1), F(idx -2, 1)) // i.e move backward

 


 

The steps are as follows:-

Function getMaxUtil( [ int ] nums, int idx, int flag):

  1. If the value of the variable 'IDX' is 0 then return 'NUMS[ idx ]'.
  2. If the value of 'IDX' is greater than or equal to 'N' then return -1e6.
  3. If the value of 'IDX' is less than 0 then return -1e6.
  4. If the value of 'FLAG' is 0:
    • Recursively call the 'getMaxUtil' function for jumps 1 and 2 forward and store the value returned by it in a variable named 'FORWARD'.
    • Recursively call the 'getMaxUtil' function for jumps 1 and 2 backward and store the value returned by it in a variable named 'BACKWARD'.
    • Return the maximum of 'FORWARD' and 'BACKWARD'.
  5. Else recursively call the 'getMaxUtil' function for jumps 1 and 2 backward and return the maximum value returned by it.


 

Function getMaxScore([ int ] nums, int k):

  1. Initialize a variable 'ANS' with value -1e8.
  2. If 'K' is equal to 0, then update the value of 'ANS' to 0 and return ‘ANS’.
  3. Start the game by moving forward and then going backward, recursively call the 'getMaxUtil' function for jumps 1 and 2 and store the maximum value returned by it in a variable named 'FORWARD'.
  4. Also, start the game by moving backward, recursively call 'getMaxUtil' function for jump 1 and 2, and store the maximum value returned by it in a variable named 'BACKWARD'.
  5. Store the maximum of forward and backward in a variable 'MAXVAL'.
  6. Change the value of 'ANS' to the maximum of 'ANS' and 'MAXVAL'.
  7. Return the value of the 'ANS' variable.

02 Approach

In this approach, the idea is to optimize the previous approach using memoization, if we observe carefully we are calculating the value of any ‘F’(idx, flag) more than once. If we can store the value of it once we have calculated it then every time this state of function will be called again then 


 

The steps are as follows:-

Function getMaxUtil( [ int ] nums, int idx, int flag, [ [ int ] ] dp):

  1. If the value of the variable 'IDX' is 0 then return 'NUMS[ idx ]'.
  2. If the value of 'IDX' is greater than or equal to 'N' then return -1e6.
  3. If the value of 'IDX' is less than 0 then return -1e6.
  4. If 'DP[ idx ][ flag ] != -1 then return its value.
  5. If the value of 'FLAG' is 0:
  • Recursively call the 'getMaxUtil' function for jumps 1 and 2 forward and store the value returned by it in a variable named 'FORWARD'.
  • Recursively call the 'getMaxUtil' function for jumps 1 and 2 backward and store the value returned by it in a variable named 'BACKWARD'.
  • Store the maximum of 'FORWARD' and 'BACKWARD' in 'DP[ idx ][ flag ] then return it.
  1. Else recursively call the 'getMaxUtil' function for jumps 1 and 2 backward and store the maximum value returned by it in a variable named 'DP[ idx ][ flag ]' and then return it.



 

Function getMaxScore([ int ] nums, int k):

  1. Initialize a 'DP' array of size 'N' x 2 with value -1.
  2. Initialize a variable 'ANS' with value -1e8.
  3. If 'K' is equal to 0, then update the value of 'ANS' to 0 and return ‘ANS’.
  4. Start the game by moving forward and then going backward, recursively call the 'getMaxUtil' function for jumps 1 and 2 and store the maximum value returned by it in a variable named 'FORWARD'.
  5. Also, start the game by moving backward, recursively call 'getMaxUtil' function for jump 1 and 2 and store the maximum value returned by it in a variable named 'BACKWARD'.
  6. Store the maximum of forward and backward in a variable 'MAXVAL'.
  7. Change the value of 'ANS' to the maximum of 'ANS' and 'MAXVAL'.
  8. Return the value of the 'ANS' variable.

03 Approach

In this approach, we can calculate the maximum score for each stone that we can collect while jumping forward. It can be easily found by the relation. ‘DP[ i ]’ = max( DP[ i - 1 ], DP[ i - 2 ] ) + ‘NUMS[ i ]’. We can use this to find the maximum score we can collect while jumping backward. For each ‘i’th stone, the maximum score can be obtained from 3 conditions:


 

i. If we are jumping from ( ‘i’ + 1 )th stone to ‘i’th stone, i.e, ‘DP[ i + 1 ] + ‘NUMS [ i ].

ii. Or if we are jumping from ( ‘i’ + 2 )th stone to ‘i’th stone, i.e, DP[ i + 2 ] + ‘NUMS[ i ]’.

iii. Or, the forward was stopped on the ‘i’th stone and the friend is just starting from that stone, i.e, DP [ i ].


 

The maximum of these three conditions gives us the maximum score we can get for the ‘i’th stone. 


 

The steps are as follows:-

Function getMaxScore([ int ] nums, int k):

  1. Initialize an array 'DP' of size 'N' + 1 with the value -1e9.
  2. Modify the value of 'DP' at 'K' to 0.
  3. Run a loop from 'i' = 'K' + 1.... 'N' - 1:
  • If the value of 'i' is greater than 1:
    • Then the value of 'DP' at 'i' is the maximum value of ( 'DP[ i - 1 ], DP[ i - 2 ]') + 'NUMS[ i ]'.
    • Else the value of 'DP[ i ]' = 'DP[ i - 1 ]' + 'NUMS [ i ]'.
  1. Run a loop from 'i' = 'N' - 2... 0:
  • Update the value of 'DP[ i ]' to the maximum of  'DP[ i ]' and ( max( 'DP[ i + 1]', 'DP[ i + 2]' ') + 'NUMS'[ i ]).