【中等】算法nodeJs:查找兄弟单词

105 阅读2分钟

描述

定义一个由小写字母构成的字符串 s 的“兄弟单词”为:任意交换 s 中两个字母的位置,得到的新字符串,且其与 s 不同。
现在,对于给定的 n 个字符串 s1​,s2​,…,sn​ 和另一个单独的字符串 x ,你需要解决两个问题:
∙统计这 n 个字符串中,有多少个是 x 的“兄弟单词”;
∙将这 n 个字符串中 x 的“兄弟单词”按字典序从小到大排序,输出排序后的第 k 个兄弟单词。特别地,如果不存在,则不输出任何内容。

从字符串的第一个字符开始逐个比较,直到找到第一个不同的位置,通过比较这个位置字符的字母表顺序得出字符串的大小,称为字典序比较。

输入描述:

在一行上:
1.​先输入一个整数 n(1≦n≦1000) 代表字符串的个数;
2.​随后,输入 n 个长度为 1≦length(si​)≦10 ,仅由小写字母构成的字符串 s1​,s2​,…,sn​ ;
3.​随后,输入一个字符串 x ;
4.​最后,输入一个整数 k(1≦k≦n) 代表要查找的兄弟单词的序号。

输出描述:

第一行输出一个整数,代表给定的 n 个字符串中,x 的“兄弟单词”的数量;
第二行输出一个字符串,代表将给定的 n 个字符串中 x 的“兄弟单词”按字典序排序后的第 k 小兄弟单词。特别地,如果不存在,则不输出任何内容。

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
    // 判断两个字符串是否是兄弟字符串
    const isBro = (s, k) => {
        if (s.length < 2) return false;
        if (s.length !== k.length) return false;
        if (s === k) return false;

        const sMap = new Map();
        const kMap = new Map();

        // 统计字符频率
        for (let i = 0; i < s.length; i++) {
            sMap.set(s[i], (sMap.get(s[i]) || 0) + 1);
            kMap.set(k[i], (kMap.get(k[i]) || 0) + 1);
        }

        // 比较两个 Map 的内容是否相同
        if (sMap.size !== kMap.size) return false;
        for (let [key, value] of sMap) {
            if (kMap.get(key) !== value) return false;
        }
        return true;
    };

    while ((line = await readline())) {
        let tokens = line.split(" ");
        const broArr = tokens.slice(0, -2); // 提取所有候选兄弟字符串
        const s = tokens[tokens.length - 2]; // 目标单词
        const num = parseInt(tokens[tokens.length - 1], 10); // 指定的序号

        // 使用 filter 方法收集兄弟字符串
        const arr = broArr.filter((word) => isBro(s, word));

        // 输出兄弟字符串的数量
        console.log(arr.length);

        // 如果存在兄弟字符串且序号有效,输出第 n 个兄弟字符串
        if (arr.length >= num) {
            arr.sort((a, b) => a.localeCompare(b)); // 按字典序排序
            console.log(arr[num - 1]);
        }
    }
})();