java解法

具体思路:

初始化字符频率表: 使用一个大小为 128 的数组 freqMap 来记录 subStr 中各字符的需求量。
初始化窗口: 首先处理 mainStr 的前 subLen + extraLen 个字符(初始窗口),检查是否已经满足条件。
动态调整窗口:
滑动窗口时,每次移除窗口起点字符,加入窗口终点字符,动态调整 freqMap 和未匹配字符的计数 missingCount。
检查匹配条件: 当 missingCount == 0 时,表示窗口内的字符可以通过排列形成 subStr,返回当前窗口起始索引。
无匹配返回 -1: 如果所有窗口均不满足条件,则返回 -1。

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 读取输入:子串、主串以及允许的额外字符长度
        String subStr = sc.next();
        String mainStr = sc.next();
        int extraLen = sc.nextInt();

        // 输出结果
        System.out.println(findMinIndex(subStr, mainStr, extraLen));
    }

    public static int findMinIndex(String subStr, String mainStr, int extraLen) {
        // 获取子串和主串的长度
        int subLen = subStr.length();
        int mainLen = mainStr.length();
        
        // 如果主串长度不足以容纳子串和额外字符,直接返回 -1
        if (mainLen < subLen + extraLen) return -1;

        // 初始化字符频率表,记录子串中每个字符的需求量
        int[] freqMap = new int[128];
        for (int i = 0; i < subLen; i++) {
            freqMap[subStr.charAt(i)]++;
        }

        // 记录未匹配的字符总数
        int missingCount = subLen;
        // 定义滑动窗口的最大起始索引
        int maxIndex = mainLen - subLen - extraLen;
        // 定义窗口长度
        int targetLen = subLen + extraLen;

        // 初始化窗口,检查前 targetLen 个字符
        for (int j = 0; j < targetLen; j++) {
            if (--freqMap[mainStr.charAt(j)] >= 0) { // 如果字符需求量未负,减少未匹配数量
                missingCount--;
            }

            // 如果未匹配数量为 0,表示找到匹配的窗口
            if (missingCount == 0) {
                return 0;
            }
        }

        // 滑动窗口,动态调整
        for (int i = 1; i <= maxIndex; i++) {
            // 移出窗口的字符,恢复其需求量
            if (++freqMap[mainStr.charAt(i - 1)] > 0) { 
                missingCount++;
            }
            // 加入窗口的字符,减少其需求量
            if (--freqMap[mainStr.charAt(i + targetLen - 1)] >= 0) {
                missingCount--;
            }

            // 如果未匹配数量为 0,返回当前窗口起始索引
            if (missingCount == 0) {
                return i;
            }
        }

        // 如果没有找到匹配,返回 -1
        return -1;
    }
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

C++解法

具体思路:

初始化字符频率表: 使用两个数组 cnt1 和 win 分别记录 s1 的字符频率和当前窗口的字符频率。
匹配计数器: 使用变量 match 记录窗口中与 s1 对应字符频率匹配的字符数量。
窗口初始化: 窗口长度为 len1 + k,初始时将 s2 的前 len1 + k 个字符加入窗口。
滑动窗口: 每次移动窗口:
加入新的字符,更新窗口频率,并检查是否增加匹配字符数量。
移除旧字符,更新窗口频率,并检查是否减少匹配字符数量。
匹配判断: 当 match == len1 时,表示窗口中字符完全覆盖了 s1 的所有字符,返回当前窗口的起始索引。
无匹配返回: 若遍历所有窗口后仍未找到匹配,返回 -1。

#include 
#include 
#include 

using namespace std;

// 在字符串 s2 中寻找满足条件的子串起始索引
int findSubstr(string s1, string s2, int k) {
    int len1 = s1.size(); // s1 的长度
    int len2 = s2.size(); // s2 的长度

    // 如果 s2 的长度不足以容纳 s1 和额外的 k 个字符,直接返回 -1
    if (len2 < len1 + k) return -1;

    // 初始化字符频率表:cnt1 记录 s1 中字符的需求量,win 记录窗口中字符的频率
    vector<int> cnt1(128, 0), win(128, 0);
    for (char c : s1) {
        cnt1[c]++;
    }

    // 记录匹配字符的数量
    int match = 0;
    // 窗口长度为 len1 + k
    int winLen = len1 + k;

    // 遍历字符串 s2
    for (int i = 0; i < len2; i++) {
        // 添加当前字符到窗口中
        if (win[s2[i]]++ < cnt1[s2[i]]) match++;

        // 当窗口长度超过 winLen 时,移除最左边的字符
        if (i >= winLen) {
            if (--win[s2[i - winLen]] < cnt1[s2[i - winLen]]) match--;
        }

        // 如果匹配字符数量等于 s1 的长度,返回当前窗口的起始索引
        if (match == len1) return i - winLen + 1;
    }

    // 如果未找到匹配的子串,返回 -1
    return -1;
}

int main() {
    string s1, s2;
    int k;

    // 输入子串 s1、主串 s2 和允许的额外字符长度 k
    cin >> s1 >> s2 >> k;

    // 输出结果
    cout << findSubstr(s1, s2, k) << endl;

    return 0;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

C解法

更新中
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

JS解法

初始化字符计数器:
使用哈希表 count 记录字符串 s1 中每个字符的需求频率。
窗口匹配计数器:
使用变量 missing 表示当前窗口中未匹配的 s1 中的字符数量。
初始化窗口:
窗口长度为 len1 + k,初始时将 s2 的前 len1 + k 个字符加入窗口,并动态更新 missing。
滑动窗口:
每次滑动窗口时,移出窗口的第一个字符,加入窗口的最后一个字符,同时更新 count 和 missing。
检查匹配条件:
当 missing == 0 时,表示窗口内字符完全覆盖了 s1 的所有字符,返回当前窗口的起始索引。
无匹配返回:
若遍历所有窗口后未找到匹配,返回 -1。

const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

const input = [];

rl.on("line", (line) => {
    input.push(line);
    if (input.length === 3) {
        const [s1, s2, k] = input;
        console.log(findMinIndex(s1, s2, parseInt(k)));
        input.length = 0;
    }
});

// 查找满足条件的子串的起始索引
function findMinIndex(s1, s2, k) {
    const len1 = s1.length; // s1 的长度
    const len2 = s2.length; // s2 的长度

    // 如果 s2 的长度不足以容纳 s1 和额外的 k 个字符,直接返回 -1
    if (len2 < len1 + k) return -1;

    // 初始化字符需求计数器
    const count = {};
    for (let ch of s1) {
        count[ch] = (count[ch] || 0) + 1;
    }

    // 初始化未匹配字符计数
    let missing = len1;
    // 窗口大小为 len1 + k
    const windowSize = len1 + k;

    // 初始化窗口,检查前 windowSize 个字符
    for (let i = 0; i < windowSize; i++) {
        const ch = s2[i];
        if (count[ch] !== undefined) { // 如果字符在需求表中
            if (count[ch] > 0) missing--; // 若字符仍被需求,减少未匹配计数
            count[ch]--; // 减少字符需求量
        }
        if (missing === 0) return 0; // 如果匹配成功,返回起始索引
    }

    // 滑动窗口,动态调整
    for (let i = 1; i <= len2 - windowSize; i++) {
        // 移出窗口的字符
        const toRemove = s2[i - 1];
        if (count[toRemove] !== undefined) { // 如果移出字符在需求表中
            if (count[toRemove] >= 0) missing++; // 若字符原本满足需求,增加未匹配计数
            count[toRemove]++; // 恢复字符需求量
        }

        // 加入窗口的字符
        const toAdd = s2[i - 1 + windowSize];
        if (count[toAdd] !== undefined) { // 如果加入字符在需求表中
            if (count[toAdd] > 0) missing--; // 若字符仍被需求,减少未匹配计数
            count[toAdd]--; // 减少字符需求量
        }

        // 如果匹配成功,返回当前窗口起始索引
        if (missing === 0) return i;
    }

    // 如果未找到匹配的子串,返回 -1
    return -1;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏

注:本文转载自blog.csdn.net的CodeClimb的文章"https://blog.csdn.net/CodeClimb/article/details/144537643"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!