目录
一,3324. 出现在屏幕上的字符串序列
本题就是一道找规律的题,对于 target 字符串中第 i 个字符来说,先执行操作1,追加一个字符 'a',执行操作2,将字符 'a' 不断更改成字母表中的下一个字符,直至与 target[i] 相同。
代码如下:
class Solution {
public List<String> stringSequence(String target) {
List<String> ans = new ArrayList<>();
StringBuilder res = new StringBuilder();
for(int i=0; i<target.length(); i++){
res.append('a');
for(char c='a'; c<=target.charAt(i); c++){
res.setCharAt(i, c);
ans.add(res.toString());
}
}
return ans;
}
}
二,3325. 字符至少出现 K 次的子字符串 I
本题是一道简单的滑窗问题,有两种思路,一个是维护以 r 为右端点时有多少满足条件的子数组,另一个是维护以 l 为左端点时有多少满足条件的子数组。两种思路的代码差不多,代码如下:
维护右端点
class Solution {
public int numberOfSubstrings(String str, int k) {
int[] cnt = new int[26];
char[] s = str.toCharArray();
int ans = 0;
for(int l=0,r=0; r<s.length; r++){
cnt[s[r]-'a']++;
while(cnt[s[r]-'a'] >= k){
cnt[s[l]-'a']--;
l++;
}
ans += l;
}
return ans;
}
}
维护左端点
class Solution {
public int numberOfSubstrings(String str, int k) {
int[] cnt = new int[26];
char[] s = str.toCharArray();
int ans = 0, n = s.length;
for(int l=0,r=0; r<n; r++){
cnt[s[r]-'a']++;
while(cnt[s[r]-'a'] == k){
ans += n-r;
cnt[s[l]-'a']--;
l++;
}
}
return ans;
}
}
三,3326. 使数组非递减的最少除法操作次数
本题是一道贪心题,需要从右往左遍历,在满足非递减条件下,右边的数越大越好,如果 nums[i] <= nums[i+1],那么 nums[i] 不需要执行任何操作(更有可能满足非递减条件),反之,则必须除以它的最大真因数,如果 nums[i] 执行操作之后还是大于 nums[i+1],表示无法满足条件,直接返回-1。为什么不是从左往右?因为如果nums[i-1] <= nums[i] 无法判断nums[i]是否需要除以它的最大真因数。
还有一个问题是什么是一个数的最大真因数?简单来说就是除了它本身的最大公因数,那么 x / x的最大真因数 = x 除了 1 以外最小公因数,所以我们可以预处理所有数的最小公因数。
代码如下:
class Solution {
private static final int[] bool = new int[1000001];
static{
for(int i=2; i<1000001; i++){
if(bool[i]!=0) continue;
for(int j=2*i; j<1000001; j+=i){
if(bool[j] != 0) continue;
bool[j] = Math.min(i, j/i);
}
}
}
public int minOperations(int[] nums) {
int n = nums.length;
int ls = nums[n-1];
int ret = 0;
for(int i=n-2; i>=0; i--){
if(ls >= nums[i]){
ls = nums[i];
continue;
}
nums[i] = bool[nums[i]];
if(nums[i] == 0 || nums[i] > ls) return -1;
ls = nums[i];
ret++;
}
return ret;
}
}
四,3327. 判断 DFS 字符串是否是回文串
本题先使用dfs + 时间戳计算出dfsStr,以及对于每个节点能组成的字符串的长度,然后使用Manacher算法(算法讲解103【扩展】 Manacher算法、扩展KMP_哔哩哔哩_bilibili)计算特殊处理后dfsStr字符串中以每个字符为中点的回文串的长度。代码如下:
class Solution {
int cnt = 0, time = 0;
int[][] node;//记录dfs(i)组成的回文串的长度
char[] c;
String s;
public boolean[] findAnswer(int[] parent, String s) {
//p[i] -> i
int n = s.length();
this.s = s;
List<Integer>[] g = new ArrayList[n];
Arrays.setAll(g, e->new ArrayList<>());
for(int i=1; i<n; i++){
g[parent[i]].add(i);//i从小到大遍历,也就是说已经是升序排列
}
node = new int[n][2];
c = new char[n];
dfs(0, g);
//为了避免讨论该回文串长度的奇偶
char[] t = new char[n*2+3];
Arrays.fill(t, '#');
t[0] = '^';
for(int i=0; i<n; i++){
t[2*i+2] = c[i];
}
t[2*n+2] = '$';
//Manacher算法实现
int boxR = 0, boxM = 0;
int[] box = new int[t.length-2];
box[1] = 1;
for(int i=2; i<box.length; i++){
int len = 1;
if(i <= boxR) len = Math.min(box[2*boxM-i], boxR - i + 1);
while(t[i+len] == t[i-len]){
boxR = i + len;
boxM = i;
len++;
}
box[i] = len;
}
boolean[] ans = new boolean[n];
for(int i=0; i<n; i++){
int l = node[i][0], r = node[i][1];
if(box[l+r+2] > r-l+1) ans[i] = true;
}
return ans;
}
void dfs(int x, List<Integer>[] g){
node[x][0] = time;
for(int y : g[x]){
dfs(y, g);
}
c[time] = s.charAt(x);
node[x][1] = time++;
}
}