ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LeetCode] 877. Stone Game
    알고리즘 문제 풀이 2021. 8. 6. 15:12

    문제 출처: https://leetcode.com/problems/stone-game/

     

    문제

    알렉스와 리는 돌 더미로 게임을 한다. 한 줄에 짝수개의 돌 더미가 배열되어 있고, 각 더미 piles[i]는 양의 정수 개의 돌이 있다.

     

    게임의 목적은 마지막에 가장 많은 돌을 갖는 것이다. 돌의 전체 개수는 홀수개라서 동점은 있을 수 없다.

     

    알렉스와 리는 자기 차례에만 플레이를 하며, 알렉스의 차례로 게임이 시작된다. 각 차례에 플레이어는 줄의 시작 또는 끝에서 전체 돌 더미를 가져온다. 더 이상 남은 더미가 없을 때까지 지속되며, 가장 많은 돌을 가진 사람이 승자가 된다.

     

    알렉스와 리는 최적의 플레이를 수행한다고 가정하고, 알렉스가 게임에서 이길수 있다면 True를 반환하라.

     

    예제

    Input: piles = [5,3,4,5]
    Output: true
    
    Explanation: 
    Alex starts first, and can only take the first 5 or the last 5.
    Say he takes the first 5, so that the row becomes [3, 4, 5].
    If Lee takes 3, then the board is [4, 5], and Alex takes 5 to win with 10 points.
    If Lee takes the last 5, then the board is [3, 4], and Alex takes 4 to win with 9 points.
    This demonstrated that taking the first 5 was a winning move for Alex, so we return true.

     

    풀이

    게임 플레이 규칙에 따라, 한 플레이어는 자신의 차례에 두가지 선택 사항이 존재한다. 만약 dp[i][j]가 piles의 i ~ j 에서 얻을 수 있는 최고의 점수를 저장하고 있는 배열이라 가정한다면, 다음과 같이 선택에 따라 얻을 수 있는 점수를 예측할 수 있다.

    • 플레이어가 첫 돌 더미를 선택한다면,
      • takeStart = sum - dp[i+1][j]
      • sum = i ~ j 범위의 돌 더미(piles)의 합
    • 플레이어가 마지막 돌 더미를 선택한다면,
      • takeEnd = sum - dp[i][j-1]
      • sum = i ~ j 범위의 돌 더미(piles)의 합
    • 최종적으로 두 선택 중에서 더 큰 점수를 얻을 수 있는 선택을 하면 된다.

     

    이러한 관계를 코드로 작성하면 다음과 같다.

    const N = piles.length;
    const dp = new Array(N).fill(0).map(val => new Array(N).fill(0));
    
    var play = function(piles, i, j) {
      if (i == j) {
      	return piles[i];
      }
    
      if (dp[i][j]) { return dp[i][j]; }
    
      let sum = 0;
      for (let s = i; s <= j; s++) { sum += piles[s]; }
    
      const takeLeft = sum - (dp[i+1][j] ? dp[i+1][j] : play(piles, i+1, j));
      const takeRight = sum - (dp[i][j-1] ? dp[i][j-1] : play(piles, i, j-1));
    
      dp[i][j] = Math.max(takeLeft, takeRight);
    
      return dp[i][j];
    }

    이러한 play 함수를 piles의 전체 범위에 대해서 수행하게 되면, dp[0][N-1]에는 게임 시작 플레이어가 얻을 수 있는 최고의 점수가 기록된다.

     

    이 플레이어가 이겼는지 확인하기 위해서 돌의 총 개수 중 절반 이상을 해당 플레이어가 얻게 되는지 확인하면 된다.

    const totalStone = piles.reduce((a, b) => a + b);
    
    let reuslt = dp[0][N-1] > totalSocre/2;

    최종 코드는 아래와 같다.

    var stoneGame = function(piles) {
        const N = piles.length;
        const dp = new Array(N).fill(0).map(val => new Array(N).fill(0));
        
        var play = function(piles, i, j) {
            if (i == j) {
                return piles[i];
            }
            
            if (dp[i][j]) { return dp[i][j]; }
            
            let sum = 0;
            for (let s = i; s <= j; s++) { sum += piles[s]; }
            
            const takeLeft = sum - (dp[i+1][j] ? dp[i+1][j] : play(piles, i+1, j));
            const takeRight = sum - (dp[i][j-1] ? dp[i][j-1] : play(piles, i, j-1));
            
            dp[i][j] = Math.max(takeLeft, takeRight);
            
            return dp[i][j];
        }
        
        const totalStone = piles.reduce((a, b) => a + b);
        
        play(piles, 0, N-1);
        
        return dp[0][N-1] > (totalStone/2);
    };

     

    Github: 877.js

     

    GitHub - opwe37/Algorithm-Study

    Contribute to opwe37/Algorithm-Study development by creating an account on GitHub.

    github.com

     

    '알고리즘 문제 풀이' 카테고리의 다른 글

    [LeetCode] 415. Add Strings  (0) 2021.08.10
    [LeetCode] 786. K-th Smallest Prime Fraction  (0) 2021.08.09
    [LeetCode] 113. Path Sum II  (0) 2021.08.05
    [LeetCode] 90. Subsets Ⅱ  (0) 2021.08.04
    [LeetCode] 827. Making A Large Island  (0) 2021.08.02

    댓글

Designed by Tistory.