文章目录
- 学习地址
- [5491. 矩阵对角线元素的和](https://leetcode-cn.com/problems/matrix-diagonal-sum/)(遍历)
- [5492. 分割字符串的方案数](https://leetcode-cn.com/problems/number-of-ways-to-split-a-string/)(计数)
- [5493. 删除最短的子数组使剩余数组有序](https://leetcode-cn.com/problems/shortest-subarray-to-be-removed-to-make-array-sorted/)(双指针)
- [5494. 统计所有可行路径](https://leetcode-cn.com/problems/count-all-possible-routes/)(记忆化搜索 ,动态规划)
学习地址
5491. 矩阵对角线元素的和(遍历)
遍历。对角线特征:
i = j || i == n - j - 1
class Solution {
public:
int diagonalSum(vector<vector<int>>& mat) {
int n = mat.size();
int res = 0;
for(int i=0;i<n;i++)
{
res += mat[i][i];
if(i != n - i - 1) res += mat[i][n - i - 1];
}
return res;
}
};
5492. 分割字符串的方案数(计数)
计数。计数问题一般跟哈希表有关。分3种情况:
- 全0
- "1"的个数不能整除3
- 乘法原理
class Solution {
public:
int mod = 1e9 + 7;
int numWays(string s) {
int n = s.size();
int ones = 0;
unordered_map<int,int> pos; // 记录位置,分类3有用
for(int i=0;i<n;i++)
{
if(s[i] == '1'){
ones ++;
pos[ones] = i;
}
}
// 分类1
if(ones == 0) return (long long)(n - 1) * (n - 2) / 2 % mod;
// 分类2
if(ones % 3 != 0) return 0;
// 分类3
int m = ones / 3;
return (long long)(pos[m + 1] - pos[m]) * (pos[m * 2 + 1] - pos[m * 2]) % mod;
}
};
5493. 删除最短的子数组使剩余数组有序(双指针)
假设一下,满足题目要求的必然是
[prefix] [- -][suffix]
,满足prefix, suffix是递增的,且prefix <= suffix。
这里就可以用双指针算法,边移动边求答案。
class Solution {
public:
int findLengthOfShortestSubarray(vector<int>& arr) {
if(is_sorted(arr.begin(),arr.end())) return 0; // is_sorted 学来的
int n = arr.size();
int l =0 ,r = n- 1;
while(arr[l] <= arr[l + 1]) l ++ ;
while(arr[r - 1] <= arr[r]) r -- ;
int ans = min(n - 1 - l,r);
// [prefix][- -][suffix]
for(int i = 0 , j = r;i <= l && j < n; i ++)
{
while(j < n && arr[j] < arr[i]) j ++;
if(j < n) ans = min(ans, j - i - 1);
}
return ans;
}
};
5494. 统计所有可行路径(记忆化搜索 ,动态规划)
状态表示 :
dp[pos][rest]
: 【表示当前在城市pos,剩余油量为rest】这个状态下,到达终点finish的方案数
答案就是 dp[start][fuel]
状态转移:dp[pos][rest] = sum(dp[i][rest - | locations[pos] - locations[i] | ) ( i ! = pos)
如果pos == finish, 对dp[pos][rest] 额外增加1
class Solution {
public:
int mod = 1e9 + 7;
vector<vector<int>> dp;
int dfs(vector<int>& locations, int pos, int finish, int rest)
{
// 记忆化搜索的精髓
if(dp[pos][rest] != -1){
return dp[pos][rest];
}
dp[pos][rest] = 0;
int n = locations.size();
for(int i = 0;i < n ;i ++ ){
if(pos != i){
int cost = abs(locations[pos] - locations[i]);
if(cost <= rest){
dp[pos][rest] += dfs(locations,i,finish,rest - cost);
dp[pos][rest] %= mod;
}
}
}
if(pos == finish){
dp[pos][rest] += 1;
dp[pos][rest] %= mod;
}
return dp[pos][rest];
}
int countRoutes(vector<int>& locations, int start, int finish, int fuel) {
//dp[postion][rest]: 【表示当前在城市position,剩余油量是rest】这个状态下,到达终点finishi的方案数
// 答案就是dp[start][fuel]
// 枚举下一站去哪个城市? 第 i 个城市 dp[position][rest] =
// sum(dp[i][rest - |locations[position] - locations[i]|])
// 如果position == finish 对 dp[position][rest] 额外增加1
dp.assign(locations.size(),vector<int>(fuel + 1, - 1));
return dfs(locations,start,finish,fuel);
}
};
解法2:另一种状态表示
class Solution {
public:
long long dp[101][201];
// 换另一种状态表示
// dp[i][k] : 剩余油量为k到达 位置i 的方案数
// 答案 dp[finish][0 .. k];
// 状态转移 dp[i][k + abs(locations[i] - locations[j])] += dp[i][k]
int mod = 1e9 + 7;
int countRoutes(vector<int>& locations, int start, int finish, int fuel) {
memset(dp,0,sizeof dp);
int n = locations.size();
// 初始化
dp[start][0] = 1;
for(int k = 0; k <= fuel; k ++ )
for(int i = 0; i < n ; i++ )
for(int j = 0; j < n ;j ++)
{
if(j == i) continue; // 同一个城市
if(k + abs(locations[i] - locations[j]) > fuel) continue;
dp[j][k + abs(locations[i] - locations[j])] += dp[i][k];
dp[j][k + abs(locations[i] - locations[j])] %= mod;
}
long long ans = 0;
for(int k = 0;k <= fuel ;k ++ ){
ans = (ans + dp[finish][k]) % mod;
}
return ans;
}
};