Back tracking
递归 / 回溯算法
MinMax
博弈 / 游戏问题中的方法。
294. Flip Game II
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.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/flip-game-ii
这道题动态规划无法直接解。需要用到递归方法。当前的情况下,如果存在一种翻转方法,使得翻转后的先手无法获胜,则当前情况一定可以获胜;否则如果所有翻转方法,都使得翻转后的先手一定能获胜,则当前情况无法获胜。
进一步,可以用记忆方法进行加速,用一个哈序表存储某一种字符串下的结果。
class Solution {
public:
unordered_map<string, bool> mem;
bool canWin(string s) {
if (mem.find(s) != mem.end()) return mem[s];
for (int i = 0; i < (int)s.size() - 1; ++i) {
if (s[i] == '+' && s[i + 1] == '+') {
s[i] = '-';
s[i + 1] = '-';
if (!canWin(s)) {
s[i] = '+';
s[i + 1] = '+';
mem[s] = true;
return true;
}
s[i] = '+';
s[i + 1] = '+';
}
}
mem[s] = false;
return false;
}
};
679. 24 Game
You have 4 cards each containing a number from 1 to 9. You need to judge whether they could operated through *, /, +, -, (, ) to get the value of 24.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/24-game
这道题其实就是枚举,因为一共也就几千种情况。关键是如何枚举,实际上只需要枚举所有可能的数字排列,有24种情况。然后对于每种数字排列,枚举不同的计算顺序。对于每两个数的计算,有4种符号。而枚举的过程都是通过递归来完成。
class Solution {
public:
bool judgePoint24(vector<int>& nums) {
vector<double> ns(0);
for (int i = 0; i < nums.size(); ++i) ns.push_back(nums[i]);
vector<vector<double>> pers = gen_pers(ns, 0);
for (int i = 0; i < pers.size(); ++i) {
vector<double> res = judge(pers[i]);
for (double r : res) {
if (abs(r - 24.0) < 0.000001) return true;
}
}
return false;
}
vector<double> judge(vector<double>& nums) {
vector<double> res(0);
if (nums.size() == 1) return nums;
for (int i = 1; i < nums.size(); ++i) {
vector<double> per1(0), per2(0), res1(0), res2(0);
for (int j = 0; j < i; ++j) per1.push_back(nums[j]);
for (int j = i; j < nums.size(); ++j) per2.push_back(nums[j]);
res1 = judge(per1);
res2 = judge(per2);
for (double a : res1) for (double b : res2) {
res.push_back(a + b);
res.push_back(a - b);
res.push_back(a * b);
res.push_back(a / b);
}
}
return res;
}
vector<vector<double>> gen_pers(vector<double>& nums, int n) {
vector<vector<double>> pers(0);
if (n == nums.size() - 1) pers.push_back(nums);
for (int i = n; i < nums.size(); ++i) {
swap(nums[i], nums[n]);
vector<vector<double>> tmp = gen_pers(nums, n + 1);
for (auto t : tmp) pers.push_back(t);
swap(nums[i], nums[n]);
}
return pers;
}
};
剑指 Offer 38. 字符串的排列
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
这一题挺简单的,不过一开始写的比较复杂。注意用交换元素的方法即可,即固定第i位元素,然后往后遍历,同时注意排除重复元素,只需要保证每一位出现的字符不重复即可,用一个unorderset来标记。
class Solution {
public:
vector<string> ans;
vector<string> permutation(string s) {
per(s, 0);
return ans;
}
void per(string s, int pos) {
unordered_set<char> first;
if (pos == s.size()) {
ans.push_back(s);
return;
}
for (int i = pos; i < s.size(); ++i) {
if (first.find(s[i]) != first.end()) continue;
else first.insert(s[i]);
string t(s);
swap(t[pos], t[i]);
per(t, pos + 1);
}
}
};