目录
题目
题目内容:
在仅由数字组成的字符串中,找出只由 6 或 8 组成的最长连续子串。
输入描述:
输入数字字符串,长度小于 256。
输出描述:
输出所有最长子串,去重后按字典序排序;字符串为空或没有符合子串时输出 [""]。
样例 1
输入:
1688
输出:
["688"]
样例 2
输入:
123
输出:
[""]
样例 3
输入:
88612668
输出:
["668","886"]
思路
整体思路:扫描所有仅含 6/8 的极大连续段,维护最长长度与并列候选集合。
第一步:遇到 6/8 后扩展到连续段末尾。
第二步:更长段出现时清空旧候选,同长度则加入集合去重。
第三步:按字典序输出候选。
边界处理:空输入或无幸运段输出 [""];重复最长段只保留一次。
复杂度分析:扫描 O(N),排序 O(K log K),空间 O(K)。
Code
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
String s =
Optional
.ofNullable(
new BufferedReader(new InputStreamReader(System.in)).readLine())
.orElse("")
.trim();
// TreeSet 同时完成最长候选去重和字典序排序。
// 输入字符串 s 从左到右扫描;maxLength 记录目前最长段长度,best 只保存达到该长度的不同字符串。
TreeSet<String> best = new TreeSet<>();
int maxLength = 0, index = 0;
while (index < s.length()) {
if (s.charAt(index) != '6' && s.charAt(index) != '8') {
index++;
continue;
}
// [start,index) 是当前只含 6/8 的极大连续段。
// 极大段表示它左右两侧已经是非 6/8 字符或字符串边界,所以无需再从段内重复寻找更短子串。
int start = index;
while (index < s.length() &&
(s.charAt(index) == '6' || s.charAt(index) == '8'))
index++;
String segment = s.substring(start, index);
if (segment.length() > maxLength) {
// 新最长值出现时清空所有旧候选。
// 发现更长段时,旧候选已经不可能成为答案,需要先清空;同长度段则加入集合自动去重。
maxLength = segment.length();
best.clear();
best.add(segment);
} else if (segment.length() == maxLength)
best.add(segment);
}
// 如果扫描结束仍没有候选,题目要求返回一个空字符串元素,而不是返回空数组。
if (best.isEmpty())
best.add("");
// 集合内容先按字符顺序排列,再给每个字符串保留双引号,得到题目规定的数组格式。
StringJoiner output = new StringJoiner(",", "[", "]");
for (String item : best)
output.add("\"" + item + "\"");
System.out.println(output);
}
}
Go
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strings"
)
func main() {
line, _ := bufio.NewReader(os.Stdin).ReadString('\n')
s := strings.TrimSpace(line)
// best 用映射去重并列最长段,maxLength 是当前资格线。
// 输入字符串 s 从左到右扫描;maxLength 记录目前最长段长度,best 只保存达到该长度的不同字符串。
best := make(map[string]bool)
maxLength, index := 0, 0
for index < len(s) {
if s[index] != '6' && s[index] != '8' { index++; continue }
// [start,index) 是无法继续延长的极大幸运段。
// 极大段表示它左右两侧已经是非 6/8 字符或字符串边界,所以无需再从段内重复寻找更短子串。
start := index
for index < len(s) && (s[index] == '6' || s[index] == '8') { index++ }
segment := s[start:index]
if len(segment) > maxLength {
// 新最长段出现时重建集合,旧候选全部失效。
// 发现更长段时,旧候选已经不可能成为答案,需要先清空;同长度段则加入集合自动去重。
maxLength, best = len(segment), map[string]bool{segment: true}
} else if len(segment) == maxLength { best[segment] = true }
}
// 如果扫描结束仍没有候选,题目要求返回一个空字符串元素,而不是返回空数组。
if len(best) == 0 { best[""] = true }
answer := make([]string, 0, len(best))
for item := range best { answer = append(answer, item) }
sort.Strings(answer)
// 为每项加引号,再拼接成无空格数组。
// 集合内容先按字符顺序排列,再给每个字符串保留双引号,得到题目规定的数组格式。
for i := range answer { answer[i] = `"` + answer[i] + `"` }
fmt.Printf("[%s]\n", strings.Join(answer, ","))
}
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare_string(const void *a, const void *b) {
return strcmp(*(const char *const *)a, *(const char *const *)b);
}
int main(void) {
char s[257] = "";
if (fgets(s, sizeof(s), stdin))
s[strcspn(s, "\r\n")] = '\0';
// best 保存去重后的并列最长段,数量不会超过字符串长度。
// 输入字符串 s 从左到右扫描;max_length 记录目前最长段长度,best 只保存达到该长度的不同字符串。
char *best[256];
int count = 0, max_length = 0, index = 0, length = (int)strlen(s);
while (index < length) {
if (s[index] != '6' && s[index] != '8') {
index++;
continue;
}
// 扩展到第一个非 6/8 字符,得到当前极大连续段。
// 极大段表示它左右两侧已经是非 6/8 字符或字符串边界,所以无需再从段内重复寻找更短子串。
int start = index;
while (index < length && (s[index] == '6' || s[index] == '8'))
index++;
int segment_length = index - start;
if (segment_length > max_length) {
// 更长段出现时释放所有旧候选。
// 发现更长段时,旧候选已经不可能成为答案,需要先清空;同长度段则加入集合自动去重。
for (int i = 0; i < count; i++)
free(best[i]);
count = 0;
max_length = segment_length;
}
if (segment_length == max_length) {
char *segment = malloc((size_t)segment_length + 1);
memcpy(segment, s + start, (size_t)segment_length);
segment[segment_length] = '\0';
int duplicate = 0;
for (int i = 0; i < count; i++)
if (!strcmp(best[i], segment))
duplicate = 1;
if (duplicate)
free(segment);
else
best[count++] = segment;
}
}
qsort(best, (size_t)count, sizeof(char *), compare_string);
// 空串或无幸运段时按题意输出 [""]。
// 如果扫描结束仍没有候选,题目要求返回一个空字符串元素,而不是返回空数组。
if (!count) {
printf("[\"\"]\n");
return 0;
}
// 集合内容先按字符顺序排列,再给每个字符串保留双引号,得到题目规定的数组格式。
printf("[");
for (int i = 0; i < count; i++) {
printf(i ? ",\"%s\"" : "\"%s\"", best[i]);
free(best[i]);
}
printf("]\n");
return 0;
}
【华为od机试真题Python+JS+Java+Go合集】【超值优惠】:Py/JS/Java/Go合集
【华为od机试真题Python】:Python真题题库
【华为od机试真题JavaScript】:JavaScript真题题库
【华为od机试真题Java&Go】:Java&Go真题题库
【华为od机试真题C++】:C++真题题库
【华为od机试真题C语言】:C语言真题题库
【华为od面试手撕代码题库】:面试手撕代码题库
【华为od机试面试交流群】【文章底部有二维码链接,可扫码加交流群】

华为OD机试:二本院校有机会吗? 有机会,但不大,大神除外!机考分数越高越好,所以需要提前刷题。机考通过后,如果没有收到面试邀请,也不要着急,非目标院校面试邀请发的时间比较晚。非目标院校今年有点难,机试至少要考到350分,所以需要疯狂刷题,华为OD机考是有题库的,最好在考前完所有题库题目。华为OD机试:跨专业可以参加华为OD可以,但是如果你的本科院校比较差,上岸概率不大。华为OD机试:华为OD简历被锁定机试通过,性格测试也通过,但是没人联系面试,发现简历被锁定。此时需要主动去联系HR。让他帮助你查询原因。

268




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



