首页 > 试题广场 >

最短包含字符串的长度

[编程题]最短包含字符串的长度
  • 热度指数:2120 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定字符串str1和str2,求str1的字串中含有str2所有字符的最小字符串长度。

输入描述:
输入包括两行,第一行一个字符串,代表str1,第二行也是一个字符串,代表str2


输出描述:
输出str1的字串中含有str2所有字符的最小字符串长度,如果不存在请输出0。
示例1

输入

abcde
ac

输出

3

说明

“abc”中包含“ac”,且“abc”是所有满足条件中最小的。
示例2

输入

12345
344

输出

0
#include <stdio.h>
#include <string.h>
#include <limits.h>

#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX_LEN 100001

int min_len(char *str1, char *str2);

int main(void) {
    char str1[MAX_LEN], str2[MAX_LEN];
    scanf("%s%s", str1, str2);
    printf("%d\n", min_len(str1, str2));
    return 0;
}

int min_len(char *str1, char *str2) {
    int len1 = (int) strlen(str1);
    int len2 = (int) strlen(str2);
    int map[256];
    memset(map, 0, sizeof(int) * 256);
    for (int i = 0; i < len2; i++) {
        map[str2[i]]++;
    }

    int min_len = INT_MAX, need = len2;
    int l = 0, r = -1;
    while (++r < len1) {
        map[str1[r]]--;
        if (map[str1[r]] >= 0) need--;
        if (need == 0) {
            while (map[str1[l]] < 0) {
                map[str1[l++]]++;
            }
            min_len = MIN(min_len, r - l + 1);
        }
    }
    return min_len != INT_MAX ? min_len : 0;
}

发表于 2022-02-11 22:24:43 回复(0)
双指针滑动窗口求解(leftright双指针):
  1. 先统计str2的字符频数,以及总的字符负债debt=str2.length
  2. 遍历str1,利用right指针扩张右边界,遇到str2中没有的字符直接跳过,否则同步减少当前字符的计数和总的字符负债,但当计数小于0时,不再减小总的字符负债,因为出现字符的多余;
  3. debt=0时,表示在str1中找到了包含str2所有字符的子串,右移左指针left收缩左边界,直到排除所有多余字符(频数小于0的字符)后更新长度。
  4. 滑动窗口重复上面三个步骤,查找后面有没有更短的子串。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        char[] str1 = br.readLine().toCharArray();
        char[] str2 = br.readLine().toCharArray();
        HashMap<Character, Integer> termFreq = new HashMap<>();
        for(int i = 0; i < str2.length; i++) termFreq.put(str2[i], termFreq.getOrDefault(str2[i], 0) + 1);
        int left = 0, right = 0;
        int debt = str2.length;        // 刚开始欠str2长度的字符
        int minLen = str1.length + 1;
        while(right < str1.length){
            if(!termFreq.containsKey(str1[right])) {
                right ++;    // 跳过不相关的字符
                continue;
            }
            termFreq.put(str1[right], termFreq.getOrDefault(str1[right], 0) - 1);
            if(termFreq.get(str1[right]) >= 0) debt --;
            if(debt == 0){
                if(!termFreq.containsKey(str1[left])){
                    left ++;    // 跳过不相关的字符
                    continue;
                }
                // 负债小于0的词是多余的,先去掉
                while(termFreq.get(str1[left]) < 0){
                    termFreq.put(str1[left], termFreq.getOrDefault(str1[left], 0) + 1);
                    left ++;
                }
                // 负债为0且无多余词,更新长度
                minLen = Math.min(minLen, right - left + 1);
                termFreq.put(str1[left], termFreq.getOrDefault(str1[left], 0) + 1);
                debt ++;
                left ++;
            }
            right ++;
        }
        minLen = Math.min(minLen, right - left + 1);
        System.out.println(minLen == str1.length + 1? 0: minLen);
    }
}

编辑于 2021-11-27 17:55:17 回复(0)
import java.util.*;
public class Main{
    public static int shortLengthOfStr(String A, String B) {
        char[] BChar = B.toCharArray();
        char[] AChar = A.toCharArray();
        int[] BMap = new int[256];
        
        
        /**
         * BMap中状态:BMap中状态:0初始值,>0欠缺的值, <0不欠缺的值
         */
        //将欠缺哪些值压入map中
        for (int i = 0; i < BChar.length; i++) {
            BMap[BChar[i]] ++;
        }

        int before = 0;
        int after = 0;
        int minLen  = Integer.MAX_VALUE;;
        int match = BChar.length;
        while (before < AChar.length){
            /**
            *  初始值 自减后 小于0,变成不欠缺的值
            *  欠缺的值 自减后,最小变成 0 初始值
            **/
            BMap[AChar[before]]--;
            if (BMap[AChar[before]] >= 0) {
                //找到欠的字符,match自减,直到match=0,说明BMap中大于0的值匹配到了
                match--;
            }

            if (match == 0){
                //全匹配上了,开始向右移动after,after也是从0开始
                //这里可以理解为找匹配字符的最左边的位置。
                //例如:abcsfdr
                //这里找:bcd
                //此时,before已经到了d即index=5的位置
                //要计算出长度,需要知道,最左边在{bcd}中字符的位置
                //所以移动after从index=0开始,直到找到{bcd}中任意字符
                //所以after移动到b即index=1,此时最短长度为 5 - 1 + 1 = 5
                while (BMap[AChar[after]] < 0){
                    /**
                    *小于0说明不是匹配到的数字,继续右移,直到找到最左边BChar值
                    因为匹配的数据是大于0,经过上面BMap[AChar[before]]--后
                    变成0了
                    **/
                    BMap[AChar[after]]++;
                    after++;
                }
                minLen = Math.min(minLen, before - after + 1);

                //继续往下走
                match++;
                //回补一个字符,告诉Map,哪个字符欠一个
                BMap[AChar[after]]++;
                after++;
            }
            //向右移动before
            before++;
        }
        return minLen == Integer.MAX_VALUE ? 0 : minLen;
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String[] data = new String[2];
        int count = 0;
        while(scan.hasNext()){
            data[count] = scan.nextLine();
            count++;
            if (count > 1){
                break;
            }
        }
        System.out.println(shortLengthOfStr(data[0], data[1]));
    }
}

发表于 2020-03-01 15:31:34 回复(0)
import java.util.Scanner;
/*设str1长度为N,str2长度为M。如果N<M,那么结果必然为0。
其余情况使用一个哈希表map来辅助。
	
  1. 先遍历一遍str2,生成哈希表对于字符的统计,其数值的具体意义就是str1目前还欠str2字符串key字符value个。
  2. 需要定义四个变量:left: str1中子串左边界;right: str1中子串右边界;match:对于所有的str2中的字符来说,str1欠str2的字符总个数;minLen: 最小子串的长度。初始时,left=0,right=0,match可由遍历str2的时候得到,minLen为32位整数最大值
  3. 通过right变量从左到右遍历str1,设当前位置right==i,有几种情况:
    1. 首先在map中把str[i]字符的value减1。如果减完之后,map[str[i]]的value大于等于0,说明str1归还了一个str[i],match也对应的-1。
    2. 在map中把str[i]字符的value减1,如果减完之后,map[str[i]]的value小于0,说明这个字符是目前str2不需要的,所以match不变。
    3. 直到某次会将match减为0时,说明str1把需要归还的字符都还完了,但此时对应的子串并不是一定最短的,因为可能有些字符归还的比较多余,此时开始向右移动left。
    4. 初始时left=0,把str[0]对应字符拿回来后,要在map[str[0]]位置+1,如果map[str[0]]位置没加1之前是负数,说明可以要回来。然后继续向右移动left,直到出现map[str[left]]为0时,不能再减了,否则就又亏欠了。此时出现了一个子串满足条件,更新minLen为right-left+1。至此,使得出现满足条件的子串的第一个right出现,但还是要往右扩,观察后面有没有更小的值。
    5. 后面的其余子串肯定比之前的子串left靠右,因为之前子串left对应的最短子串已经找到,对maxLen已经更新。所以此时令left++,同时让对应字符在map中也+1,说明又出现了亏欠str2,对应得,match也+1。然后继续right往右扩,直到match继续归0,重复这个过程,直到right到达str1的末尾。
    6. 如果从始至终没有更新过maxLen,说明没有匹配成功过,返回0。

时间复杂度: O(N)*/

public class Main {
    public static void main(String[] args) {         Scanner scanner = new Scanner(System.in);         String str1 = scanner.next();         String str2 = scanner.next();         int minlength = minLength(str1, str2);         System.out.println(minlength);     }      public static int minLength(String str1, String str2) {         if (str1 == null || str2 == null || str1.length() < str2.length()) {             return 0;         }         char[] chas1 = str1.toCharArray();         char[] chas2 = str2.toCharArray();         int[] map = new int[256];         for (int i = 0; i < chas2.length; i++) {             map[chas2[i]]++;         }         int left = 0;         int right = 0;         int match = chas2.length;         int minLen = Integer.MAX_VALUE;         while (right < chas1.length) {             map[chas1[right]]--;             if (map[chas1[right]] >= 0) {                 match--;             }             if (match == 0) {                 while (map[chas1[left]] < 0) {                     map[chas1[left++]]++;                 }                 minLen = Math.min(minLen, right - left + 1);                 match++;                 map[chas1[left++]]++;             }             right++;         }         return minLen == Integer.MAX_VALUE ? 0 : minLen;     } }


编辑于 2020-02-29 17:31:12 回复(1)
#include <bits/stdc++.h>
using namespace std;

int main(){
    string s1, s2;
    cin>>s1>>s2;
    int n=s1.length(), m=s2.length(), l=0, r=0, Min=INT_MAX;
    unordered_map<int,int> M;
    if(n<m){
        puts("0");
        return 0;
    }
    for(int i=0;i<m;i++)
        M[s2[i]]++;
    for(int i=0,k=0;i<n;i++){
        M[s1[i]]--;
        if(M[s1[i]] >= 0){
            k++;
            if(k==m){
                while(M[s1[l]] < 0)
                    M[s1[l++]]++;
                Min = min(Min, r-l+1);
                M[s1[l++]]++;
                k--;
            }
        }
        r++;
    }
    printf("%d\n", Min==INT_MAX?0:Min);

    return 0;
}

编辑于 2020-06-14 10:58:12 回复(0)
    public static int minLen(String a, String b){
        char[] char1 = a.toCharArray();
        char[] char2 = b.toCharArray();

        HashMap<Character, Integer> map = new HashMap<>();
        for (char c : char1) {
            map.put(c, 0);
        }
        for (char c : char2) {
            map.put(c, -1);
        }

        int match = 0;
        int start = 0;
        int end = 0;
        int len = Integer.MAX_VALUE;

        for (int i = 0; i < char1.length; i++) {
            if (map.get(char1[i]) == -1) {
                map.put(char1[i], 1);
                match++;

                if (match == char2.length) {
                    end = i;
                    while (map.get(char1[start]) != 1) {
                        start++;
                    }
                    len = Math.min(len, end - start + 1);

                    map.put(char1[start], -1);
                    match--;
                    start++;
                }
            }
        }

        return len;
    }


编辑于 2021-10-16 21:45:55 回复(0)

Golang解法

代码如下

package main

import (
    "fmt"
    "math"
    "strings"
)

func GetMinLength(str1, str2 string)int {
    // 获取最短长度
    left, res, match := 0, math.MaxInt32, len(str2)

    // 先统计str2的字符出现的频次
    frequence := map[string]int{}

    for _, ch := range str2 {
        frequence[string(ch)] = strings.Count(str2, string(ch))
    }

    for right := 0;right < len(str1);right++ {
        nowchar := string(str1[right])

        if frequence[nowchar]--;frequence[nowchar] >= 0 {
            match--

            if match == 0 {
                // 收缩左边界
                for frequence[string(str1[left])] < 0 {
                    frequence[string(str1[left])]++
                    left++
                }

                res = int(math.Min(float64(res), float64(right - left + 1)))

                // 移动左边界
                frequence[string(str1[left])]++
                left++
                match++
            }
        }
    }

    if res == math.MaxInt32 {
        res = 0
    }

    return res
}

func main() {
    var str1, str2 string
    fmt.Scan(&str1)
    fmt.Scan(&str2)
    fmt.Println(GetMinLength(str1, str2))
}
发表于 2021-04-28 11:05:48 回复(0)
def minWindow(s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        need,window={},{}
        for i in t:
            need[i]=need.get(i,0)+1
        #定义窗口左右节点,初始化最小长度
        left,right = 0,0
        minlen = float('inf')
        #窗口包含t字符个数
        count=0
        while right<len(s):
            if need.get(s[right],0)==0:
                right+=1
                continue
            window[s[right]]=window.get(s[right],0)+1
            if window[s[right]]==need[s[right]]:
                count+=1
            right+=1
            #当窗口包含t所有的字符时,缩小窗口
            while count==len(t):
                if right-left<minlen:
                    minlen=right-left
                #缩小窗口
                if s[left] not in need:
                    left+=1
                    continue
                #出窗,不满足条件结束循环
                if window[s[left]]==need[s[left]]:
                    count-=1
                window[s[left]]-=1
                left+=1
        if minlen==float('inf'):
            return 0
        else:
            return minlen
        
s=input()
t=input()
print(minWindow(s,t))
链接:https://www.nowcoder.com/questionTerminal/58569ba19c05436e9eb492244b0902d8
来源:牛客网
您的代码已保存
答案错误:您提交的程序没有通过所有的测试用例
case通过率为28.57%
用例:
YVRYIaLMyKzhPVAgQTJblZITJUaEiZDCOkzYVolKDCSdEoVeDUCXWrZQwXaSJZLVmgxmUvJZVvHLAuutRaaDsqDDZoEtznxCxqjPVAENPOjRlhPjFdGxQCprzKeXnooqDrwZZjqnTltpDwiWmjORaeemItQhuMIbBzHLskjIHWJjbfTrKDAyoaOHjApMCQHVAabnVDoSwHDXfFHXcOmcrkrieCQWHicfMLNdcYuZBAyVXfQyCsYkiXgRdBMUsQCinrsfPFFsoHiKXZJjGWQnPguYsVRGMyxUQaynGBteHJyEJzAUEHwrMpzLDnZGpuxRmGabZuPvHcPmlanDExXYkKtEyIgvxStIXAvYKXirVMXvadOuykiFixuMKaHYTXmlPTdmWjcpNsaFMcxffALvAURprNhhGvskLTgDfIwERLZMcjgUPCFaUztICgQOklDHJuGovKsojDXqpAUkmfMETvXvKtPCkLCQHFmwpCiLBnkoXpVBfSYWVyVOHneOWvyzPthrWBDIxZIfKAOHvlwDNiLTVjrYqShfrSSeeTmERZimBxhvgEnVkQCcsKDYJRFUHwTQgMCdOYXZenwMhSLaGNIXLHDqYdZbQoKUpsyNJxRYTvJImDAHbfONprsWXsAjjfubPUxNERCiOjeVZIlzyChWIxUmEEOSyTvMKNecDOXrBljujPjQMDXbzPbRLLrwdAQBcohSdcUAcStQTgaIVRqOzLdXkqICbhlHOzvbFpnLwrIlaPsqxYnFqMBKvAgfCRCkDmGIfoOTlIycpesWnRSokRKZDjRdtmNHroeCHAvRcpqfvBZRYSRhZIoFSyJyBvCUhDMFGTWGotNkbTbAqfqsmdmuiWhrmyNvjcbRFuYrBbhrPYQuFRnWWLUSsJmisjVZtAjzQPYHrlDwWPXKunQHpeukzfWPIjqbHbbCAOKgRvsRuqxTiXauAdGLlaFqhtTSpnxEduGhbOmrLrugpZWNOnQFYPcXtBlSZofNNitvvdveMCzznYWyXkU

有部分用例未通过,实在查不出什么问题,麻烦大神帮忙看下
编辑于 2021-03-18 04:34:50 回复(0)
我还是太菜, 唉

#include <iostream>
#include <limits>
#include <string>


size_t minLength(const std::string & str1, const std::string & str2)
{
    /* 方法:
     * 1. 创建计数数组table,统计str2的每个字符的个数,
     * 2. 定义变量matched表示当前已匹配str2中字符的个数
     * 3. 滑动窗口,左边界为left,右边界为right,初始都为0
     *    增长右边界,每次将计数组中右边界对应的字符的计数减一,
     *    如果计数大于等于0,说明这个字符匹配到了str2中的字符,将matched计数加一
     * 4. 判断matched是否等于str2的长度,如果等于,则说明字符已经全部匹配,此时计数数组中的元素应该全部小于等于0,
     *    接下来将left边界右移,移过那些不在str2中出现的字符(移动的时候要先给计数数组对应的值加1),直到匹配到一个str2的字符为止,
     *    如何判断匹配到str2中的字符呢?计数为0即可。
     *    例如str1="AAABBB", str2="AB", 在第一次全部匹配到时,
     *    AAABBB, 计数数组table[A]=-2, table[B]=0, 判断left当前指向的为止对应的计数是否为0,如果不是则右移
     *    ^  ^
     *    |  |
     *  left right
     */

    std::vector<int> table(256);
    for(char c : str2)
    {
        table[static_cast<unsigned char>(c)]++;
    }

    const unsigned char * pStr1 = reinterpret_cast<const unsigned char *>(str1.c_str());

    size_t res = std::numeric_limits<size_t>::max();
    size_t left = 0;
    size_t right = 0;

    size_t matched = 0;

    while(right < str1.size())
    {
        size_t c = static_cast<size_t>(str1[right]);
        table[c]--;

        if(table[c] >= 0)
        {
            matched++;
        }
        if(matched == str2.size())    // AAABBB   AB
        {
            while(table[pStr1[left]] < 0)
            {
                table[pStr1[left]]++;
                left++;
            }
            res = std::min(res, right - left + 1);
            table[pStr1[left]]++;
            left++;
            matched--;
        }
        right++;
    }

    if(res == std::numeric_limits<size_t>::max())
    {
        return 0;
    }

    return res;
}


int main()
{
    std::string str1;
    std::string str2;
    
    std::cin >> str1;
    std::cin >> str2;

    auto res = minLength(str1, str2);

    std::cout << res << "\n";

    return 0;
}


发表于 2020-08-04 21:21:40 回复(0)

 
public int minLength(String str1, String str2){
          if(str1 == null || str2 ==null || str1.length() < str2.length()){
            return 0;
        }
        char[] chas1 = str1.toCharArray();
        char[] chas2 = str2.toCharArray();
        int[] map = new int[256];
        for (int i=0; i< chas2.length; i++){
            map[chas2[i]]++;
        }
        int left= 0;
        int right = 0;
        int minLen =Integer.MAX_VALUE;
        int match =chas2.length;
        while (right != chas1.length){
            map[chas1[right]]--;
            if(map[chas1[right]] >= 0){
                match--;
            }
            if(match == 0){
                while (map[chas1[left]] < 0){
                    map[chas1[left++]]++;
                }
                minLen = Math.min(minLen, right - left + 1);
                match++;
                map[chas1[left++]]++;
            }
            right++;
        }
        return minLen == Integer.MAX_VALUE ? 0 :minLen;
}
 
    


发表于 2020-07-24 19:06:42 回复(0)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int hhash[256];
char str1[100010],str2[100010];
int main(){
    while(~scanf("%s %s",str1,str2)){
    fill(hhash,hhash+256,0);
    for(int i=0;i<strlen(str2);++i){
        hhash[str2[i]]++;
    }
    int len1=strlen(str1),len2=strlen(str2);
    int maxlength=999999;
    int left=0,right=0,match=len2;
    for(int i=0;i<len1;++i){
        hhash[str1[i]]--;
        if(hhash[str1[i]]>=0){
            match--;
            if(match==0){
                while(hhash[str1[left]]<0)
                {
                    hhash[str1[left]]++;
                    left++;
                }
                if((right-left+1)<maxlength)
                    maxlength=right-left+1;
                hhash[str1[left]]++;
                left++;
                match++;
            }
        }
        right++;
    }
    printf("%d",maxlength==999999?0:maxlength);
}
    return 0;
}

编辑于 2020-04-10 23:40:33 回复(0)

问题信息

上传者:小小
难度:
11条回答 8255浏览

热门推荐

通过挑战的用户

查看代码