小红书机考真题- 避重口令
整理历年互联网大厂机考、机试真题与面试真题,覆盖校招、实习招聘等常见求职场景,包含高频算法题、编程题、机考题及面试题,并提供完整代码、解题思路、代码详解和在线 OJ 练习,方便系统刷题和备战大厂技术面试。
点击查看完整题库目录:互联网大厂历年机考机试与面试真题题库|代码详解+在线OJ
题目描述
短视频审核后台要把已过审成片的标题按发布时间依次拼接,得到小写字符串 S。S 的每一个子序列(含 S 本身与空串)都被视为已经占用的口令,不能再给新专题使用。
求最短的、不是 S 子序列的小写口令长度。
子序列:从原串中删除任意个(可以为零个)字符后,剩余字符保持相对顺序所形成的串。
输入描述
一行,仅含小写字母的字符串 S(1≤∣S∣≤10^5)。
输出描述
一行一个正整数,即最短未占用口令的长度。
示例1
输入
zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba
输出
3
说明
S 由两段倒序的 26 个小写字母拼接而成。任意单个字母、任意长度为 2 的小写串都是 S 的子序列(前半段取第一个字符、后半段取第二个字符即可)。S 中字母 a 只出现两次,故
aaa不是子序列,最短长度为 3。
解题思路
核心思想
把字符串从左到右尽量早地切分:每当当前片段第一次集齐 26 个小写字母,就结束这一层,并从下一个字符重新收集。
假设最终得到 k 个完整层。每个完整层都至少包含一次 a 到 z,因此任意长度为 k 的小写字符串,都可以让第 i 个字符在第 i 层中找到,必然是 S 的子序列。所以答案至少为 k + 1。
另一方面,记每一层最后补齐的字母为该层的“收尾字母”。由于这一层是在该字符处第一次集齐 26 种字母,所以该收尾字母在本层此前没有出现。依次取每层的收尾字母,再取一个未出现在最后残余片段中的字母,可构造出一个长度为 k + 1、无法成为 S 子序列的口令。因此答案恰好是 k + 1。
算法步骤
- 准备一个集合或长度为 26 的布尔数组,记录当前层已经出现的字母。
- 从左到右扫描 S,将当前字符加入本层。
- 当前层集齐 26 种字母时,完整层数加一,并清空记录。
- 扫描结束后输出“完整层数 + 1”。
复杂度分析
- 时间复杂度:
O(n),每个字符只处理一次。 - 空间复杂度:
O(1),只维护 26 个字母的出现状态。
Java
import java.util.Scanner;
public class Main {
static int solve(String text) {
boolean[] appeared = new boolean[26];
int distinctCount = 0;
int completeLayers = 0;
for (int i = 0; i < text.length(); i++) {
// 当前层首次遇到某个字母时,更新已收集的不同字母数量
int index = text.charAt(i) - 'a';
if (!appeared[index]) {
appeared[index] = true;
distinctCount++;
}
// 集齐 26 个字母后形成一层,下一字符开始重新收集
if (distinctCount == 26) {
completeLayers++;
appeared = new boolean[26];
distinctCount = 0;
}
}
// 完整层数是可覆盖的最大万能长度,答案需要再加一
return completeLayers + 1;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine().trim();
System.out.println(solve(text));
scanner.close();
}
}
Python
def solve(text):
appeared = set()
complete_layers = 0
for ch in text:
# 当前层记录已经出现过的不同小写字母
appeared.add(ch)
# 集齐 26 个字母就完成一层,并从下一字符重新收集
if len(appeared) == 26:
complete_layers += 1
appeared.clear()
# 完整层数是所有等长口令都能成为子序列的最大长度
return complete_layers + 1
def main():
text = input().strip()
print(solve(text))
if __name__ == "__main__":
main()
JavaScript
const readline = require('readline');
function solve(text) {
const appeared = new Array(26).fill(false);
let distinctCount = 0;
let completeLayers = 0;
for (const ch of text) {
// 当前层首次遇到某个字母时,更新不同字母数量
const index = ch.charCodeAt(0) - 97;
if (!appeared[index]) {
appeared[index] = true;
distinctCount++;
}
// 集齐 26 个字母后完成一层,并清空状态继续扫描
if (distinctCount === 26) {
completeLayers++;
appeared.fill(false);
distinctCount = 0;
}
}
// 最短未占用口令长度比完整层数多一
return completeLayers + 1;
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
rl.once('line', (line) => {
console.log(solve(line.trim()));
rl.close();
});
C++
#include <array>
#include <iostream>
#include <string>
using namespace std;
int solve(const string& text) {
array<bool, 26> appeared{};
int distinctCount = 0;
int completeLayers = 0;
for (char ch : text) {
// 当前层首次遇到某个字母时,更新不同字母数量
int index = ch - 'a';
if (!appeared[index]) {
appeared[index] = true;
distinctCount++;
}
// 集齐 26 个字母后完成一层,并从下一字符重新收集
if (distinctCount == 26) {
completeLayers++;
appeared.fill(false);
distinctCount = 0;
}
}
// 完整层数加一就是最短未占用口令长度
return completeLayers + 1;
}
int main() {
string text;
cin >> text;
cout << solve(text) << '\n';
return 0;
}
Go
package main
import (
"bufio"
"fmt"
"os"
)
func solve(text string) int {
appeared := [26]bool{}
distinctCount := 0
completeLayers := 0
for _, ch := range text {
// 当前层首次遇到某个字母时,更新不同字母数量
index := int(ch - 'a')
if !appeared[index] {
appeared[index] = true
distinctCount++
}
// 集齐 26 个字母后完成一层,并清空状态继续扫描
if distinctCount == 26 {
completeLayers++
appeared = [26]bool{}
distinctCount = 0
}
}
// 最短未占用口令长度比完整层数多一
return completeLayers + 1
}
func main() {
in := bufio.NewReader(os.Stdin)
var text string
fmt.Fscan(in, &text)
fmt.Println(solve(text))
}
C语言
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
int solve(const char *text) {
bool appeared[26] = {false};
int distinctCount = 0;
int completeLayers = 0;
for (int i = 0; text[i] != '\0'; i++) {
// 当前层首次遇到某个字母时,更新不同字母数量
int index = text[i] - 'a';
if (!appeared[index]) {
appeared[index] = true;
distinctCount++;
}
// 集齐 26 个字母后完成一层,并清空状态继续扫描
if (distinctCount == 26) {
completeLayers++;
memset(appeared, 0, sizeof(appeared));
distinctCount = 0;
}
}
// 完整层数加一就是最短未占用口令长度
return completeLayers + 1;
}
int main(void) {
char text[100005];
if (scanf("%100000s", text) != 1) {
return 0;
}
printf("%d\n", solve(text));
return 0;
}
完整用例
用例1
zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba
用例2
a
用例3
abcdefghijklmnopqrstuvwxyz
用例4
abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxy
用例5
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc
用例6
abcdefghijklmnopqrstuvwxyazbcdefghijklmnopqrstuvwxyz
用例7
zyxwvutsrqponmlkjihgfedcbaabcdefghijklmnopqrstuvwxyz
用例8
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzmnop
用例9
aaaaaaaaaa
用例10
qwertyuiopasdfghjklzxcvbnm
文章目录

1万+




被折叠的 条评论
为什么被折叠?



