
2026-01-10:变为活跃状态的最小时间。用go语言,给定一个长度为 n 的字符串 s 和一个包含 0 到 n-1 的排列 order。按 order 中指定的次序,从时间 t=0 起每一时刻将 s 中对应位置的字符改为 ''(例如在时刻 t 时会把下标为 order[t] 的字符替换为 '',所以经过时刻 t 已替换了索引 order[0] 到 order[t] 共 t+1 个位置)。
把任意连续的一段字符视为一个子串;如果某个子串中至少含有一个 '*',就把它称为“有效子串”。当字符串中有效子串的数量不小于 k 时,称该字符串处于“活跃”状态。
要求找出使 s 首次达到活跃状态的最早时刻 t(按上述时刻计数)。如果经过所有替换也无法让有效子串数达到 k,则返回 -1。
1 <= n == s.length <= 100000。
order.length == n。
0 <= order[i] <= n - 1。
s 由小写英文字母组成。
order 是从 0 到 n - 1 的整数排列。
1 <= k <= 1000000000。
输入: s = "cat", order = [0,2,1], k = 6。
输出: 2。
t | order[t] | 修改后的 s | 有效子字符串 | 计数 | 激活状态 (计数 >= k) |
|---|---|---|---|---|---|
0 | 0 | "*at" | "*", "*a", "*at" | 3 | 否 |
1 | 2 | "a" | ""(第0位), "a", "a", "a", ""(第2位) | 5 | 否 |
2 | 1 | "***" | 所有子字符串(均包含 '*') | 6 | 是 |
字符串 s 在 t = 2 时变为激活状态。因此,答案是 2。
题目来自力扣3639。
s 所有可能的连续子串总数。对于一个长度为 n 的字符串,子串总数为 n * (n + 1) / 2。如果这个总数小于目标 k,那么即使将所有字符都改为 '*'(这意味着所有子串都变成有效子串),有效子串的数量也无法达到 k,因此直接返回 -1。'*')以及计算由此带来的有效子串数量变化,代码使用数组模拟了一个双向链表。这个链表代表了字符串中字符的原始顺序。prev 数组:prev[i] 存储下标为 i 的字符的前一个字符的下标。对于首字符(i=0),其 prev[0] 设为 -1。next 数组:next[i] 存储下标为 i 的字符的后一个字符的下标。对于尾字符(i=n-1),其 next[n-1] 设为 n。order。初始时,假设所有字符都已被替换为 '*',此时有效子串数等于总子串数 cnt。t = n-1)开始,向更早的时刻倒推。t 发生的替换操作。也就是说,我们将当时被替换为 '*' 的字符(其下标为 i = order[t])恢复为原始字符。在链表的语境下,这相当于将之前“删除”的节点重新插入,但在此逆向过程中,我们实际是进行“删除”操作。i)被恢复(即逆向操作中,它从 '*' 变回原字符)时,关键是要计算因为这个字符不再是 '*' 而导致减少的有效子串数量。i 被恢复后,它可能会将其左右两段由 '*' 组成的连续区域分割开。此时,我们需要计算以字符 i 为中心,且包含 i 的连续子串有多少个变成了无效子串(因为这些子串现在不再包含任何 '*')。i 在链表中的前一个节点 l(即左边最近的 '*' 或边界)和后一个节点 r(即右边最近的 '*' 或边界)。那么,所有左端点位于 (l, i] 且右端点位于 [i, r) 的连续子串,在字符 i 恢复后都将变为无效。这样的子串数量为 (i - l) * (r - i)。cnt 中减去这个数量。cnt 后,检查 cnt 是否小于 k。cnt 变得小于 k,说明在正向时间轴上,刚刚恢复的这个字符被替换为 '*' 的时刻(即当前的 t),是使有效子串数首次达到或超过 k 的时刻。因为在这个时刻之后(正向时间上),有效子串数才足以使字符串进入活跃状态。因此,函数返回当前的 t。t=0),cnt 仍然大于等于 k,则说明在初始时刻(t=0)字符串就已经是活跃状态,根据逻辑应返回 0(代码中需注意边界处理)。O(n)。算法主要操作包括初始化双向链表(O(n))和一次对 order 数组的逆向遍历(O(n))。在逆向遍历的每个步骤中,通过预处理的链表结构,计算子串数量变化和更新链表都是 O(1) 操作。O(n)。主要的额外空间消耗在于用于模拟双向链表的两个数组 prev 和 next,它们的长度均为 n 或 n+1。这个解法的巧妙之处在于其逆向思维和利用双向链表进行高效区间维护。通过从全 '*' 状态倒推,并计算每次“恢复”一个字符所影响的子串范围,避免了在正向模拟时难以高效计算有效子串数量变化的难题。链表结构使得在“恢复”字符时,能够快速确定其左右边界,从而在常数时间内完成对有效子串数量的更新。
.
package main
import (
"fmt"
)
func minTime(s string, order []int, k int)int {
n := len(s)
cnt := n * (n + 1) / 2
if cnt < k { // 全改成星号也无法满足要求
return-1
}
// 数组模拟双向链表
prev := make([]int, n+1)
next := make([]int, n)
for i := range n {
prev[i] = i - 1
next[i] = i + 1
}
for t := n - 1; ; t-- {
i := order[t]
l, r := prev[i], next[i]
cnt -= (i - l) * (r - i)
if cnt < k {
return t
}
// 删除链表中的 i
if l >= 0 {
next[l] = r
}
prev[r] = l
}
}
func main() {
s := "cat"
order := []int{0, 2, 1}
k := 6
result := minTime(s, order, k)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def min_time(s: str, order: list[int], k: int) -> int:
n = len(s)
cnt = n * (n + 1) // 2 # 初始所有子串数量
if cnt < k: # 全改成星号也无法满足要求
return-1
# 模拟双向链表
prev = list(range(-1, n - 1)) # prev[i] = i-1
nxt = list(range(1, n + 1)) # nxt[i] = i+1
# 从最后时刻开始向前遍历
for t in range(n - 1, -1, -1):
i = order[t]
l = prev[i]
r = nxt[i]
# 删除位置 i 后,减少的子串数量
cnt -= (i - l) * (r - i)
if cnt < k:
return t
# 从链表中删除 i
if l >= 0:
nxt[l] = r
if r < n:
prev[r] = l
return0 # 如果一开始就满足条件
# 测试示例
if __name__ == "__main__":
s = "cat"
order = [0, 2, 1]
k = 6
result = min_time(s, order, k)
print(result) 
.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int minTime(string s, vector<int>& order, int k) {
int n = s.length();
long long cnt = (long long)n * (n + 1) / 2; // 初始所有子串数量
if (cnt < k) { // 全改成星号也无法满足要求
return-1;
}
// 模拟双向链表
vector<int> prev(n + 1);
vector<int> next(n);
for (int i = 0; i < n; i++) {
prev[i] = i - 1;
next[i] = i + 1;
}
// 从最后时刻开始向前遍历
for (int t = n - 1; t >= 0; t--) {
int i = order[t];
int l = prev[i];
int r = next[i];
// 删除位置 i 后,减少的子串数量
cnt -= (long long)(i - l) * (r - i);
if (cnt < k) {
return t;
}
// 从链表中删除 i
if (l >= 0) {
next[l] = r;
}
prev[r] = l;
}
return0; // 如果一开始就满足条件
}
int main() {
string s = "cat";
vector<int> order = {0, 2, 1};
int k = 6;
int result = minTime(s, order, k);
cout << result << endl;
return0;
}

·
我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。
·