July 28, 2023
   
   
    
    
    
    
     Edit me
    
   #. Problem & What to Remember
Go to the problem on leetcode
1. My approach
Bruteforce for all the possible cases would take O(2^n). However, it says each player would choose optimally. Assuming, each player would try all the possible answers and will choose it for the maximum score.
Each player has 2 different choices.
- get it from the front,
- get it from the back.
And each player has to see which one has a better possibility. So this has to be done by recursive. Top-bottom fashion.
Check the code for more explanation.
function PredictTheWinner(nums: number[]): boolean {
    const n = nums.length;
    function maxDiff(left: number, right: number): number {
        //At this point, just return the last possible number.
        if (left === right) return nums[left];
        /*
        ** scoreByLeft: the possible differences in scores when choosing it from the front.
        ** 'maxDiff(left+1, right)' will calculate the best possible score for the opponent.
        ** It will recursively come out with the possible maximum score differences.
        ** scoreByRight will function the same way but when choosing from behind.
        */
        const scoreByLeft = nums[left] - maxDiff(left + 1, right);
        const scoreByRight = nums[right] - maxDiff(left, right - 1);
        return Math.max(scoreByLeft, scoreByRight);
    }
    return maxDiff(0, n - 1) >= 0;
};
| Time (O(2^n)) | Space O(1) | 
|---|---|
| 232 ms | 43 MB | 
2. DP
Since the recursive would continuously have it do the same calculation, we can think about storing those in a nested array.
function PredictTheWinner(nums: number[]): boolean {
    const n = nums.length;
    const dp:number[][] = Array.from({length: n}, () => []);
    function maxDiff(left: number, right: number): number {
        if (left === right) return nums[left];
        if(!dp[left+1][right]) dp[left+1][right] = maxDiff(left + 1, right);
        if(!dp[left][right-1]) dp[left][right-1] = maxDiff(left, right - 1);
        const scoreByLeft = nums[left] - dp[left+1][right];
        const scoreByRight = nums[right] - dp[left][right-1];
        
        return Math.max(scoreByLeft, scoreByRight);
    }
    return maxDiff(0, n - 1) >= 0;
};
OR
function PredictTheWinner(nums: number[]): boolean {
    const n = nums.length;
    const dp:number[][] = Array.from({length: n}, () => []);
    function maxDiff(left: number, right: number): number {
        if (left === right) return nums[left];
        const scoreByLeft = nums[left] - (dp[left+1][right] || maxDiff(left + 1, right));
        const scoreByRight = nums[right] - (dp[left][right-1] || maxDiff(left, right - 1));
        dp[left][right] = Math.max(scoreByLeft, scoreByRight);
        return dp[left][right];
    }
    return maxDiff(0, n - 1) >= 0;
};
Time complexity would be the time of filling n*n array:
| Time (O(n^2)) | Space O(1) | 
|---|---|
| 54 ms | 43 MB | 
3. Epilogue
What I’ve learned from this exercise:
- DP is such a headache…
- Be used to do top-down approach