灵神题单-动态规划(更新中)
·
1.1 爬楼梯
由前几个状态转移到现在这个状态
class Solution {
public:
int climbStairs(int n) {
int f0 = 0, f1 = 1;
for (int i = 0; i < n; i++) {
int new_f = f0 + f1;
f0 = f1, f1 = new_f;
}
return f1;
}
};
class Solution {// 1、记忆化搜索
public:
int minCostClimbingStairs(vector<int>& nums) {
int n = nums.size();
vector<int> memo(n + 1, -1);
function<int(int)> dp = [&](int i) -> int {// dp(i)的含义是,到达第 i 级台阶需要的最小费用
if (i <= 1)// 注意这里填1,因为再往下,nums 数组就越界了
return 0;
if (memo[i] != -1)
return memo[i];
memo[i] = min(dp(i - 1) + nums[i - 1], dp(i - 2) + nums[i - 2]);
return memo[i];
};
return dp(n);
}
};
class Solution {// 2、递推
public:
int minCostClimbingStairs(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n + 1, 0);
for (int i = 2; i <= n; i++)
dp[i] = min(dp[i - 1] + nums[i - 1], dp[i - 2] + nums[i - 2]);
return dp[n];
}
};
class Solution {// 3、递推(空间优化版)
public:
int minCostClimbingStairs(vector<int>& nums) {
int n = nums.size();
int f0 = 0, f1 = 0;
for (int i = 1; i < n; i++) {
int new_f = min(f0 + nums[i - 1], f1 + nums[i]);
f0 = f1;
f1 = new_f;
}
return f1;
}
};
本质上是爬楼梯,每一个状态根据数组长度个状态转移而来
class Solution { // 1、记忆化搜索
public:
int combinationSum4(vector<int>& nums, int target) {
int n = nums.size();
vector<int> memo(target + 1, -1);
function<int(int)> dp = [&](int i) -> int {
if (i == 0)
return 1;
if (memo[i] != -1) // 如果设置为0,会导致无限循环
return memo[i];
memo[i] = 0;
for (int x : nums)
if (x <= i)
memo[i] += dp(i - x);
return memo[i];
};
return dp(target);
}
};
class Solution {// 2、递推
public:
int combinationSum4(vector<int>& nums, int target) {
int n = nums.size();
vector<unsigned> dp(target + 1, 0);
dp[0] = 1;
for (int i = 1; i <= target; i++) {
for (int x : nums)
if (x <= i)
dp[i] += dp[i - x];
}
return dp[target];
}
};
2466. 统计构造好字符串的方案数 - 力扣(LeetCode)
class Solution {
public:
int countGoodStrings(int low, int high, int zero, int one) {
vector<int> dp(high + 1, 0);
dp[0] = 1;
const int MOD = 1000000007;
for (int i = 0; i <= high; i++) {
if (i >= zero)
dp[i] = dp[i - zero];
if (i >= one)
dp[i] = (dp[i] + dp[i - one]) % MOD;
}
int ans = 0;
for (int i = low; i <= high; i++) {
ans += dp[i];
ans %= MOD;
}
return ans;
}
};
class Solution {
public:
int countTexts(string pressedKeys) {
vector<pair<char, int>> nums;
char c = pressedKeys[0];
int cnt = 0;
for (int i = 0; i < pressedKeys.size(); i++) {
if (c == pressedKeys[i])
++cnt;
else {
nums.push_back({c, cnt});
cnt = 1;
c = pressedKeys[i];
}
}
nums.push_back({c, cnt});
const unsigned long long MOD = 1000000007;
vector<unsigned long long> dp1(100001), dp2(100001);
dp1[1] = 1, dp1[2] = 2, dp1[3] = 4, dp1[4] = 7;
dp2[1] = 1, dp2[2] = 2, dp2[3] = 4, dp2[4] = 8;
for (size_t i = 5; i <= 100000; i++) {
dp1[i] = (dp1[i - 1] + dp1[i - 2] + dp1[i - 3]) % MOD;
dp2[i] = (dp2[i - 1] + dp2[i - 2] + dp2[i - 3] + dp2[i - 4]) % MOD;
}
unsigned long long ans = 1;
for (auto it : nums) {
if (it.first != '7' && it.first != '9')
ans *= dp1[it.second];
else
ans *= dp2[it.second];
ans %= MOD;
}
return ans;
}
};
1.2 打家劫舍
选了这一个,就不能选下一个(下几个)
class Solution {// 1、记忆化搜索
public:
int rob(vector<int>& nums) {
int n = nums.size();
vector<int> memo(n, -1);// 辅助数组,实现记忆化搜索
function<int(int)> dp = [&](int i) -> int {
if (i < 0)
return 0;
if (memo[i] != -1)
return memo[i];
memo[i] = max(dp(i - 1), dp(i - 2) + nums[i]);
return memo[i];
};
return dp(n - 1);
}
};
class Solution {// 2、递推
public:
int rob(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 0);
dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < n; i++)
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);// 核心代码部分,递推和记忆化搜索是非常相似的
return dp[n - 1];
}
};
class Solution {// 3、递推(空间优化版)
public:
int rob(vector<int>& nums) {
int f0 = 0, f1 = 0;
for (int x : nums) {
int new_f = max(f0 + x, f1);
f0 = f1;// 注意这两句的顺序不能反了!
f1 = new_f;// 注意这两句的顺序不能反了!
}
return f1;
}
};
这个解法模板可以解决这个问题,但是sum元素上溢的话,就得增大数据类型,或者使用pair
class Solution {
public:
int deleteAndEarn(vector<int>& nums) {
int maxval = ranges::max(nums);
vector<int> sum(maxval + 1, 0);
for (int val : nums)
sum[val] += val;
int f0 = 0, f1 = 0;
for (int i = 0; i < maxval + 1; i++) {
int new_f = max(f0 + sum[i], f1);
f0 = f1, f1 = new_f;
}
return f1;
}
};
2320. 统计放置房子的方式数 - 力扣(LeetCode)
class Solution {
public:
int countHousePlacements(int n) {
if (n == 1)
return 4;
vector<long long> dp(n+1, 0);
dp[0] = 1, dp[1] = 2;
for (int i = 2; i <= n; ++i)
dp[i] = (dp[i - 1] + dp[i - 2])%1000000007;
return (dp[n] * dp[n]) % 1000000007;
}
};
连起来的时候,分类讨论即可
class Solution {
public:
int rob(vector<int>& nums) {
int f0 = 0, f1 = 0, n = nums.size();
if (n < 2)
return nums[0];
for (int i = 0; i < n - 1; i++) {
int new_f = max(f0 + nums[i], f1);
f0 = f1, f1 = new_f;
}
int ans = f1;
f0 = 0, f1 = 0;
for (int i = 1; i < n; i++) {
int new_f = max(f0 + nums[i], f1);
f0 = f1, f1 = new_f;
}
return max(ans, f1);
}
};
这题和740类似,但是数据上溢了,只能用pair表示元素
class Solution {
public:
long long maximumTotalDamage(vector<int>& power) {
// 爆内存了
// int maxval = ranges::max(power);
// vector<int> sum(maxval + 1);
// for (int val : power)
// sum[val] += val;
// vector<int> dp(maxval + 1, 0);
// int f0 = 0, f1 = 0, f2 = 0;
// for (int i = 0; i <= maxval; i++) {
// int new_f = max(max(f0 + sum[i], f1), f2);
// f0 = f1;
// f1 = f2;
// f2 = new_f;
// }
// return f2;
unordered_map<int, int> map;
for (auto x : power)
++map[x];
vector<pair<int, int>> nums(map.begin(), map.end());
ranges::sort(nums);
int n = nums.size();
vector<long long> dp(n + 1);
for (int i = 0, j = 0; i < n; i++) {
auto& [x, c] = nums[i];
while (nums[j].first < x - 2)
++j;
dp[i + 1] = max(dp[i], dp[j] + (long long)x * c);
}
return dp[n];
}
};
1.3 最大子数组和
遍历数组,记录 max_f 和 min_f
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int ans = INT_MIN, sum = 0;// 由于题目要求子数组非空,因此ans初始化为INT_MIN,如果没有这个要求,应该初始化为0
for (int x : nums) {
sum = max(sum, 0) + x;
ans = max(ans, sum);
}
return ans;
}
};
2606. 找到最大开销的子字符串 - 力扣(LeetCode)
class Solution {
public:
int maximumCostSubstring(string s, string chars, vector<int>& vals) {
unordered_map<char, int> map;
for (int i = 0; i < chars.size(); i++)
map.emplace(chars[i], vals[i]);
for (int i = 0; i < 26; i++)
if (map.find('a' + i) == map.end())
map.emplace('a' + i, i + 1);
int ans = 0, sum = 0, n = s.size();
for (int left = 0, right = 0; right < n; right++) {
while (sum < 0) {
sum -= map[s[left]];
++left;
}
sum += map[s[right]];
ans = max(ans, sum);
}
return ans;
}
};
1749. 任意子数组和的绝对值的最大值 - 力扣(LeetCode)
class Solution {
public:
int maxAbsoluteSum(vector<int>& nums) {
int ans = 0, f_max = 0, f_min = 0;
for (int x : nums) {
f_max = max(f_max, 0) + x;
f_min = min(f_min, 0) + x;
ans = max(ans, max(f_max, -f_min));
}
return ans;
}
};
1191. K 次串联后最大子数组之和 - 力扣(LeetCode)
分 k==1 和 k>1 讨论。
class Solution {
public:
int kConcatenationMaxSum(vector<int>& nums, int k) {
int mod = 1e9 + 7;
if (k == 1) {
int ans = 0, f_max = 0;
for (int x : nums) {
f_max = max(f_max, 0) + x;
ans = max(ans, f_max);
}
return ans;
} else {
int ans = 0, f_max = 0, n = nums.size(), sum = 0;
for (int j = 0; j < 2; j++) {
for (int i = 0; i < n; i++) {
sum += nums[i];
f_max = max(f_max, 0) + nums[i];
ans = max(ans, f_max);
}
}
sum /= 2;
if (sum > 0)
ans = (ans + (long long)(k - 2) * sum) % mod;
return ans % mod;
}
}
};
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int sum = 0, max_f = 0, min_f = 0, max_s = INT_MIN, min_s = 0; // 由于要求不为空,因此max_s不能初始化为0,而min_s可以初始化为0
for (int x : nums) {
sum += x;
max_f = max(max_f, 0) + x;
min_f = min(min_f, 0) + x;
max_s = max(max_s, max_f);
min_s = min(min_s, min_f);
}
return min_s == sum ? max_s : max(max_s, sum - min_s);
}
};
2321. 拼接数组的最大分数 - 力扣(LeetCode)
class Solution {
public:
int slove(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), res = 0, max_f = 0, sum = 0;
for (int i = 0; i < n; i++) {
sum += nums2[i];
max_f = max(max_f, 0) + nums1[i] - nums2[i];
res = max(res, max_f);
}
return sum + res;
}
int maximumsSplicedArray(vector<int>& nums1, vector<int>& nums2) {
return max(slove(nums1, nums2), slove(nums2, nums1));
}
};
也可以记录 max_f, min_f
class Solution {// 正向乘一遍,再逆向乘一遍
public:
int maxProduct(vector<int>& nums) {
int product = 1, n = nums.size(), ans = INT_MIN;
for (int i = 0; i < n; i++) {
product *= nums[i];
ans = max(ans, product);
if (product == 0)
product = 1;
}
product = 1;
for (int i = n - 1; i >= 0; i--) {
product *= nums[i];
ans = max(ans, product);
if (product == 0)
product = 1;
}
return ans;
}
};
2.1 网格图DP
LCR 166. 珠宝的最高价值 - 力扣(LeetCode)
class Solution {
public:
int jewelleryValue(vector<vector<int>>& dp) {
int n = dp.size(), m = dp[0].size();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (i == 0 && j > 0)
dp[i][j] += dp[i][j - 1];
if (i > 0 && j == 0)
dp[i][j] += dp[i - 1][j];
if (i > 0 && j > 0)
dp[i][j] += max(dp[i][j - 1], dp[i - 1][j]);
}
}
return dp[n - 1][m - 1];
}
};
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> matrix(m + 1, vector<int>(n + 1, 0));
matrix[0][1] = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
matrix[i + 1][j + 1] = matrix[i + 1][j] + matrix[i][j + 1];
}
}
return matrix[m][n];
}
};
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if (obstacleGrid[0][0] == 1)
return 0;
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
int dp[m][n];
dp[0][0] = 1;
for (int i = 1; i < m; i++) {
if (obstacleGrid[i][0] == 1)
dp[i][0] = 0;
else
dp[i][0] = dp[i - 1][0];
}
for (int i = 1; i < n; i++) {
if (obstacleGrid[0][i] == 1)
dp[0][i] = 0;
else
dp[0][i] = dp[0][i - 1];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1)
dp[i][j] = 0;
else
dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
}
}
return dp[m - 1][n - 1];
}
};
class Solution {
public:
int minPathSum(vector<vector<int>>& nums) {
int m = nums.size(), n = nums[0].size();
for (int i = 1; i < n; i++)
nums[0][i] += nums[0][i - 1];
for (int i = 1; i < m; i++)
nums[i][0] += nums[i - 1][0];
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++)
nums[i][j] += min(nums[i - 1][j], nums[i][j - 1]);
}
return nums[m - 1][n - 1];
}
};
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
for (int i = 0; i < triangle.size() - 1; i++) {
triangle[i + 1][0] += triangle[i][0];
for (int j = 1; j < triangle[i].size(); j++)
triangle[i + 1][j] += min(triangle[i][j - 1], triangle[i][j]);
triangle[i + 1][triangle[i].size()] += triangle[i][triangle[i].size() - 1];
}
int ans = 10010;
for (int i = 0; i < triangle[triangle.size() - 1].size(); i++)
ans = min(ans, triangle[triangle.size() - 1][i]);
return ans;
}
};
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
int n = matrix.size();
if (n == 1)
return matrix[0][0];
for (int i = 1; i < n; i++) {
matrix[i][0] += min(matrix[i - 1][0], matrix[i - 1][1]);
for (int j = 1; j < n - 1; ++j)
matrix[i][j] +=
min(min(matrix[i - 1][j - 1], matrix[i - 1][j]),
min(matrix[i - 1][j], matrix[i - 1][j + 1]));
matrix[i][n - 1] += min(matrix[i - 1][n - 2], matrix[i - 1][n - 1]);
}
return *min_element(matrix[n - 1].begin(), matrix[n - 1].end());
}
};
1289. 下降路径最小和 II - 力扣(LeetCode)
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& grid) {
int n = grid.size();
for (int i = 1; i < n; i++) {
for (int j = 0; j < n; j++) {
int temp = 20000;
for (int k = 0; k < n; k++)
if (k != j)
temp = min(temp, grid[i - 1][k]);
grid[i][j] += temp;
}
}
return *min_element(grid[n - 1].begin(), grid[n - 1].end());
}
};
2684. 矩阵中移动的最大次数 - 力扣(LeetCode)
class Solution {
public:
int maxMoves(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
int ans = 0;
function<void(int, int)> dfs = [&](int i, int j) {
ans = max(ans, j);
if (ans == n - 1)
return;
for (int x = max(0, i - 1); x < min(m, i + 2); x++) {// 注意这里防止下标出界的处理,可以学习
if (grid[i][j] < grid[x][j + 1])
dfs(x, j + 1);
}
grid[i][j] = 0;
};
for (int i = 0; i < m; i++)
dfs(i, 0);
return ans;
}
};
2.2 网格图DP进阶
class Solution {// 仍然是记录max与min
public:
int maxProductPath(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
int mod = 1e9 + 7;
vector<vector<long long>> max_matrix(m, vector<long long>(n));
vector<vector<long long>> min_matrix(m, vector<long long>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
max_matrix[i][j] = grid[i][j];
min_matrix[i][j] = grid[i][j];
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i == 0 && j > 0)
min_matrix[i][j] = max_matrix[i][j] =
max_matrix[i][j - 1] * grid[i][j];
if (i > 0 && j == 0)
min_matrix[i][j] = max_matrix[i][j] =
max_matrix[i - 1][j] * grid[i][j];
if (i > 0 && j > 0) {
if (grid[i][j] >= 0) {
max_matrix[i][j] =
max(max_matrix[i - 1][j], max_matrix[i][j - 1]) *
grid[i][j];
min_matrix[i][j] =
min(min_matrix[i - 1][j], min_matrix[i][j - 1]) *
grid[i][j];
} else {
max_matrix[i][j] =
min(min_matrix[i - 1][j], min_matrix[i][j - 1]) *
grid[i][j];
min_matrix[i][j] =
max(max_matrix[i - 1][j], max_matrix[i][j - 1]) *
grid[i][j];
}
}
}
}
return max_matrix[m - 1][n - 1] < 0 ? -1
: max_matrix[m - 1][n - 1] % mod;
}
};
1301. 最大得分的路径数目 - 力扣(LeetCode)
class Solution {
public:
int mod = 1e9 + 7;
int n;
void update(vector<vector<pair<int, int>>>& dp, int x, int y, int u,
int v) {
if (u >= n || v >= n || dp[u][v].first == -1)
return;
if (dp[u][v].first > dp[x][y].first)
dp[x][y] = dp[u][v];// 更大,则更新
else if (dp[u][v].first == dp[x][y].first) {
dp[x][y].second += dp[u][v].second;// 加法原理
dp[x][y].second %= mod;
}
}
vector<int> pathsWithMaxScore(vector<string>& board) {
this->n = board.size();
vector<vector<pair<int, int>>> dp(n, vector<pair<int, int>>(n, {-1, 0}));
dp[n - 1][n - 1] = {0, 1};
for (int i = n - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
if (!(i == n - 1 && j == n - 1) && board[i][j] != 'X') {
update(dp, i, j, i + 1, j);
update(dp, i, j, i, j + 1);
update(dp, i, j, i + 1, j + 1);
if (dp[i][j].first != -1)
dp[i][j].first += (board[i][j] == 'E' ? 0 : board[i][j] - '0');
}
}
}
return dp[0][0].first == -1 ? vector<int>{0, 0} : vector<int>{dp[0][0].first, dp[0][0].second};
}
};
2435. 矩阵中和能被 K 整除的路径 - 力扣(LeetCode)
class Solution {// 将dp元素初始化为一个vector,存放各个结果的方案数
public:
int mod = 1e9 + 7;
int numberOfPaths(vector<vector<int>>& grid, int k) {
int m = grid.size(), n = grid[0].size();
vector<vector<vector<int>>> dp( m + 1, vector<vector<int>>(n + 1, vector<int>(k, 0)));
dp[0][1][0] = 1;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
for (int v = 0; v < k; v++)
dp[i + 1][j + 1][(v + grid[i][j]) % k] =
(dp[i + 1][j][v] + dp[i][j + 1][v]) % mod;
return dp[m][n][0] % mod;
}
};
// 正向思考的话,考虑dp[i][j]为到达(i,j)时的血量,这样的话存在一个问题:有两条路线,一条使你到达(i,j)时血量更高,但历史最低血量更低,也就是出发时所需的初始血量更高,另一条则相反。选择哪一条路线会因为后面的值而难以确定。
// 逆向思考的话,dp[i][j]为到达右下角所需要的最低血量,这样就避免了正向思考时的问题
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int m = dungeon.size(), n = dungeon[0].size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
dp[m - 1][n] = 1;
for (int i = m - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
int minn = min(dp[i + 1][j], dp[i][j + 1]);
dp[i][j] = max(minn - dungeon[i][j], 1);
}
}
return dp[0][0];
}
};
329. 矩阵中的最长递增路径 - 力扣(LeetCode)
class Solution {
public:
int ans = 0;
int m, n;
int dfs(vector<vector<int>>& matrix, vector<vector<int>>& dp, vector<vector<bool>>& vis, int i, int j) {
if(vis[i][j])
return dp[i][j];
vis[i][j] = true;
int up = (i == 0 || matrix[i - 1][j] <= matrix[i][j]) ? 0 : dfs(matrix, dp, vis, i - 1, j);
int down = (i == m - 1 || matrix[i + 1][j] <= matrix[i][j]) ? 0 : dfs(matrix, dp, vis, i + 1, j);
int left = (j == 0 || matrix[i][j - 1] <= matrix[i][j]) ? 0 : dfs(matrix, dp, vis, i, j - 1);
int right = (j == n - 1 || matrix[i][j + 1] <= matrix[i][j]) ? 0 : dfs(matrix, dp, vis, i, j + 1);
dp[i][j] += max(max(up, down), max(left, right));
ans = max(ans, dp[i][j]);
return dp[i][j];
}
int longestIncreasingPath(vector<vector<int>>& matrix) {
this->m = matrix.size(), this->n = matrix[0].size();
vector<vector<int>> dp(m, vector<int>(n, 1));
vector<vector<bool>> vis(m, vector<bool>(n, false));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (vis[i][j])
continue;
dfs(matrix, dp, vis, i, j);
}
}
return ans;
}
};
2328. 网格图中递增路径的数目 - 力扣(LeetCode)
class Solution {
public:
int ans = 0, mod = 1e9 + 7;
int m, n;
vector<vector<int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int dfs(vector<vector<int>>& grid, vector<vector<int>>& dp, vector<vector<bool>>& vis, int i, int j) {
if (vis[i][j])// 检查是否已经计算过
return dp[i][j];
vis[i][j] = true;// 置为已计算过
for (int k = 0; k < 4; k++) {// 向四个方向DFS
int x = i + dir[k][0], y = j + dir[k][1];
if (x >= 0 && x < m && y >= 0 && y < n && grid[i][j] < grid[x][y])
dp[i][j] += dfs(grid, dp, vis, x, y);
}
dp[i][j] %= mod;
ans += dp[i][j];// 累加到ans中
ans %= mod;
return dp[i][j];
}
int countPaths(vector<vector<int>>& grid) {
this->m = grid.size(), this->n = grid[0].size();
vector<vector<int>> dp(m, vector<int>(n, 1));
vector<vector<bool>> vis(m, vector<bool>(n, false));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (vis[i][j])
continue;
dfs(grid, dp, vis, i, j);
}
}
return ans;
}
};
2267. 检查是否有合法括号字符串路径 - 力扣(LeetCode)
// 设计一个变量c为进入格子之前,左括号减去右括号的数量
class Solution {
public:
bool hasValidPath(vector<vector<char>>& grid) {
int m = grid.size(), n = grid[0].size();
if ((m + n) % 2 == 0 || grid[0][0] == ')' || grid[m - 1][n - 1] == '(')// 如果长度为奇数,或者左上角不是'(',右下角不是')'
return false;
bool vis[m][n][(m + n + 1) / 2];// 标记数组
memset(vis, false, sizeof(vis));
function<bool(int, int, int)> dfs = [&](int x, int y, int c) -> bool {
if (c > m - x + n - y - 1)// 如果此时序列中'('太多,就算剩下的都是')'也无法全部匹配
return false;
if (x == m - 1 && y == n - 1)// 已到达右下角,由于lambda函数外面已经排除了右下角不是')'这种情况,所以这里只需要判断c == 1
return c == 1;
if (vis[x][y][c])// 如果访问过了,说明上次访问没有成功跳出,那么这个格子是不会成功的
return false;
vis[x][y][c] = true;// 标记已经访问过
c += grid[x][y] == '(' ? 1 : -1;// 更新c
return c >= 0 && (x < m - 1 && dfs(x + 1, y, c) || y < n - 1 && dfs(x, y + 1, c));//
};
return dfs(0, 0, 0);
}
};
更多推荐
所有评论(0)