-
[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 - 플레이어가 첫 돌 더미를 선택한다면,