开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情
前言
小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标1900分,现在1806!!
力扣第 92 场双周赛-力扣
第 92 场双周赛 - 力扣(LeetCode)
前三题都不咋难,第四题没做出来,,一直超时,确实有点难。
周日打周赛的人都不多了,周六的双周赛更少了。
2484. 统计回文子序列数目
给你数字字符串 s ,请你返回 s 中长度为 5 的 回文子序列 数目。由于答案可能很大,请你将答案对 109 + 7 取余 后返回。
提示:
如果一个字符串从前往后和从后往前读相同,那么它是 回文字符串 。
子序列是一个字符串中删除若干个字符后,不改变字符顺序,剩余字符构成的字符串。
示例 1:
输入:s = "103301"
输出:2
解释:
总共有 6 长度为 5 的子序列:"10330" ,"10331" ,"10301" ,"10301" ,"13301" ,"03301" 。 它们中有两个(都是 "10301")是回文的。
示例 2:
- 输入: s = "9999900000"
- 输出: 2
- 解释: 仅有的两个回文子序列是 "99999" 和 "00000" 。
示例 3:
- 输入: s = "0000000"
- 输出: 21
- 解释: 所有 21 个长度为 5 的子序列都是 "00000" ,都是回文的。
提示:
1 <= s.length <= 104s只包含数字字符。
代码
很多题解都贴了这题,确实思路差不多。长度为3的回文做法,遍历中间的数,统计index坐标和右边相同字符的个数就可以了。
[杨小白]_leetcode_力扣_1930. 长度为 3 的不同回文子序列 - 掘金 (juejin.cn)
1930. 长度为 3 的不同回文子序列
那么本题长度为5的回文,做法相似。首先dp[i][j][k]表示,包括i之后的所有字符中,jk出现的次数。
从后向前遍历整个字符串,更新dp。
现在从前往后更新predp[j][k],表示index往前的字符中,出现jk的次数。
这样对于index,前面出现jk的次数 * 后面出现kj的次数,就是一个回文,启聪jk从00到99共100种,进行遍历即可。
空间复杂度是O(nmm) 时间复杂度是O(nmm),m为10,n为字符串长度
class Solution {
public int countPalindromes(String s) {
if(s.length() < 5) return 0;
int MOD = 1_000_000_007;
int[][][] dp = new int[s.length() + 2][10][10];
int[] num = new int[10];
for(int i = s.length() - 1; i >= 0; i--) {
int b = s.charAt(i) - '0';
for (int j = 0; j < 10; j++) {
for (int k = 0; k < 10; k++) {
dp[i][j][k] = dp[i + 1][j][k];
}
}
for(int j = 0; j < 10; j++) {
dp[i][b][j] = (dp[i + 1][b][j] + num[j]) % MOD;
}
num[b]++;
}
long res = 0;
long[][] predp = new long[10][10];
num = new int[10];
num[s.charAt(0) - '0']++;
num[s.charAt(1) - '0']++;
predp[s.charAt(0) - '0'][s.charAt(1) - '0']++;
for(int i = 2; i < s.length(); i++) {
for(int j = 0; j < 10; j++) {
for(int k = 0; k <10; k++) {
res = res + (predp[j][k] * dp[i +1][k][j]) % MOD;
res = res % MOD;
}
}
int b = s.charAt(i) - '0';
for(int j = 0; j < 10; j++){
predp[j][b] = (predp[j][b] + num[j]) % MOD;
}
num[b]++;
}
return (int)res;
}
}
3.结束
前三题太简单,第四题太难,真是无语,好歹手速快还是能涨个20大几分。