首页 > 试题广场 >

寻找最小子字符串

[编程题]寻找最小子字符串
  • 热度指数:1831 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

小美和小团在玩一个游戏,小美任意给出一个大字符串str1以及一个独立的小字符串str2,小团需要从这个大字符串str1里找到包含独立小字符串str2中所有字符的最小子字符串str3;
例如,小美给出一个大字符串"meituan2019"和一个子字符串"i2t",那么小团给出的答案就应该是"ituan2";

需要注意:
1、str1中有可能没有完整包含str2所有字符的情况,此时返回"",即为空字符串;
2、str1不会为空,但str2有可能为空,此时返回整个str1;
3、str2可能存在重复的字符,此时str3需要包含相等数量该字符;

示例1

输入

"meituan2019","i2t"

输出

"ituan2"

备注:
str1,str2 的长度均不超过100
class Solution:
    def getMinString(self , str1 , str2 ):
        # write code here
        if not str2:return str1
        minindex = len(str2)
        maxindex = 0
        flag = 0
        str3 = list(str1).copy()
        for i in str2:
            if i in str3:
                flag += 1
                minindex = min(str3.index(i),minindex)
                maxindex = max(str3.index(i),maxindex)
                str3[str3.index(i)] = " "
        return str1[minindex:maxindex+1]if flag == len(str2) else ""
发表于 2020-09-01 10:31:14 回复(1)
class Solution:
    def getMinString(self , str1 , str2 ):
        # write code here
        str1l=list(str1)
        str2l=list(str2)
        if len(str2)==0:
            return str1
        tmp1=str1l.copy()
        p=[]
        for i in range(len(str2)):
            x=0
            for j in range(len(str1)):
                if tmp1[j]==str2l[i]:
                    p.append(j)
                    tmp1[j]=" "
                    x=1
                    break
            if x==0:
                return ""
        return(str1[min(p):max(p)+1])

用列表存,暴力遍历对应字符所在位置,完事
发表于 2020-03-13 14:57:28 回复(4)
[Python3] 感觉有点复杂,但还没想出来怎么简化
1. 双指针动态列表法
class Solution:
    def isOk(self, ch, list1, list2):
        list1.remove(ch)
        for i in list2:
            if i in list1:
                list1.remove(i)
            else:
                return False
        return True
        
    def getMinString(self , str1 , str2 ):
        if not str2:
            return str1
        list1, list2 = list(str1), list(str2)
        res, left, right = "", 0, len(str1)-1
        while right-left >= len(str2)-1:
            if self.isOk(str1[left], list1[:], list2[:]):
                list1.remove(str1[left])
                left += 1
                res = str1[left:right+1]
            elif self.isOk(str1[right], list1[:], list2[:]):
                list1.remove(str1[right])
                right -= 1
                res = str1[left:right+1]
            else:
                return res
2.双指针动态字典法
import collections
import copy

class Solution:
    def isOk(self, ch, d1, d2):
        d1[ch] -= 1
        for i in d2:
            if d2[i] > d1.get(i, 0):
                return False
        return True
        
    def getMinString(self , str1 , str2 ):
        # write code here
        if not str2:
            return str1
        dict1, dict2 = collections.Counter(str1), collections.Counter(str2)
        res, left, right = "", 0, len(str1)-1
        while right-left >= len(str2)-1:
            if self.isOk(str1[left], copy.deepcopy(dict1), copy.deepcopy(dict2)):
                dict1[str1[left]] -= 1
                left += 1
                res = str1[left:right+1]
            elif self.isOk(str1[right], copy.deepcopy(dict1), copy.deepcopy(dict2)):
                dict1[str1[right]] -= 1
                right -= 1
                res = str1[left:right+1]
            else:
                return res


发表于 2021-07-26 10:42:11 回复(0)
python 代码在此:
python版本
# 寻找最小子串
str1,str2=input().split('","')
str1=str1.replace("\"","")
str2=str2.replace("\"","")
str_set=[]
for i in range(0,len(str2)):
    str_set.append(str2[i])
save=[]
i=0
j=0
flag=False
while(i<len(str1) and j<len(str2)):
    if(str1[i] in str_set): # 遇到子串元素
        save.append(str1[i])
        str_set.remove(str1[i]) # 待查找集合中 删掉该元素
        flag=True
        j+=1
    elif flag:
        save.append(str1[i])
    i+=1
if len(str2)==0:
    print("\""+str1+"\"")
elif j!=len(str2):
    print("\"\"")
else:
    string='"'
    for ch in save:
        string=string+ch
    print(string+"\"")



编辑于 2020-04-14 18:02:26 回复(1)
public String getMinString (String str1, String str2) {
        // write code here
        if(str2==null||str2.length()==0){ return str1;}
        int[] strA = new int[128];
        int[] strB = new int[128];
        int left = 0,right = 0;
        for(int i=0;i<str1.length();i++){
            strA[str1.charAt(i)]++;
        }
        for(int i=0;i<str2.length();i++){
            strB[str2.charAt(i)]++;
        }
        // 没有完全包含所有字符,str2中有个字符多了几个或一个。
        for(int k=0;k<str2.length();k++){//str.charAt()
            if(strA[str2.charAt(k)]<strB[str2.charAt(k)]){
                return "";
            }
        }
        //find left
        for(int k=0;k<str1.length();k++){
            //保证相同数目的字符在范围内
            if(--strA[str1.charAt(k)]<strB[str1.charAt(k)]){
                left=k;
                break;
            }
        }
        for(int k=str1.length()-1;k>=0;k--){
            if(--strA[str1.charAt(k)]<strB[str1.charAt(k)]){
                right=k;
                break;
            }
        }

        return str1.substring(left,right+1);
    }


既然是包含它的最小子序列,那么序列的左右两边必定包含str2的字符

1.     自己构建hash函数表,记录每个单词出现的次数。

2.     找出特殊情况,str2中某个字符的数量,少于str1中。

3.     找出left,right

str1=aaabbc    str2=aab     [--3<2 index=0]    [--2<2 index=1=left]

str1=abbcd      str2=bbc    [--1<0 index=0]    [--2<2 index=1=left ]

left满足 str1当前字符在str2中,并且str1当前字符在右边的数量小于当前字符在str2中的数量.  --strA[ str1.charAt(k) ]<strB[ str1.charAt(k) ]

发表于 2020-04-02 12:32:08 回复(3)
class Solution:
    def getMinString(self, str1, str2):
        if str2:
            index_list = []
            for letter in str2:
                _index = str1.find(letter)
                if _index in index_list:
                    _index = str1.find(letter, _index + 1)
                index_list.append(_index)
            result = str1[min(index_list):max(index_list) + 1]
            if -1 in index_list:
                result = ""
        else:
            result = str1
        print(result)

发表于 2023-10-18 21:28:44 回复(0)
classSolution:
    def getMinString(self , str1 , str2 ):
        # write code here
        ifstr2 == '':
            returnstr1
 
        str1l=list(str1)
        str2l=list(str2)
 
        tmp1=str1l.copy()
        p=[]
        fori in range(len(str2)):
            exist_signal=0
            forj in range(len(str1)):
                iftmp1[j]==str2l[i]:
                    p.append(j)
                    tmp1[j]=" "
                    exist_signal=1
                    break
            ifexist_signal==0:
                return""
        return(str1[min(p):max(p)+1])
发表于 2023-08-11 22:28:39 回复(1)
class Solution:
    def getMinString(self , str1 , str2 ):
        # write code here
        if not str2:
            return str1
        dic = {}
        for char in str2:
            dic[char] = dic.get(char, 0) + 1
        indexes = []
        for key, value in dic.items():
            if str1.count(key) < value:
                return ''
            index_ = -1
            for _ in range(value):
                index_ = str1.index(key, index_+1)
            indexes.append(index_)
        return str1[min(indexes):max(indexes) + 1]


编辑于 2023-05-30 17:00:35 回复(0)
思路:首先判断str2是否空,空直接打印str1,非空继续,遍历str2,若字符不在str1内赋值s='',若在里面,将字符在str1上的序数添加到序数列表内,并将str1内的对应字符变为*,以便于重复字符出现时的计数,循环结束后找到序列列表内的最大数和最小数,对str1进行切片
str1,str2=input().split('","')
str1=str1.replace("\"","")
str2=str2.replace("\"","")
x=list(str1)
if not str2:
    print('"{}"'.format(str1)) 
else:
    list_num=[]
    for str in list(str2):
        if str not in x:
            s=''
        else:
            y=x.index(str)
            list_num.append(y)
            x[y]='*'
            a=min(list_num)
            b=max(list_num)
            s=str1[a:b+1]
    print('"{}"'.format(s))
发表于 2022-12-20 15:04:14 回复(0)
import re from functools import reduce def list_combination(lists,code=''): def myfunc(list1, list2): return [str(i) + code + str(j) for i in list1 for j in list2] return reduce(myfunc, lists)
n = []
str_temp = str1 = input()
str2 = input()
a = 0 for i in str2: if i in str_temp:
        a += 1  str_temp = str_temp.replace(i, '') if str2 == '': print(str1) elif len(str2) > a: print(' ') else: for i in str2:
        m = [] for h in re.finditer(i, str1):
            x = h.start()
            m.append(x)
        n.append(m) # print(n)  # print('常见写法结果:\n', list_combination(n, '+'))  # 排列结果用+连接  result = list_combination(n, '+') # print(result)  res = [] for i in result:
        temp = list(map(int,i.split('+')))
        a = max(temp) - min(temp) + 1  b = [a,i]
        res.append(b) print(res)
    x = int(res[0][0])
    y = res[0][1] for i in res: if int(i[0]) < x:
            x = i[0]
            y = i[1] # print(y)  temp = list(map(int, y.split('+')))
    a = max(temp) + 1  b = min(temp) print(str1[b:a])
发表于 2022-07-07 15:47:07 回复(0)
def minwindow(s1,s2):
    if s2 is None:
        return s1
    need,window=defaultdict(int),defaultdict(int)
    left,right,vaild=0,0,0
    start,curlen=0,float('inf')
    for i in s2:
        need[i]+=1
    while right<len(s1):
        c=s1[right]
        right+=1
        if c in s2:
            window[c]+=1
            if window[c]==need[c]:
                vaild+=1
        while vaild==len(need):
            if right-left<curlen:
                curlen=right-left
                start=left
            d=s1[left]
            left+=1
            if d in s2:
                if need[d]==window[d]:
                    vaild-=1
                window[d]-=1
    if curlen==float('inf'):
        return ""
    else:
        return s1[start:start+curlen] 

发表于 2022-03-30 10:42:02 回复(0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int inStr(char c, char *str) {
    char *p = str;
    int i = 0;
    while('\0' != *p) {
        if (*p == c) {
            return i;
        }
        p ++;
        i ++;
    }
    return -1;
}

void printSubStr(char *str, int start, int end) {
    char *p = str;
    for (int i = start; i <= end; i ++) {
		printf("%c", str[i]);
    }
}

int findMinSubStr(char *s, char *t, int *start, int *end) {
    
    char *sp = s;
    
    size_t sLen = strlen(s);
    size_t tLen = strlen(t);
    
    unsigned long long bitmaps[sLen];
    memset(bitmaps, 0, sizeof(unsigned long long) * sLen);
    int positions[sLen];
    int substrMap[sLen];
    int minLen = 0;
    int minPos = 0;
    
    int i = 0, k = 0;

    while ('\0' != *sp) {
        unsigned int pos = inStr(*sp, t);
        if (-1 != pos) {
//            printf("find s[%d]=%c\n", i, *sp);  // 4debug
            positions[k] = i;
            for (int j = 0; j <= k; j ++) {
                if (substrMap[positions[j]] > 0) {	// already find a Min-Length-Substr started from j
//                    printSubStr(s, positions[j], substrMap[positions[j]]); printf(" is already a substr!\n"); // 4debug
                    continue;
                }
            	bitmaps[positions[j]] |= (1 << pos);	// update every bitmap
                if (bitmaps[positions[j]] == (1 << tLen) - 1) {	// find a substr
                    substrMap[positions[j]] = i;	// recode this Min-Length-Substr end position by start position indexing
                    if (i - positions[j]+ 1 < minLen || minLen == 0) {
                        minPos = positions[j];	// update Min-Length-Substr start position
                        minLen = i - positions[j]+ 1;	// update min length
                    }
//                    printSubStr(s, positions[j], i); printf(" is a new substr! (minPos=%d, minLen=%d)\n", minPos, minLen); // 4debug
                }
            }
            k ++;
//            printf("\n");   // 4debug
        }
        sp ++, i ++;
    }
    if (minLen == 0) {
	    return -1;
    }
    *start = minPos;
    *end = substrMap[minPos];
    return 0;
}

int main() {
    char s[1024], t[64];
    scanf("%s\n%s", s, t);
    int start, end;
    if (0 == findMinSubStr(s, t, &start, &end)) {
    	printSubStr(s, start, end);
    }
    printf("\n");
    return 0;
}

发表于 2021-08-27 16:01:21 回复(0)
#

# @param str1 string字符串 
# @param str2 string字符串 
# @return string字符串
#
class Solution:
    def getMinString(self , str1 , str2 ):
        # write code here
        if len(str2)==0:
            return str1
        has={}
        for idx,char in enumerate(str1):
            if char not in has:
                has[char]=[]
                (has[char]).append(idx)
            else:
                (has[char]).append(idx)
        dd=[]
        for i in str2 :
            if i in has.keys():
                dd+=has[i]
        if len(set(dd))!=len(str2):
            return ""
        dd.sort()
        left=dd[0]
        right=dd[-1]
        strs=str1[left:right+1]
        return strs
发表于 2021-03-22 20:36:25 回复(0)
为啥我在本机都调通了,在这里没校验通过
发表于 2021-01-07 20:47:09 回复(0)
#
# 
# @param str1 string字符串 
# @param str2 string字符串 
# @return string字符串
#
class Solution:
    def getMinString(self , str1 , str2 ):
        # write code here
        if str2 == "":
            return str1
        elif len(str2) > len(str1):
            return ""
        results = []
        result = []
        ls = []
        str2t = str2
        i = 0
        append = False
        while i < len(str1):
            if str1[i] in str2t:
                append = True
                str2t = str2t.replace(str1[i], "", 1)
                if str2t == "":
                    result.append(str1[i])
                    results.append(result)
                    ls.append(len(result))
                    str2t = str2
                    result = []
                    append = False
            if append:
                result.append(str1[i])
            i += 1
        if len(results) == 0:
            return ""
        else:
            minl = min(ls)
            for i in results:
                if len(i) == minl:
                    return "".join(i)

发表于 2020-09-26 22:45:10 回复(0)
str1 = str(input("输入大字符串:"))
str2 = str(input("输入小字符串:"))
str_set=[]
save = str("")
if (len(str2)==0):
    print(str1)
    
else:    
    for i in range(len(str1)):
        for j in range(len(str2)):
            if(str1[i]==str2[j]):
                str_set.append(i)            
    if (len(str_set)<len(str2)):
        print("")
    else:

        min = str_set[0]
        max = str_set[int(len(str_set))-1]
        for k in range(min ,max+1):
            save = save + str1[k]

        print(save)
        
发表于 2020-09-14 16:18:30 回复(0)
#输入“abbbbasa”,“asa”,输出应该是什么?🤔🤔
#
#
# @param str1 string字符串
# @param str2 string字符串
# @return string字符串
#
def getlistitem(str1, str2):
    str3=str1
    index_list=[]
    try:
        for item in str2:
            n=str3.index(item)
            str3=str3[0:n]+" "+str3[n+1:]
            index_list.append(n)
            index_list.sort()
        return str1[index_list[0]:index_list[-1]+1]
    except:
        return ""
class Solution:

    def getMinString(self , str1 , str2 ):
        # write code here
        if str2=="":
            return str1
        outlist=[]
        try:
            for i in range(len(str1)):
                item=getlistitem(str1[i:],str2)
                if item!='':
                    outlist.append(item)
            outlist.sort(key=len)
            return outlist[0]
        except:
            return ""
编辑于 2020-09-12 16:41:55 回复(0)
import java.util.*;


public class Solution {
    /**
     * 
     * @param str1 string字符串 
     * @param str2 string字符串 
     * @return string字符串
     */
    public String getMinString (String str1, String str2) {
       // write code here
        if(str2.length() == 0) return  str1;
        int[] map = new int[128];
        for (char c : str2.toCharArray())
            map[c]++;
        int counter = str2.length(),begin = 0,end = 0,distance = Integer.MAX_VALUE,head = 0;
        while(end<str1.length()){
            if(map[str1.charAt(end++)]-- >0)counter -- ;
            while(counter==0){
                if(end - begin<distance) distance = end-(head =begin);
                if(map[str1.charAt(begin++)]++ == 0) counter++;
            }
        }
        return distance == Integer.MAX_VALUE ? "" : str1.substring(head, head + distance);
        
    }
}

发表于 2020-08-22 11:21:27 回复(0)
# python
input_str = input()

father_str = input_str.split(",")[0].split("\"")[1]
son_str = input_str.split(",")[1].split("\"")[1]

result = ""
index_list = []

for letter in son_str:
    _index = father_str.find(letter)
    if _index in index_list:
        _index = father_str.find(letter, _index+1)
    index_list.append(_index)

if len(index_list) == 0:
    result = father_str
else:
    result = father_str[min(index_list):max(index_list)+1]

if -1 in index_list:
    result = ""

print("\""+result+"\"")


发表于 2020-08-09 21:21:41 回复(0)
class Solution {
public:
    /**
     * 
     * @param str1 string字符串 
     * @param str2 string字符串 
     * @return string字符串
     */
    string getMinString(string s, string t) {
        // write code here
        if(t.size() == 0) return s;
         unordered_map<char,int> need,window;
        for(char c : t) need[c]++;

        int left = 0, right = 0;
        //表示窗口中满足need条件的字符个数,如果valid和need.size()相同,说明窗口已经满足条件,已经覆盖了T
        int vilid = 0;
        //记录最小覆盖子串的起始位置和长度
        int start = 0, len = INT_MAX;
        while(right < s.size()){
            //c 是将要移入窗口的字符
            char c = s[right];
            // 右移窗口
            right++;
            //进行窗口内的数据的一系列更新
            if(need.count(c)){
                window[c]++;
                 if(window[c] == need[c]){
                    vilid++;
                }
            }
            //判断左侧窗口是否要收敛
            while(vilid == need.size()){
                //这里更新最小的覆盖子串
                if(right - left < len){
                    start = left;
                    len = right -left;
                }
                //d 是将要移出窗口的字符
                char d = s[left];
                // 左移窗口
                left++;
                // 进行窗口内的数据的一系列的更新
                if(need.count(d)){
                    if(window[d] == need[d]){
                        vilid--;
                    }
                    window[d]--;
                }
            }
        }
        //返回最小的覆盖子串
        return len == INT_MAX ? "" :s.substr(start,len);
    }
};
发表于 2020-07-16 16:47:43 回复(0)