第五周作业2(LeetCode76)

1. 题目描述(LeetCode76)

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = “ADOBECODEBANC”
T = “ABC”

Minimum window is “BANC”.

Note:
If there is no such window in S that covers all characters in T, return the emtpy string “”.

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

2. 解决思路

这道题真的好绕,跟实验室同学讨论了一个晚上,具体思路就看下面的代码注释吧……

3. 完整代码

#include <stdio.h>
#include <malloc.h>
#include<string.h>


int main()
{

    char S[4096];  //定义很大的数组,为了方便就不用动态分配了。
    char T[4096];  
    int mTable[256] = { 0 };  //用来代替哈希表,key是字符的ascii码(包括扩展码也不会超过256),直接一一映射到数组的下标


    int Sn = 0; //字符串S的长度
    int Tn = 0; //字符串T的长度

    printf("请输入字符串S,按回车结束:\n");
    char c;
    while (true)
    {
        c = getchar();
        if (c == '\n')  //回车结束输入
        {
            S[Sn] = '\0'; //给字符串增加结束标志
            break;
        }
        S[Sn] = c;
        Sn += 1;
    }
    printf("你输入的字符串S:%s\n", S);

    printf("请输入要查找的子串T,按回车结束:\n");
    while (true)
    {
        c = getchar();
        if (c == '\n')  //回车结束输入
        {
            T[Tn] = '\0'; //给字符串增加结束标志
            break;
        }
        T[Tn] = c;
        Tn += 1;
    }
    printf("你输入的字符串T:%s\n", T);


    for (int i=0; i< Tn; i++)  //遍历T,填充Hash表
    {
        int ascci = T[i];  //获取字符的ascci码,转成整型
        mTable[ascci] += 1;  //直接将ascci码映射成下标,并改变value
    }


    int tempTable[256];  //临时的哈希表,否则对原哈希表的值进行减一操作将破坏原有数据需要反复填充
    memcpy(tempTable,mTable,sizeof(int) * 256); //将哈希表的内存拷贝给临时表,相当于对数组遍历赋值


    int minBegin = 0; int minEnd = 0;  //用来存储最短子串在S中的开始结束
    int minNum = 0;  //用来记录当前子串的长度。

    int begin = 0; int end = 0; //当前遍历子串的开始结束位置
    for (end = begin; end< Sn; end++) //遍历S
    {
        int ascci = S[end];  //获取字符的ascci码,转成整型
        if (mTable[ascci] > 0)  //字符在T中存在(T[ascci]这里利用哈希表的映射功能,直接根据值大于0来确定,不需要反复遍历T来确定一个字符是否在T中存在)
        {

            tempTable[ascci] -= 1;  //把对应哈希表的值减一,这里我们操作临时的哈希表,原表始终不改变
            bool bend = true;
            for (int j=0; j<256; j++)  //由于此哈希表的长度固定,循环是常数级
            {
                //如果哈希表中所有值都小于等于0,说明所有字符已经包含在当前S子串
                if (tempTable[j] > 0)   //只要有一个还大于0,子串就没有被全部包含,也就是没有结束
                {
                    bend = false;
                    break;
                }               
            }

            if (bend)  //找到一个能够包含所有T中字符的子串
            {
                ascci = S[begin];
                while(tempTable[ascci] < 0 || mTable[ascci] == 0) // tempTable中的值小于0,说明字符出现次数大于字串被减成负的, mTable中的值等于0,说明不在字串中,这时可以将开始位置右移
                {
                    begin += 1;
                    ascci = S[begin];
                }

                if(minNum == 0 || minNum >( end - begin))
                {
                    minNum = end - begin;
                    minBegin = begin;
                    minEnd = end;
                }


                begin += 1;
                end = begin;
                memcpy(tempTable,mTable,sizeof(int) * 256); //将哈希表的内存拷贝给临时表,从新的位置重新遍历

            }

        }

    }


    //输出结果
    for (int i=minBegin; i<= minEnd; i++)
    {
        printf("%c", S[i]);
    }



    scanf("%d", &c);  //加个输入让窗口停下来

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值