【OD机试题笔记】没有回文串

题目描述

回文串的定义:正读和反读都一样的字符串。

现在已经存在一个不包含回文串的字符串,字符串的字符都是在英语字母的前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. 核心逻辑
    • 倒序遍历字符串,找最右侧可递增的字符位(增大后满足「≠前1/前2位」);
    • 增大该位后,低位从’a’开始填充,优先选最小的合法字符(≠前1/前2位);
    • 无可用位则输出NO,否则输出填充后的字符串;
  2. 关键约束:仅校验「当前字符≠前1/前2位」,覆盖所有长度≥2的回文;
  3. 时间复杂度: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('-------');
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值