• leetcode_字节跳动_挑战字符串_字符串的排列


      字符串的排列
     

    给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

    换句话说,第一个字符串的排列之一是第二个字符串的子串。

    示例1:

    输入: s1 = "ab" s2 = "eidbaooo"
    输出: True
    解释: s2 包含 s1 的排列之一 ("ba").
    

     

    示例2:

    输入: s1= "ab" s2 = "eidboaoo"
    输出: False
    

     

    注意:

    1. 输入的字符串只包含小写字母
    2. 两个字符串的长度都在 [1, 10,000] 之间

    解题思路:
    解决这个问题前可以先回顾下无排列的子串匹配问题,我们当时使用的是实现了DFA状态转移图,当匹配到不同字符时来到不同的状态,知道最终完全匹配。

    (图后补,下次一定)

    而对于有排列的子串问题,我们一样可以构建一个DFA图来实现它,在这时候相比于无排列子串匹配问题,子串的字符顺序就不重要了,思路如下:

    (图后补,下次一定)

    逐个判断长字符串字符:
    (1)不是子串字符,跳过

    (2)是子串字符且没多余重复,记录当前匹配到的长度

    (3)是子串字符但是已经多余了,比如子串“adc”,串“dcda“,第二个d是超出了子串d个数的,从第二个d这个位置往前重新匹配到dc。

    (4)若匹配到的个数已经达到子串长度,完成。

    class Solution {
    public:
        bool checkInclusion(string s1, string s2) {
            
            int len_s1 = s1.length();
            int len_s2 = s2.length();
            if(len_s1>len_s2) return false;
            if(len_s1==0) return true;
            if(len_s1==1){
                for(int i=0;i<len_s2;i++){
                    if(s1[0]==s2[i]) return true;
                }
                return false;
            }
            
            int size[26];//子串字符统计
            int size_tmp[26];//临时子串已用字符统计
            memset(size,0,sizeof(int)*26);
            memset(size_tmp,0,sizeof(int)*26);
                
            map<char,int> mp;
            for(int i=0;i<len_s1;i++){
                mp.insert(pair<char,int>(s1[i],i));//map容器储存,方便查找
                size[s1[i]-'a']++;//记录个数
            }
            
            int len=0;
            
            for(int i=0;i<len_s2;i++){
                //不是子串字符重置跳过
                if(mp.find(s2[i])==mp.end()){
                    len=0;
                    memset(size_tmp,0,sizeof(int)*26);
                    continue;
                }
                
                //是子串字符,判断是否多余出现
                //  cout<<s1[j]<<"--"<<s2[i]<<endl;
                    if(size_tmp[s2[i]-'a']<size[s2[i]-'a']){//存在且还有可用空间
                        len++;
                        size_tmp[s2[i]-'a']++; 
                    }
                    else if(size_tmp[s2[i]-'a']==size[s2[i]-'a']){//没有可用空间了,说明重复了子串一个字符
                       /**当前字符是s1中已经访问过的字符,则往前重新访问记录到无法继续访问**/
                       len=0;
                       memset(size_tmp,0,sizeof(int)*26);
                       int z;
                       for(int z=i;z>=0;z--){
                           if(mp.find(s2[z])==mp.end()) break;//不是子串内容退出
                              
                           if(size_tmp[s2[z]-'a']<size[s2[z]-'a']){//存在且有容量
                                len++;
                                size_tmp[s2[z]-'a']++;
                           }
                           else if(size_tmp[s2[z]-'a']==size[s2[z]-'a']) break; //没有容量了
                       }
                    }
                if(len==len_s1) return true;
            }
            return false;
        }
    };

    此处可以不用map容器,只是一开始查找想到了map,后来规定状态才想到了数组。

    最好的开始时间是以前,其次是现在。
  • 相关阅读:
    asp.net mvc在Model中控制日期格式
    MVC3.0删除数据的时候给提示信息
    Jquery的鼠标移动上去显示div,鼠标离开的时候隐藏div效果
    数据库的日志数据库(_log.ldf)文件太大,如何压缩
    如何在加载数据的时候给一个等待动画
    Div内部的内容超出部分显示省略号(仅仅只有一行内容)
    IIS7.0提示---无法识别的属性“targetFramework”。请注意属性名称区分大小写。
    如何用Jquery判断在键盘上敲的哪个按键
    Split()的简单的用法
    oracle AWR报告
  • 原文地址:https://www.cnblogs.com/dragonsbug/p/13286226.html
Copyright © 2020-2023  润新知