程序问答   发布时间:2022-05-31  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了C 查找包含 s2 中所有字母的字符串 s1 的最短子串大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决C 查找包含 s2 中所有字母的字符串 s1 的最短子串?

开发过程中遇到C 查找包含 s2 中所有字母的字符串 s1 的最短子串的问题如何解决?下面主要结合日常开发的经验,给出你关于C 查找包含 s2 中所有字母的字符串 s1 的最短子串的解决方法建议,希望对你解决C 查找包含 s2 中所有字母的字符串 s1 的最短子串有所启发或帮助;

用户输入字符串 s1s2。找出字符串 s1 中包含 s2 的所有字母的最小子串。 (如果有多个相同大小,则找出出现的第一个)

示例输入:

it is raining today
dot

输出:tod

注意:我写了一个工作代码,但是我花了太多时间来弄清楚和编写,而且由于我将在测试中使用这样的示例,所以这并不好。 有没有更简单的方法?

我是如何做到的:我编写了两个函数,一个函数返回从索引 i 到索引 j 的子字符串,用于检查给定字符串,另一个函数检查子字符串是否包含所有字母。然后我使用它们通过嵌套的 for 循环找到包含所有字母的最短子字符串。

我的代码(工作):

#include <stdio.h>
#include <stdlib.h>
#include <String.h>
#include <limits.h>

const int LEN = 100;

char *subString(int beg,int end,int n,char str[n])
{
    int resultLen = abs(end - beg),i;
    char *result = malloc(sizeof(char) * resultLen);

    for (i = 0; i < resultLen; i++)
    {
        result[i] = str[i + beg - 1];
    }

    return result;
}

int doesSubstrContainAllLetters(int substrLen,int lettersLen,char substr[substrLen],char letters[lettersLen])
{
    int i,j,result = 1;
    char *containtChar;

    for (i = 0; i < lettersLen; i++)
    {
        containtChar = strchr(substr,letters[i]);

        if (containtChar == 0)
        {
            result = 0;
        }
        else
        {
            *containtChar = '+';
        }
    }

    return result;
}

int main()
{
    char s1[LEN],s2[LEN];

    gets(s1);
    gets(s2);

    int s1Len = strlen(s1);
    int s2Len = strlen(s2);
    int res,min_substrLen = INT_MAX,substrLen,i,c;

    for (i = 0; i < s1Len - 1; i++)
    {
        for (j = i + 1; j < s1Len; j++)
        {

            char *substr = subString(i,s1Len,s1);
            substrLen = strlen(substr);

            res = doesSubstrContainAllLetters(strlen(substr),s2Len,substr,s2);

            if (res == 1)
            {
                min_substrLen = (substrLen < min_substrLen) ? substrLen : min_substrLen;
            }
        }
    }

    for (i = 0; i < s1Len - 1; i++)
    {
        for (j = i + 1; j < s1Len; j++)
        {
            char *substr = subString(i,s2);

            if (res == 1 && substrLen == min_substrLen)
            {
                char *substr = subString(i,s1);
                printf("%s",substr);
                return 0;
            }
        }
    }

    return 0;
}

解决方法

你的代码有一些缺点:

  • 您不应使用 gets()
  • 您分配了大量内存却从未释放过。
  • 如果 s2 包含一个或多个 + 字符,它不会按预期工作

C 库中没有函数可以满足您的需求。

这个问题不是那么容易解决,我花了 40 分钟才得到一个我认为很可靠的实现,尽管速度不是很快。它不分配内存,但假设字节有 8 位。

这是我的代码:

#include <stdio.h>
#include <String.h>

const char *minsubstr(const char *str,const char *set,size_t *plen) {
    size_t count[256] = { 0 },cc[256];
    size_t i,n,set_len,best_len = -1;
    const char *best = NULL;
    for (i = 0; set[i]; i++) {
        unsigned char c = set[i];
        count[c]++;
    }
    set_len = i;
    if (set_len == 0) {
        best_len = 0;
        best = str;
    } else {
        for (; *str; str++) {
            if (count[(unsigned char)*str] == 0)
                conTinue;
            memcpy(cc,count,sizeof cc);
            for (i = n = 0; i < best_len && str[i]; i++) {
                unsigned char c = str[i];
                if (cc[c]) {
                    cc[c]--;
                    if (++n == set_len) {
                        if (best_len > i + 1) {
                            best_len = i + 1;
                            best = str;
                        }
                        break;
                    }
                }
            }
            if (!str[i]) {
                // no more matches
                break;
            }
        }
    }
    *plen = best_len;
    return best;
}

int main() {
    char s1[100],s2[100];
    const char *p;
    size_t len;

    if (fgets(s1,sizeof s1,stdin) && fgets(s2,sizeof s2,stdin)) {
        s1[strcspn(s1,"\n")] = '\0';  // Strip the Trailing newline
        s2[strcspn(s2,"\n")] = '\0';  // Strip the Trailing newline if any
        p = minsubstr(s1,s2,&len);
        if (p) {
            printf("%.*s\n",(int)len,p);
        } else {
            printf("no match\n");
        }
    }
    return 0;
}

这里有一种替代方法,它确实分配了一些内存,但对于小 s2 字符串应该更快:

#include <stdlib.h>
#include <String.h>

const char *minsubstr(const char *str,size_t *plen) {
    size_t i,len,set_len = strlen(set),best_len = -1;
    const char *best = NULL;
    if (set_len == 0) {
        best_len = 0;
        best = str;
    } else {
        char *buf = malloc(set_len);
        for (; *str; str++) {
            if (!memchr(set,*str,set_len))
                conTinue;
            memcpy(buf,set,len = set_len);
            for (i = 0; i < best_len && str[i]; i++) {
                char *p = memchr(buf,str[i],len);
                if (p != NULL) {
                    *p = buf[--len];
                    if (len == 0) {
                        if (best_len > i + 1) {
                            best_len = i + 1;
                            best = str;
                        }
                        break;
                    }
                }
            }
            if (!str[i]) {
                // no more matches
                break;
            }
        }
        free(buf);
    }
    *plen = best_len;
    return best;
}
,

这是一个使用直方图和滑动窗口来寻找最佳匹配的解决方案。它假设只有小写字母是感兴趣的。如果需要,可以扩展直方图以涵盖不同的字符集。它没有内存分配,运行时间为 O(n)。将 "tod" 正确识别为针头 "dot" 的正确输出的初稿花了我 31 分钟来编写,包括调试时间。

#include <stdio.h>
#include <ctype.h>
#include <String.h>

char *findMinSubString(char *haystack,char *needle,int *bestLength)
{
    int needleHistogram[26] = {0};
    int haystackHistogram[26] = {0};

    // create a histogram from the needle,keeping track of the number of non-zero entries in the histogram
    int count = 0;
    for (int i = 0; needle[i] != '\0'; i++)
        if (islower(needle[i]))
        {
            int c = needle[i] - 'a';
            needleHistogram[c]++;
            if (needleHistogram[c] == 1)
                count++;
        }

    // now look for the best subString using a sliding window
    int start = 0;
    int end = 0;
    int length = (int)strlen(haystack);
    int bestStart = -1;
    int bestEnd = length+1;
    for (;;)
    {
        if (end < length && count != 0)
        {
            // if the window doesn't contain all of the necessary letters,enlarge it by advancing the end
            if (islower(haystack[end]))
            {
                int c = haystack[end] - 'a';
                haystackHistogram[c]++;
                if (needleHistogram[c] > 0 && haystackHistogram[c] == needleHistogram[c])
                    count--;
            }
            end++;
        }
        else if (start < end && count == 0)
        {
            // if the window contains all of the necessary letters,shrink it by advancing the start
            if (islower(haystack[start]))
            {
                int c = haystack[start] - 'a';
                haystackHistogram[c]--;
                if (needleHistogram[c] > 0 && haystackHistogram[c] == needleHistogram[c]-1)
                    count++;
            }
            start++;
        }
        else
        {
            // if expanding or shrinking the window isn't an option,then we're done
            break;
        }

        // if the window contains all the necessary letters,and is smaller than the previous best,update the best
        if (count == 0 && (end - start) < (bestEnd - bestStart))
        {
            bestStart = start;
            bestEnd = end;
        }
    }

    if (bestStart >= 0 && bestEnd <= length)
    {
        // if a matching subString exists,return the length and a pointer to the beginning of the subString
        *bestLength = bestEnd - bestStart;
        return haystack + bestStart;
    }
    else
    {
        // failed,return NULL
        *bestLength = 0;
        return NULL;
    }
}

int main(void)
{
    char haystack[] = "it is raining today";
    char *needle[] = { "dot","dott","dotti","it","today","i","ii","iii","iiii","iiiii","y","yy","end",NULL };
    for (int i = 0; needle[i] != NULL; i++)
    {
        int bestLength = 0;
        char *bestString = findMinSubString(haystack,needle[i],&bestLength);
        printf("%-5s ",needle[i]);
        if (bestString != NULL)
            printf("'%.*s'\n",bestLength,bestString);
        else
            printf(" No matching subString\n");
    }
}

@H_292_3@main 有多种测试用例,包括来自问题的测试用例。程序的输出是:

dot   'tod'
dott  't is raining tod'
dotti 't is raining tod'
it    'it'
today 'today'
i     'i'
ii    'ini'
iii   'is raini'
iiii  'it is raini'
iiiii  No matching subString
y     'y'
yy     No matching subString
end    No matching subString

大佬总结

以上是大佬教程为你收集整理的C 查找包含 s2 中所有字母的字符串 s1 的最短子串全部内容,希望文章能够帮你解决C 查找包含 s2 中所有字母的字符串 s1 的最短子串所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:s1s2