题目描述
回文串的定义:正读和反读都一样的字符串。
现在已经存在一个不包含回文串的字符串,字符串的字符都是在英语字母的前N个,且字符串不包含任何长度大于等于2的回文串;
请找出下一个字典序的不包含回文串的、字符都是在英语字母的前N个、且长度相同的字符串。
如果不存在,请输出NO。
输入描述
输入包括两行。
第一行有一个整数:N(1<=N<=26),表示字符串的每个字符范围都是前N的英语字母。
第二行输入一个字符串(输入长度<=10000),输入保证这个字符串是合法的并且没有包含回文串。
输出描述
输出下一个字典序的不包含回文串的、字符都是在英语字母的前N个、且长度相同的字符串;
如果不存在,请输出”NO“。
用例1
输入
3
cba
输出
NO
用例2
输入
4
cba
输出
cbd
用例3
输入
4
abcd
输出
abda
思路
- 核心逻辑:
- 倒序遍历字符串,找最右侧可递增的字符位(增大后满足「≠前1/前2位」);
- 增大该位后,低位从’a’开始填充,优先选最小的合法字符(≠前1/前2位);
- 无可用位则输出NO,否则输出填充后的字符串;
- 关键约束:仅校验「当前字符≠前1/前2位」,覆盖所有长度≥2的回文;
- 时间复杂度:O(n×N)(n为字符串长度,N为字母范围),len≤10000、N≤26,效率满足要求。
代码
function solution() {
const N = Number(readline());
const s = readline();
const n = s.length;
const strs = s.split('');
const maxCode = 97 + N-1;
let result = null;
for (let i = n-1; i >= 0; i--) {
const curCode = strs[i].charCodeAt(0);
for (let newCode = curCode + 1; newCode <= maxCode; newCode++) {
const newChar = String.fromCharCode(newCode);
// 检查是否合法(不与前一个或前前一个字符相同)
if (i > 0 && newChar === strs[i-1]) continue;
if (i > 1 && newChar === strs[i-2]) continue;
const newStr = [...strs.slice(0, i), newChar];
for (let j = i + 1; j < n; j++) {
// 尝试从 'a' 开始填充
for (let c = 97; c <= maxCode; c++) {
const char = String.fromCharCode(c);
// 检查是否合法
if (char === newStr[j-1]) continue;
if (j > 1 && char === newStr[j-2]) continue;
newStr.push(char);
break;
}
}
result = newStr;
break;
}
if (result) break;
}
console.log(result === null ? "NO" : result.join(''));
}
// 测试用例
const cases = [
`3
cba`,
`4
cba`,
`4
abcd`
];
let caseIndex = 0, lineIndex = 0;
const readline = (() => {
let lines = [];
return () => {
if (!lineIndex) lines = cases[caseIndex].trim().split('\n').map(l => l.trim());
return lines[lineIndex++];
};
})();
cases.forEach((_, i) => {
caseIndex = i;
lineIndex = 0;
solution();
console.log('-------');
});
4667

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



