关联子串 - 华为OD统一考试(JavaScript题解)
华为OD机试题库《C++》限时优惠 9.9
华为OD机试题库《Python》限时优惠 9.9
华为OD机试题库《JavaScript》限时优惠 9.9
针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。
看不懂有疑问需要答疑辅导欢迎私VX: code5bug
题目描述
给定两个字符串str1和str2,如果字符串str1中的字符,经过排列组合后的字符串中,只要有一个字符串是str2的子串,则认为str1是str2的关联子串。
若str1是str2的关联子串,请返回子串在str2的起始位置;
若不是关联子串,则返回-1。
输入描述
输入两个字符串,分别为题目中描述的str1、str2。
备注:
输入的字符串只包含小写字母;
两个字符串的长度范围[1, 100000]之间;
输出描述
若str1是str2的关联子串,请返回子串在str2的起始位置;
若不是关联子串,则返回-1。
若str2中有多个str1的组合子串,请返回最小的起始位置。
示例1
输入:
abc efghicbaiii输出:
5说明:
str2包含str1的一种排列组合(“cab”),此组合在str2的字符串起始位置为5(从0开始计数)
示例2
输入:
abc efghiccaiii输出:
-1说明:
“abc”字符串中三个字母的各种组合(abc、acb、bac、bca、cab、cba),str2中均不包含,因此返回-1
题解
我们需要判断字符串
str1
的任意排列是否是str2
的子串。如果是,返回该子串在str2
中的起始位置(最小位置);否则返回 -1。解题思路
- 滑动窗口法:这是解决此类问题的经典方法。
- 统计
str1
的字符频率。- 在
str2
上维护一个与str1
长度相同的滑动窗口。- 比较窗口内字符频率与
str1
的字符频率。- 如果匹配,返回当前窗口的起始位置;否则滑动窗口继续检查。
JavaScript
const rl = require('readline').createInterface({input: process.stdin,output: process.stdout,
});var iter = rl[Symbol.asyncIterator]();const readline = async () => (await iter.next()).value;// 在s2中查找与s1字符组成相同的子串(关联子串)的起始位置
function solve(s1, s2) {// 使用Map统计s1的字符频率const cnt1 = new Map();for (const c of s1) {cnt1.set(c, (cnt1.get(c) || 0) + 1);}const targetLen = s1.length;if (targetLen > s2.length) return -1;// 初始化滑动窗口(前targetLen个字符)const window = new Map();for (let i = 0; i < targetLen; i++) {const c = s2[i];window.set(c, (window.get(c) || 0) + 1);}// 检查初始窗口是否匹配if (compareMaps(cnt1, window)) {return 0;}// 滑动窗口遍历s2for (let i = targetLen; i < s2.length; i++) {// 移除窗口最左边的字符const leftChar = s2[i - targetLen];if (window.get(leftChar) === 1) {window.delete(leftChar);} else {window.set(leftChar, window.get(leftChar) - 1);}// 添加新进入窗口的字符const rightChar = s2[i];window.set(rightChar, (window.get(rightChar) || 0) + 1);// 检查当前窗口是否匹配if (compareMaps(cnt1, window)) {return i - targetLen + 1;}}return -1; // 未找到匹配子串
}// 比较两个Map是否相等(用于频率统计比较)
function compareMaps(map1, map2) {if (map1.size !== map2.size) return false;for (const [key, val] of map1) {if (map2.get(key) !== val) {return false;}}return true;
}// Author: code5bug
(async () => {const input = await readline();const [s1, s2] = input.trim().split(/\s+/);console.log(solve(s1, s2));rl.close();
})();
希望这个专栏能让您熟练掌握算法
整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏