You are playing the following Flip Game with your friend: Given a string that contains only these two characters: + and -, you and your friend take turns to flip two consecutive "++" into "--". The game ends when a person can no longer make a move and therefore the other person will be the winner.
Write a function to determine if the starting player can guarantee a win.
Example:
Input:s = "++++"Output: true Explanation: The starting player can guarantee a win by flipping the middle"++"to become"+--+".
Follow up:
Derive your algorithm's runtime complexity.
這道題是之前那道 Flip Game 的拓展,讓我們判斷先手的玩家是否能贏,可以窮舉所有的情況,用回溯法來解題,思路跟上面那題類似,也是從第二個字母開始遍歷整個字符串,如果當前字母和之前那個字母都是+,那么遞歸調用將這兩個位置變為--的字符串,如果返回 false,說明當前玩家可以贏,結束循環返回 false。這里同時貼上熱心網友 iffalse 的解釋,這道題不是問 “1p是否會怎么選都會贏”,而是 “如果1p每次都選特別的兩個+,最終他會不會贏”。所以 canWin 這個函數的意思是 “在當前這種狀態下,至少有一種選法,能夠讓他贏”。而 (!canWin) 的意思就變成了 “在當前這種狀態下,無論怎么選,都不能贏”。所以 1p 要看的是,是否存在這樣一種情況,無論 2p 怎么選,都不會贏。所以只要有一個 (!canWin),1p 就可以確定他會贏。這道題從博弈論的角度會更好理解。每個 player 都想讓自己贏,所以每輪他們不會隨機選+。每一輪的 player 會選能夠讓對手輸的+。如果無論如何都選不到讓對手輸的+,那么只能是當前的 player 輸了,參見代碼如下:
解法一:
class Solution { public: bool canWin(string s) { for (int i = 1; i < s.size(); ++i) { if (s[i] == '+' && s[i - 1] == '+' && !canWin(s.substr(0, i - 1) + "--" + s.substr(i + 1))) { return true; } } return false; } };
第二種解法和第一種解法一樣,只是用 find 函數來查找 ++ 的位置,然后把位置賦值給i,然后還是遞歸調用 canWin 函數,參見代碼如下:
解法二:
class Solution { public: bool canWin(string s) { for (int i = -1; (i = s.find("++", i + 1)) >= 0;) { if (!canWin(s.substr(0, i) + "--" + s.substr(i + 2))) { return true; } } return false; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/294
類似題目:
Guess Number Higher or Lower II
參考資料:
https://leetcode.com/problems/flip-game-ii/
https://leetcode.com/problems/flip-game-ii/discuss/74033/4-line-Java-Solution
https://leetcode.com/problems/flip-game-ii/discuss/74010/Short-Java-and-Ruby
https://leetcode.com/problems/flip-game-ii/discuss/73962/Share-my-Java-backtracking-solution
