【2022/05/08-第292场单周赛】复盘

总结
Q4还是要想好再做好点,先dfs超时,然后两次WA没有注意错误用例,多WA了两次,以后在做周赛的时候也要兼顾少WA。
Q1.字符串中最大的 3 位相同数字
模拟。
class Solution {
public:
string largestGoodInteger(string s) {
string ret;
for(int i = 2; i < s.size(); ++i){
if(s[i] == s[i - 1] && s[i - 1] == s[i - 2]){
ret = max(ret, s.substr(i - 2, 3));
}
}
return ret;
}
};
Q2. 统计值等于子树平均值的节点数
递归模板题。
class Solution {
public:
int ret = 0;
int getSum(TreeNode* root, int &num){ // 返回以root为根结点的子树上所有结点值之和,num是该子树结点数
if(!root) return 0;
int ln = 0, rn = 0;
int ls = getSum(root->left, ln); // 分别得到左右子树结点值之和和结点数
int rs = getSum(root->right,rn);
num = ln + rn + 1;
int sum = ls + rs + root->val;
if((sum) / num == root->val) ++ret;
return sum;
}
int averageOfSubtree(TreeNode* root) {
int num;
getSum(root, num);
return ret;
}
};
Q3.统计打字方案数
分离子串后,对每个子串用动态规划求结果数,最后相乘。
class Solution {
public:
int h[10] = {0, 0, 3, 3, 3, 3, 3, 4, 3, 4};
const int M = 1000000007;
int helper(string temp){
int n = temp.size();
vector<int> f(n + 1, 0); // 用动态规划计算该子串有多少种可能的文字信息
f[0] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= h[temp[0] - '0'] && i - j >= 0; ++j){
f[i] = (f[i] + f[i - j]) % M;
}
}
return f[n];
}
int countTexts(string s) {
string temp;
long long ret = 1;
for(int i = 0; i < s.size(); ++i){ // 分离字符相同的子串
if(i == 0 || s[i] == s[i - 1]) temp += s[i];
else if(s[i] != s[i - 1]){
ret = (ret * helper(temp)) % M;
temp.clear();
temp += s[i];
}
}
ret = (ret * helper(temp)) % M; // 遍历完会剩下一段
return ret;
}
};
Q4.检查是否有合法括号字符串路径
一开始暴力dfs超时,然后用bfsWA了几发后过了。
class Solution {
public:
bool hasValidPath(vector<vector<char>>& grid) {
int m = grid.size(), n = grid[0].size();
if(grid[0][0] == ')' || m + n - 1 & 1 || grid[m - 1][n - 1] == '(') return false;
vector<vector<int>> inq(m, vector<int> (n, 0));
vector<vector<unordered_set<int>>> t(m, vector<unordered_set<int>> (n)); // set内的值表示到达该点时,路径上左括号数和右括号数之差,由于到每个点可能有多条路径,所以我们要用set来储存可能的多个值
t[0][0].insert(1);
queue<pair<int, int>> q;
q.push({0, 0});
inq[0][0] = 1;
while(!q.empty()){
auto k = q.front(); q.pop();
int x = k.first, y = k.second;
if(x == m - 1 && y == n - 1 && t[x][y].find(0) != t[x][y].end()) return true; // 到达右下点且有恰好左括号数等于右括号数的路径
if(x + 1 < m){
if(grid[x + 1][y] == '('){ // 下一结点为左括号,直接添加
for(auto i : t[x][y]) t[x + 1][y].insert(i + 1);
if(!inq[x + 1][y]){
q.push({x + 1, y});
inq[x + 1][y] = 1;
}
}
else{
bool flag = false; // 下一结点为右括号,只有当该结点有括号差值大于1的路径时,才可能到达下一结点
for(auto i : t[x][y]){
if(i >= 1) t[x + 1][y].insert(i - 1);
flag = true;
}
if(flag && !inq[x + 1][y]){
q.push({x + 1, y});
inq[x + 1][y] = 1;
}
}
}
if(y + 1 < n){
if(grid[x][y + 1] == '('){
for(auto i : t[x][y]) t[x][y + 1].insert(i + 1);
if(!inq[x][y + 1]){
q.push({x, y + 1});
inq[x][y + 1] = 1;
}
}
else{
bool flag = false;
for(auto i : t[x][y]){
if(i >= 1) t[x][y + 1].insert(i - 1);
flag = true;
}
if(flag && !inq[x][y + 1]){
q.push({x, y + 1});
inq[x][y + 1] = 1;
}
}
}
}
return false;
}
};
dfs剪枝
class Solution {
public:
int m, n;
bool dfs(int x, int y, int c, vector<vector<char>>& grid, vector<vector<vector<bool>>> &vis){
if (c > m - x + n - y - 1) return false;
if (x == m - 1 && y == n - 1) return c == 1;
if (vis[x][y][c]) return false;
vis[x][y][c] = true;
c += grid[x][y] == '(' ? 1 : -1;
return c >= 0 && (x < m - 1 && dfs(x + 1, y, c, grid, vis) || y < n - 1 && dfs(x, y + 1, c, grid, vis));
}
bool hasValidPath(vector<vector<char>>& grid) {
m = grid.size(), n = grid[0].size();
if(grid[0][0] == ')' || !((m + n) & 1) || grid[m - 1][n - 1] == '(') return false;
vector<vector<vector<bool>>> vis(m, vector<vector<bool>> (n, vector<bool> (m + n, false)));
return dfs(0, 0, 0, grid, vis);
}
};
dp+bitset优化
class Solution {
using B128 = bitset<128>;
public:
bool hasValidPath(vector<vector<char>>& grid) {
int m = grid.size(), n = grid[0].size();
if(grid[0][0] == ')' || grid[m - 1][n - 1] == '(' || !((m + n) & 1)) return false;
vector<B128> f(n, 0);
f[0] = 2;
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(grid[i][j] == '('){
if(i) f[j] <<= 1;
if(j) f[j] |= (f[j - 1] << 1);
}
else{
if(i) f[j] >>= 1;
if(j) f[j] |= (f[j - 1] >> 1);
}
}
}
return f[n - 1].test(0);
}
};
浙公网安备 33010602011771号