2014. 重复 K 次的最长子序列
March 11, 2026 · View on GitHub
题目描述
给你一个长度为 n 的字符串 s ,和一个整数 k 。请你找出字符串 s 中 重复 k 次的 最长子序列 。
子序列 是由其他字符串删除某些(或不删除)字符派生而来的一个字符串。
如果 seq * k 是 s 的一个子序列,其中 seq * k 表示一个由 seq 串联 k 次构造的字符串,那么就称 seq 是字符串 s 中一个 重复 k 次 的子序列。
- 举个例子,
"bba"是字符串"bababcba"中的一个重复2次的子序列,因为字符串"bbabba"是由"bba"串联2次构造的,而"bbabba"是字符串"bababcba"的一个子序列。
返回字符串 s 中 重复 k 次的最长子序列 。如果存在多个满足的子序列,则返回 字典序最大 的那个。如果不存在这样的子序列,返回一个 空 字符串。
示例 1:

输入:s = "letsleetcode", k = 2 输出:"let" 解释:存在两个最长子序列重复 2 次:let" 和 "ete" 。 "let" 是其中字典序最大的一个。
示例 2:
输入:s = "bb", k = 2 输出:"b" 解释:重复 2 次的最长子序列是 "b" 。
示例 3:
输入:s = "ab", k = 2 输出:"" 解释:不存在重复 2 次的最长子序列。返回空字符串。
提示:
n == s.length2 <= k <= 20002 <= n < min(2001, k * 8)s由小写英文字母组成
解法
方法一:BFS
我们可以先统计字符串中每个字符出现的次数,然后将出现次数大于等于 的字符按从小到大的顺序存入一个列表 中。接下来,我们可以使用 BFS 来枚举所有可能的子序列。
我们定义一个队列 ,初始时将空字符串放入队列中。然后,我们从队列中取出一个字符串 ,并尝试将每个字符 添加到 的末尾,形成一个新的字符串 。如果 是一个重复 次的子序列,我们就将其加入到答案中,并将 放入队列中继续处理。
我们需要一个辅助函数 来判断字符串 是否是字符串 的一个重复 次的子序列。具体地,我们可以使用两个指针来遍历字符串 和 ,如果在遍历过程中能够找到 的所有字符,并且能够重复 次,那么就返回 ,否则返回 。
Python3
class Solution:
def longestSubsequenceRepeatedK(self, s: str, k: int) -> str:
def check(t: str, k: int) -> bool:
i = 0
for c in s:
if c == t[i]:
i += 1
if i == len(t):
k -= 1
if k == 0:
return True
i = 0
return False
cnt = Counter(s)
cs = [c for c in ascii_lowercase if cnt[c] >= k]
q = deque([""])
ans = ""
while q:
cur = q.popleft()
for c in cs:
nxt = cur + c
if check(nxt, k):
ans = nxt
q.append(nxt)
return ans
Java
class Solution {
private char[] s;
public String longestSubsequenceRepeatedK(String s, int k) {
this.s = s.toCharArray();
int[] cnt = new int[26];
for (char c : this.s) {
cnt[c - 'a']++;
}
List<Character> cs = new ArrayList<>();
for (char c = 'a'; c <= 'z'; ++c) {
if (cnt[c - 'a'] >= k) {
cs.add(c);
}
}
Deque<String> q = new ArrayDeque<>();
q.offer("");
String ans = "";
while (!q.isEmpty()) {
String cur = q.poll();
for (char c : cs) {
String nxt = cur + c;
if (check(nxt, k)) {
ans = nxt;
q.offer(nxt);
}
}
}
return ans;
}
private boolean check(String t, int k) {
int i = 0;
for (char c : s) {
if (c == t.charAt(i)) {
i++;
if (i == t.length()) {
if (--k == 0) {
return true;
}
i = 0;
}
}
}
return false;
}
}
C++
class Solution {
public:
string longestSubsequenceRepeatedK(string s, int k) {
auto check = [&](const string& t, int k) -> bool {
int i = 0;
for (char c : s) {
if (c == t[i]) {
i++;
if (i == t.size()) {
if (--k == 0) {
return true;
}
i = 0;
}
}
}
return false;
};
int cnt[26] = {};
for (char c : s) {
cnt[c - 'a']++;
}
vector<char> cs;
for (char c = 'a'; c <= 'z'; ++c) {
if (cnt[c - 'a'] >= k) {
cs.push_back(c);
}
}
queue<string> q;
q.push("");
string ans;
while (!q.empty()) {
string cur = q.front();
q.pop();
for (char c : cs) {
string nxt = cur + c;
if (check(nxt, k)) {
ans = nxt;
q.push(nxt);
}
}
}
return ans;
}
};
Go
func longestSubsequenceRepeatedK(s string, k int) string {
check := func(t string, k int) bool {
i := 0
for _, c := range s {
if byte(c) == t[i] {
i++
if i == len(t) {
k--
if k == 0 {
return true
}
i = 0
}
}
}
return false
}
cnt := [26]int{}
for i := 0; i < len(s); i++ {
cnt[s[i]-'a']++
}
cs := []byte{}
for c := byte('a'); c <= 'z'; c++ {
if cnt[c-'a'] >= k {
cs = append(cs, c)
}
}
q := []string{""}
ans := ""
for len(q) > 0 {
cur := q[0]
q = q[1:]
for _, c := range cs {
nxt := cur + string(c)
if check(nxt, k) {
ans = nxt
q = append(q, nxt)
}
}
}
return ans
}
TypeScript
function longestSubsequenceRepeatedK(s: string, k: number): string {
const check = (t: string, k: number): boolean => {
let i = 0;
for (const c of s) {
if (c === t[i]) {
i++;
if (i === t.length) {
k--;
if (k === 0) {
return true;
}
i = 0;
}
}
}
return false;
};
const cnt = new Array(26).fill(0);
for (const c of s) {
cnt[c.charCodeAt(0) - 97]++;
}
const cs: string[] = [];
for (let i = 0; i < 26; ++i) {
if (cnt[i] >= k) {
cs.push(String.fromCharCode(97 + i));
}
}
const q: string[] = [''];
let ans = '';
while (q.length > 0) {
const cur = q.shift()!;
for (const c of cs) {
const nxt = cur + c;
if (check(nxt, k)) {
ans = nxt;
q.push(nxt);
}
}
}
return ans;
}