题目描述
给定两个字符串string1和string2。
string1是一个被加扰的字符串。
string1由小写英文字母(‘a’-‘z’)和数字字符(‘0’-‘9’)组成,而加扰字符串由 ‘0’-‘9’、‘a’-‘f’ 组成。
string1里面可能包含0个或多个加扰子串,剩下可能有0个或多个有效子串,这些有效子串被加扰子串隔开。
string2是一个参考字符串,仅由小写英文字母(‘a’-‘z’)组成。
你需要在string1字符串里找到一个有效子串,这个有效子串要同时满足下面两个条件:
(1)这个有效子串里不同字母的数量不超过且最接近于string2里不同字母的数量,即小于或等于string2里不同字母的数量的同时且最大。
(2)这个有效子串是满足条件(1)里的所有子串(如果有多个的话)里字典序最大的一个。
如果没有找到合适条件的子串的话,请输出“Not Found”
输入描述
input_string1
input_string2
输出描述
output_string
用例1
输入
123admyffc79pt
ssyy
输出
pt
说明
将输入字符串 1 里的加扰子串 “123ad”、“ffc79” 去除后得到有效子串序列:“my”、“pt”,其中 “my” 里不同字母的数量为 2(有‘m’和‘y’两个不同字母),“pt” 里不同字母的数量为 2(有‘p’和‘t’两个不同字母);输入字符串 2 里不同字母的数量为 2(有‘s’和‘y’两个不同字母)。
可得到最终输出结果为 “pt”,其不同字母的数量最接近与 “ssyy” 里不同字母的数量的同时字典序最大。
说明
用例2
输入
123admyffc79ptaagghi2222smeersst88mnrt
ssyyfgh
输出
mnrt
说明
将输入字符串 1 里的加扰子串 “123ad”、“ffc79”、“aa”、“2222”、“ee”、“88” 去除后得到有效子串序列:“my”、“pt”、“gghi”、“sm”、“rsst”、“mnrt”;输入字符串 2 里不同字母的数量为 5(有 “s”、“y”、“f”、“g”、“h” 5 个不同字母)。可得到最终输出结果为 “mnrt”,其不同字母的数量为(4)最接近于 “ssyyfgh” 里不同字母的数量,其他有效子串不同字母的数量都小于 “mnrt”。
用例3
输入
abcmnq
rt
输出
Not Found
说明
将输入字符串 1 里的加扰子串 “abc” 去除后得到有效子串序列:“mnq”;输入字符串 2 里不同字母的数量为 2(有 “r”、“t” 两个不同的字母)。可得到最终的输出结果为 “Not Found”,没有符合要求的有效子串,因有效子串里的不同字母的数量(为 3),大于输入字符串 2 里的不同字母的数量。
思考
提取重点:(1)加扰字符范围 ‘0’-‘9’、‘a’-‘f’ ;(2)参考字符串 string2 只包含小写字母;(3)string1 是有效子串与加扰字符的混合体,有效子串和加扰子串数量都可能为0;(4)要算出 string2 中不同字母的数量 N,然后在 string1 中找到不同字母数量不超过且最接近 N的有效子串集合,从集合中挑出字典序最大的那个,如果没有则输出"Not Found"。
解题思路:那么第一步先计算 string2 中不同字母的数量 N,这个用哈希集合 Set 统计;第二步,遍历 string1 字符列表,拼接有效子串,存入有效子串集合中。遍历 string1 把每个加扰字符替换成空格“ ”,然后 string1.split(" ")切分可用得到所有有效子串的集合,这个集合中会包含之前切割空格产生的空串项目,过滤掉空串就得到有效子串集合。这些逻辑考察了子串基本操作,如 split、replace等。如果记得住正则表达式语法也可用正则表达式快速获取有效子串。如果前面几种字符串操作都嫌弃,那么用双指针从 string1 中截取所有有效子串也可行,但我觉得写起来容易错,不熟练可能会花费许多时间调试!得到了有效子串集合,暂且命名为 effectingSubs,统计每个子串中不同字母的数量 M,保留 M 最大的子串,再按字典序倒序排序,返回第一个。如果结果集合为空返回 “Not Found”。
算法过程
- 读取输入:从标准输入读取
string1
和string2
。 - 计算
string2
的不同字母数量:使用countDiff
函数计算string2
中不同字母的数量。 - 提取有效子串:
- 定义加扰字符为
'0'-'9'
和'a'-'f'
。 - 将
string1
中的所有加扰字符替换为空格。 - 使用
split(' ')
分割字符串,得到有效子串列表。 - 过滤掉空字符串。
- 定义加扰字符为
- 筛选有效子串:
- 遍历所有有效子串,计算每个子串的不同字母数量。
- 保留那些不同字母数量不超过
string2
的不同字母数量且尽可能接近的子串。
- 选择结果:
- 如果没有满足条件的子串,输出 “Not Found”。
- 否则,按字典序降序排序,输出第一个子串。
参考代码1
function solution() {
let str1 = readline();
const str2 = readline();
const strDiffNum = countDiff(str2);
let badChars = 'abcdef';
for (let i = 0; i <= 9; i++) {
badChars += i+'';
}
for (let i = 0; i < str1.length; i++) {
if (badChars.includes(str1[i])) {
str1 = str1.replace(str1[i], " ")
}
}
let arr1 = str1.split(' ');
let effectingSubs = [];
for (let s of arr1) {
if (s !== '') {
effectingSubs.push(s);
}
}
// console.log(effectingSubs);
let result = [];
let maxDiffNum = 0;
for (let s of effectingSubs) {
let diffNum = countDiff(s);
if (diffNum > 0 && diffNum <= strDiffNum) {
if (diffNum === maxDiffNum) {
maxDiffNum = Math.max(maxDiffNum, diffNum);
result.push(s);
} else if (diffNum > maxDiffNum) {
maxDiffNum = diffNum;
result = [s];
}
}
}
if (maxDiffNum === 0) {
console.log("Not Found");
return;
}
result.sort((a, b) => {
if (a >= b) {
return -1;
} else {
return 1;
}
});
console.log(result[0]);
}
function countDiff(s) {
const set = new Set();
for (const c of s) {
if (/[a-z]/.test(c)) { // 仅统计小写字母
set.add(c);
}
}
return set.size;
}
const cases = [
`123admyffc79pt
ssyy`, // pt
`123admyffc79ptaagghi2222smeersst88mnrt
ssyyfgh`, // mnrt
`abcmnq
rt`, // Not Found
];
let caseIndex = 0;
let lineIndex = 0;
const readline = (function () {
let lines = [];
return function () {
if (lineIndex === 0) {
lines = cases[caseIndex]
.trim()
.split("\n")
.map((line) => line.trim());
}
return lines[lineIndex++];
};
})();
cases.forEach((_, i) => {
caseIndex = i;
lineIndex = 0;
solution();
});
潜在问题
- 加扰字符替换:
- 代码中使用
str1.replace(str1[i], " ")
逐个替换加扰字符为空格。这种方法会多次修改字符串,效率较低。 - 更好的方法是使用正则表达式一次性替换所有加扰字符。
- 代码中使用
- 字典序排序:
- 使用
a >= b
作为比较函数不严谨,可能导致排序结果不符合预期。应该使用localeCompare
或直接比较字符串。
- 使用
参考代码2(优化版)
function solution() {
let str1 = readline();
const str2 = readline();
const strDiffNum = countDiff(str2);
// Replace all bad characters with spaces
const badChars = /[0-9a-f]/g;
str1 = str1.replace(badChars, ' ');
// Split by spaces and filter out empty strings
const effectingSubs = str1.split(' ').filter(s => s !== '');
let result = [];
let maxDiffNum = 0;
for (const s of effectingSubs) {
const diffNum = countDiff(s);
if (diffNum > 0 && diffNum <= strDiffNum) {
if (diffNum > maxDiffNum) {
maxDiffNum = diffNum;
result = [s];
} else if (diffNum === maxDiffNum) {
result.push(s);
}
}
}
if (result.length === 0) {
console.log("Not Found");
return;
}
// Sort in descending lexicographical order
result.sort((a, b) => b.localeCompare(a));
console.log(result[0]);
}
function countDiff(s) {
const set = new Set(); // set自动去重
for (const c of s) {
if (/[a-z]/.test(c)) { // 仅统计小写字母
set.add(c);
}
}
return set.size;
}
const cases = [
`123admyffc79pt
ssyy`, // pt
`123admyffc79ptaagghi2222smeersst88mnrt
ssyyfgh`, // mnrt
`abcmnq
rt`, // Not Found
];
let caseIndex = 0;
let lineIndex = 0;
const readline = (function () {
let lines = [];
return function () {
if (lineIndex === 0) {
lines = cases[caseIndex]
.trim()
.split("\n")
.map((line) => line.trim());
}
return lines[lineIndex++];
};
})();
cases.forEach((_, i) => {
caseIndex = i;
lineIndex = 0;
solution();
});