【292】 Nim Game (2019年3月12日,E)html
有一堆石头,游戏规则是每次能够从里面拿1-3颗石头,拿到最后的石头的人赢。你和你的对手都 optimal 的玩这个游戏,问先手(也就是你)能不能赢得这个比赛。api
题解:我原本写的是 dfs + memo,可是没想到这个题数字太大了。容易爆栈。后来经过看discuss和观察,发现,这个题,只要不是 4 的倍数,先手都能赢得比赛。less
1 class Solution { 2 public: 3 bool canWinNim(int n) { 4 return n % 4 != 0; 5 } 6 };
【375】Guess Number Higher or Lower II (2019年3月12日,google tag,H)ide
给了 1 ~ N 这 N 个数字猜数,我来猜,若是我猜错了,我猜这个数为x,那么我就付 x 元。返回在能保证我赢的状况下,返回我必须付多少钱。优化
https://www.1point3acres.com/bbs/thread-197552-1-1.htmlui
【464】Can I Win (2019年2月20日,谷歌tag,M)google
给了一个1-100的游戏,游戏规则是,两个选手,player1每次从1-100中抽取一个数字,player2每次也从1-100中抽取一个数字,不能重复抽取相同的数字。直到某个player抽取到一个数,全部轮次中每一个player抽取的数字加和大于等于target(target是提早给定的)。问player1能不能赢这个游戏。spa
本题的题目意思是把100换成一个变量叫作 maxChoosableInteger。问 player1 能不能赢这个游戏。code
题解:这是一棵博弈树的问题。解空间以下图:htm
裸的dfs搜索方法以下:对于当前的局面,咱们尝试用一个没有用过的数做为当前的解,而后dfs到下一个局面。
若是下个局面返回了false,就是对手不能赢,那我确定很是高兴的立刻返回了true,由于这个局面我能赢。(注意返回的时候要把当前局面用过的数字清空。回溯。不能忘。)
可是若是下个局面返回了true,我就会认真反思本身,而后后悔当前局面的走法(是的,就是这么的无赖)去换一种新的走法。
那么对于当前局面的前一个局面来讲,对手看到我返回了true,那他也能够反悔啊,他心里os:老子也不这么走了,我也要换一个走法。因而他就继续遍历他解空间的下一个解,直到他在当前空间找到了一个解,这个解能让他在当前空间赢,或者他找遍了全部的可能解,都赢不了,他只好认输,"我在当前空间赢不了,我返回false"。
1 class Solution { 2 public: 3 bool canIWin(int maxChoosableInteger, int desiredTotal) { 4 if (desiredTotal <= 0) {return true;} 5 if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) {return false;} 6 string used(maxChoosableInteger, '0'); 7 int sum = 0; 8 return canIWin(maxChoosableInteger, desiredTotal, sum, used); 9 } 10 bool canIWin(int maxChoosableInteger, int desiredTotal, int sum, string& used) { 11 if (sum >= desiredTotal) {return false;} 12 for (int i = 1; i <= maxChoosableInteger; ++i) { 13 if (used[i-1] == '1') { continue; } //若是当前的数用过了,那么就换下一个能用的数 14 used[i-1] = '1'; 15 if (canIWin(maxChoosableInteger, desiredTotal, sum + i, used) == false) { 16 //到这里须要回溯。若是下一个局面为false的话,就说明当前局面能赢。 17 //可是你想象一下若是你是一个玩家,当对手告诉你这个局面对手能赢的时候,你会怎么作, 18 //确定是返回到一个有一个解-对手不能赢的层次,而后去dfs那个解空间。 19 used[i-1] = '0'; 20 return true; 21 } 22 used[i-1] = '0'; 23 } 24 return false; 25 } 26 };
再加上能够记忆化或者状态压缩的技巧。用个memo。
1 class Solution { 2 public: 3 bool canIWin(int maxChoosableInteger, int desiredTotal) { 4 if (desiredTotal <= 0) {return true;} 5 if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) {return false;} 6 string used(maxChoosableInteger, '0'); 7 int sum = 0; 8 return canIWin(maxChoosableInteger, desiredTotal, sum, used, 0); 9 } 10 unordered_map<string, bool> memo; 11 bool canIWin(int maxChoosableInteger, int desiredTotal, int sum, string& used, int player) { 12 if (sum >= desiredTotal) {return false;} 13 if (memo.find(used) != memo.end()) {return memo[used];} 14 string key = used; 15 memo[key] = false; 16 for (int i = 1; i <= maxChoosableInteger; ++i) { 17 if (used[i-1] == '1') { continue; } 18 used[i-1] = '1'; 19 if (canIWin(maxChoosableInteger, desiredTotal, sum + i, used, 1 - player) == false) { 20 memo[key] = true; 21 used[i-1] = '0'; 22 return true; 23 } 24 used[i-1] = '0'; 25 } 26 return false; 27 } 28 };
【486】Predict the Winner
【843】Guess the Word (2019年3月12日,google tag)
给了一个 wordlist 猜单词,给了一个 api ,叫作 int guess(string word),返回咱们的 target 单词有多少个位置和 word match。
For each test case, you have 10 guesses to guess the word. At the end of any number of calls, if you have made 10 or less calls to master.guess
and at least one of these guesses was the secret, you pass the testcase.
题解:这道题不难,其实主要是这种交互式的问题在leetcode上第一次出现。
intuition: 咱们先随机选一个单词 word,而后利用返回值 x,若是 target 和 word match 的有 x,那么咱们只须要选择在 list 中和 word match x个位置的单词,这个做为咱们下次选择的集合。
这么作能 ac。
可是能够优化:若是说咱们随机选一个单词,可是若是 返回值 x == 0 的话,那么其实剩下的解可能不少。咱们试图找一个单词,与这个单词有 0 个match 的单词解的集合最小就好了。
1 /** 2 * // This is the Master's API interface. 3 * // You should not implement it, or speculate about its implementation 4 * class Master { 5 * public: 6 * int guess(string word); 7 * }; 8 */ 9 class Solution { 10 public: 11 void findSecretWord(vector<string>& wordlist, Master& master) { 12 for (int t = 0; t < 10; ++t) { 13 int n = wordlist.size(); 14 unordered_map<string, int> mp; 15 for (int i = 0; i < n; ++i) { 16 for (int j = i + 1; j < n; ++j) { 17 if (calMatch(wordlist[i], wordlist[j]) == 0) { 18 mp[wordlist[i]]++; 19 } 20 } 21 } 22 pair<string, int> minmax = make_pair(wordlist[0], 1000); 23 for (auto& p : mp) { 24 if (p.second < minmax.second) {minmax = p;} 25 } 26 int x = master.guess(minmax.first); 27 if (x == 6) {return;} 28 vector<string> list2; 29 for (auto& w : wordlist) { 30 if (calMatch(w, minmax.first) == x) { 31 list2.push_back(w); 32 } 33 } 34 wordlist = list2; 35 } 36 } 37 int calMatch(string& s, string& t) { 38 int match = 0; 39 for (int i = 0; i < s.size(); ++i) { 40 if (s[i] == t[i]) {match++;} 41 } 42 return match; 43 } 44 };
【913】Cat and Mouse