Leetcode 293. Flip Game & 294. Flip Game II
来源:互联网 发布:灵格斯翻译家 for mac 编辑:程序博客网 时间:2024/05/24 02:08
293. Flip Game
Total Accepted: 14847 Total Submissions: 28238 Difficulty: Easy- Contributors: Admin
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 compute all possible states of the string after one valid move.
For example, given s = "++++"
, after one move, it may become one of the following states:
[ "--++", "+--+", "++--"]
If there is no valid move, return an empty list []
.
思路:
从左到右,直接重置,加入res,复原。
public class Solution { public List<String> generatePossibleNextMoves(String s) { List<String> res = new ArrayList<>(); char[] ss = s.toCharArray(); for(int i = 0; i < ss.length - 1; i++){ if(ss[i] == '+' && ss[i + 1] == '+'){ ss[i] = '-'; ss[i + 1] = '-'; res.add(String.valueOf(ss)); ss[i + 1] = '+'; ss[i] = '+'; } } return res; }}
294. Flip Game II
Total Accepted: 15396 Total Submissions: 35004 Difficulty: Medium- Contributors: Admin
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.
For example, given s = "++++"
, return true. The starting player can guarantee a win by flipping the middle "++"
to become "+--+"
.
Follow up:
Derive your algorithm's runtime complexity.
思路:
创历史了,居然被backtracking折磨了3个多小时。一般DFS用于输出所有情况,然后如果是问能不能一般都用DFS+全局变量,DFS来更新全局变量。
这个题非常优秀,看似DFS,但根本不是dfs。因为问的是能不能保证第一个人赢,对于第一个人,只要他能有一个方法赢就行;而对于第二个人而言,必须第二个人所有方法都无法阻止第一个人赢。
这个题其实非常的巧妙,它是问你能不能,但是并不能用DFS加全局变量,而且DFS函数要区别对待。平时我们写树的递归,每个节点和每个节点没差别,然而这个题是问我们第一个人能不能赢,也就是说我们DFS结果返回的true和false要根据当前选手而定,而且是为第一个选手做出的返回值。
先上个非常容易理解的版本,来自这里:
如果能找到任何一种方式,使得之后第二个选手无法赢,那么表明第一个选手可以赢。
public class Solution { public boolean canWin(String s) { char[] arr = s.toCharArray(); for(int i = 1; i < s.length(); i++) { if(arr[i] == '+' && arr[i - 1] == '+') { arr[i] = '-'; arr[i - 1] = '-'; String next = String.valueOf(arr); if(!canWin(next)) { return true; } arr[i] = '+'; arr[i - 1] = '+'; } } return false; }}
一开始就用DFS,后来发现返回值应该根据不同player的人而异。具体思路应该如下:(此时函数其实是canPlayer1Win)
如果是第一个人的调用:只要找到一个情况保证第二个选手输就行,这时候 return true,否则loop结束返回false。
如果是第二个人的调用,对于自己的每一个可能的选择,都必须保证第一个选手能赢。
也就是说,第一个选手的round,自己可以做决定,选择能行的解;而别人(第二人)的round,必须让其所有选择都导致第一个人赢,否则无法保证第一个人必赢。
讨论区这里有个参考:
public class Solution { public boolean canWin(String s) { //remember bits flipped int[] visited = new int[s.length()]; //mark existing - to 1 for(int i=0;i<s.length();i++){ if(s.charAt(i)=='-'){ visited[i]=1; } } return canWinR(s,1,visited); } public boolean canWinR(String s, int step, int[] visited){ //first player's turn if(step%2==1){ for(int i=0;i<s.length()-1;i++) { //if already flipped, skip if(visited[i]==1||visited[i+1]==1) continue; //mark the two to be flipped visited[i]=1; visited[i+1]=1; //if this move can win, return; boolean r=canWinR(s,step+1,visited); visited[i]=0; visited[i+1]=0; if(r) return true; } return false; } else { //second player's turn. //all second player's moves should result in first player to win //otherwise, first player cannot be guaranteed to win for(int i=0;i<s.length()-1;i++) { if(visited[i]==1||visited[i+1]==1) continue; visited[i]=1; visited[i+1]=1; boolean r = canWinR(s,step+1,visited); visited[i]=0; visited[i+1]=0; //this move leads to first player to lose , return false; if(!r) return false; } return true; } }}
其实他上面的代码是冗余的,直接用char[]就可以了(也就是其代码中的int[] visited):
public class Solution { public boolean canWin(String s) { //remember bits flipped int[] visited = new int[s.length()]; //mark existing - to 1 for(int i=0;i<s.length();i++){ if(s.charAt(i)=='-'){ visited[i]=1; } } return canWinR(1,visited); } public boolean canWinR(int step, int[] visited){ //first player's turn if(step%2==1){ for(int i=0;i<visited.length-1;i++) { //if already flipped, skip if(visited[i]==1||visited[i+1]==1) continue; //mark the two to be flipped visited[i]=1; visited[i+1]=1; //if this move can win, return; boolean r=canWinR(step+1,visited); visited[i]=0; visited[i+1]=0; if(r) return true; } return false; } else { //second player's turn. //all second player's moves should result in first player to win //otherwise, first player cannot be guaranteed to win for(int i=0;i<visited.length-1;i++) { if(visited[i]==1||visited[i+1]==1) continue; visited[i]=1; visited[i+1]=1; boolean r = canWinR(step+1,visited); visited[i]=0; visited[i+1]=0; //this move leads to first player to lose , return false; if(!r) return false; } return true; } }}
博主本来被什么时候该返回什么搞的晕头转向,强行将逻辑改到一致:
public class Solution { public boolean canWin(String s) { //if(s == null || s.length() <= 1) return false; char[] ss = s.toCharArray(); return canWin(ss, 1); } public boolean canWin(char[] ss, int player){ if(player == 1){ for(int i = 0; i < ss.length - 1; i++){ if(ss[i] == '+' && ss[i + 1] == '+'){ ss[i] = '-'; ss[i + 1] = '-'; if(canWin(ss, 2)) return true; ss[i] = '+'; ss[i + 1] = '+'; } } return false; }else{ //second player's turn. //all second player's moves should result in first player to win //otherwise, first player cannot be guaranteed to win for(int i = 0; i < ss.length - 1; i++){ if(ss[i] == '+' && ss[i + 1] == '+'){ ss[i] = '-'; ss[i + 1] = '-'; if(!canWin(ss, 1)) return false; ss[i] = '+'; ss[i + 1] = '+'; } } return true; } }}
以上代码在"++++"会return false,很明显是true。楼主以为是逻辑又错了,于是改了一个多小时。一会return false,一会true;一会canWin return;一会!canWin return。
当然都失败了,直到注意到一个特殊的细节:原代码中是先保存的了结果,复原之后判断的。看了下自己的代码输出,果然是出在复原问题上。改为如下终于AC了。
逻辑是如上所说,canWin其实的意思是canPlayer1Win!!!应该是第一次见到变种dfs+backtracking的题目。那么之前标准版满足return就得修改,得改成先保存结果再return。要不然当就会变成这样的运行模式:
++++ 1选手开始
--++ 到0选手上, 0将最后俩++变成--,----到1,return false,1要输,返回0的调用,因为我们已经发现这种情况会使得1输,已经没有必要继续1的--++这个选择。
然而因为立即return了,----并没有复原成--++,这样到了主循环本来应该复原成++++,就办不到了。
public class Solution { public boolean canWin(String s) { //if(s == null || s.length() <= 1) return false; char[] ss = s.toCharArray(); return canWin(ss, 1); } public boolean canWin(char[] ss, int player){ if(player == 1){ for(int i = 0; i < ss.length - 1; i++){ if(ss[i] == '+' && ss[i + 1] == '+'){ ss[i] = '-'; ss[i + 1] = '-'; boolean res = canWin(ss, 2); ss[i] = '+'; ss[i + 1] = '+'; if(res) return true; } } return false; }else{ //2 player's turn. //all 2 player's moves should result in 1 player to win //otherwise, 1 player cannot be guaranteed to win for(int i = 0; i < ss.length - 1; i++){ if(ss[i] == '+' && ss[i + 1] == '+'){ ss[i] = '-'; ss[i + 1] = '-'; boolean res = !canWin(ss, 1); ss[i] = '+'; ss[i + 1] = '+'; if(res) return false; } } return true; } }}
- Leetcode 293. Flip Game & 294. Flip Game II
- LeetCode 294. Flip Game II
- *LeetCode-Flip Game II
- 294. Flip Game II
- LeetCode 293. Flip Game
- [leetcode] 294. Flip Game II 解题报告
- [Leetcode] 294. Flip Game II 解题报告
- Leetcode Everyday: 293. Flip Game
- LeetCode 294. Flip Game II(反转游戏II)
- [LeetCode294] Flip Game II
- [LeetCode294]Flip Game II
- [leetcode294]Flip Game II
- [LeetCode294] Flip Game II
- Flip Game II
- Flip Game II
- LeetCode 题解(277) :Flip Game II
- Leetcode 294. Flip Game II (回溯,记忆化)
- [LeetCode 293] Flip Game
- 用链表模拟栈(100)
- shell脚本练习
- 204. Count Primes
- ios绘图系列五:绘制渐变CGContextDrawLinearGradient, CGContextDrawRadialGradient, CAGradientLayer
- 职业连连看模型,助你找到理想职业
- Leetcode 293. Flip Game & 294. Flip Game II
- Linux的文件搜索
- ubuntu上初次使用bochs
- 玩转HTML5移动页面_非常实用的css\js\图片优化等工具
- SQL 数据库 学习 025 查询-08 模糊查询 --- 怎样编写模糊查询语句
- fixed income
- Java异常处理
- 说说最近的读书计划
- linux解决无法打开资源管理器