1839. 所有元音按顺序排布的最长子字符串 用四种方法实现 暴力解法、动态规划、状态机、滑动窗口

原题链接

leetcode : https://leetcode-cn.com/problems/longest-substring-of-all-vowels-in-order/

解题思路

  1. 方法1 根据题目的英文提示 暴力法
    Start from each 'a' and find the longest beautiful substring starting at that index.
    Based on the current character decide if you should include the next character in the beautiful substring.
    复杂度 O(n^2) 对于len(word) > 50K 超时
  2. 方法2 动态规划, see 连续的最长递增序列
    设DP[i] 表示以word[i]结尾最长递增序列长度
  3. 方法3 滑动窗口
  • 窗口中包含的是递增序列
  • right:遍历Word即窗口扩大
  • 当检测到下降时候, left 直接等于right
  1. 方法4 状态机
    状态转移如下图,重点是要区分'a' 与other

代码

class Solution {
public:
//方法1 根据题目的英文提示  暴力法
     int method1(string word)
     {
         
// Start from each 'a' and find the longest beautiful substring starting at that index.
// Based on the current character decide if you should include the next character in the beautiful substring.
       
    //    for start in a_index:
    //         for i in range(start ,len)
    //             if word[i ] >= subStart[-1]
    //                 subStart += word[i ]
    //             else break;
    // e.g    aeiaaio  aaaaeiiiiouuu  ooaauuaeiu
    int res=0;
    //O(n^2) 对于len(word) > 50K 超时
    std::map<char,int> tbl={{'a',0},{'e',1},{'i',2},{'o',3},{'u',4}};
     for(int start =0; start< word.size(); start++ )
     {
         if(word[start] == 'a')
         {
             string subStr="a";
             for (int i=start+1;i<word.size();i++)
             {
              if(subStr[subStr.size()-1] ==word[i] ||  tbl[subStr[subStr.size()-1]] +1 == tbl[word[i]]   )   subStr += word[i];
              else break;
             }

            if(subStr[subStr.size()-1] == 'u' && res < subStr.size() ) res= subStr.size();
            
            //std::cout<< subStr << std::endl;
         }
     }

     return res;
        //    aei
        // aaio
        // aio
        // aaaaeiiiiouuu
        // aaaeiiiiouuu
        // aaeiiiiouuu
        // aeiiiiouuu
        // aauu
        // auu
        // aeiu
     
     }
//方法2 动态规划 see 连续的最长递增序列
      int method2(string word)
      {
            //  设DP[i] 表示以word[i]结尾最长递增序列长度  
            //A =|= B 表示   A与B相等 或 B-1=A
            // if word[i+1]  =|= word[i]  : DP[i+1] = DP[i]+1
            // else DP[i+1] = 1 
            
        //      a a e a e u
        //   dp 1 2 3 1 2 1  
           
         // 从左往右进行遍历
         int res=0;
         std::vector<int> dp(word.size(),1);
         std::map<char,int> tbl={{'a',0},{'e',1},{'i',2},{'o',3},{'u',4}};
         for(int i=1;i<word.size();i++)
         { 
              
             if(word[i-1] ==word[i] ||  tbl[word[i-1]] +1 == tbl[word[i]]   )
             {
                 dp[i] = dp[i-1]+1;
                 //递增序列不光记得结束点是u,起始是a也要要考虑
                 if(  word[i+1-dp[i]]=='a' &&   word[i]=='u' && res < dp[i] ) res= dp[i];
             }else
             {
                 dp[i] =1;
             }
         }
        //  for(auto c: word)  std::cout <<c<< " "; std::cout<<std::endl;
        
        //  for(auto x : dp) std::cout<< x <<" "; std::cout<<std::endl;
         return res;
//e.g "aeiaaioaaaaeiiiiouuuooaauuaeiu"
        //  a e i a a i o a a a a e i i i i  o  u  u  u o o a a u u a e i u 
        //  1 2 3 1 2 1 2 1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 1 2 1 2 1 2 3 1 
      }
      //方法3 滑动窗口   
      int method3(string word)
      {
        //  窗口中包含的是递增序列  
        //  right:遍历Word即窗口扩大
        //  当检测到下降时候, left 直接等于right
        //e.g aeaiou
          std::map<char,int> tbl={{'a',0},{'e',1},{'i',2},{'o',3},{'u',4}};
        int left=0,right=0;
        int res=0;
        for(right=1;right<word.size();right++)
        {

             if(word[right-1] ==word[right] ||  tbl[word[right-1]] +1 == tbl[word[right]]   )
             {

             }
             else
             {
               // std::cout <<std::string(word.begin()+left ,word.begin()+right) <<std::endl;
                if(word[left]=='a' && word[right-1] == 'u' && right-left > res) res= right-left;
                left = right;
             }
        }
         //对应最后一个区块 
       //   std::cout <<std::string(word.begin()+left ,word.begin()+right) <<std::endl;
         if(word[left]=='a' && word[right-1] == 'u' && right-left > res) res= right-left;
        return res;
      }
	//方法4 状态机   
	int method4(string word)
	{
		//  设计6个状态 ,设计状态转移图 ,简化为如下表示
		//      X -> A -> E -> I  -> O -> U 

		//     X状态下 :
		//    if('a') 从X进入A res++
		//     else res=0  

		//     A 状态下:
		//     if('e' )  ->E ,res++
		//     if ('a')  in A,res++
		//     else -> X res=0
		//...
		//其他状态类似
		//...
		//U 状态  
		//     if ('u')  in U,res++
		//     else
		//     {
		//         -> X res=0
		//         //  max(res) ,收集结果
		//     } 

		//初始状态 
	
		int result = 0;
		int res = 0;
		char state ='x';
//e.g "aeiaaioaaaaeiiiiouuuooaauuaeiu"
  //stdout 0 1 2 3 1 2 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 0 1 2 0 0 1 2 3 
		//状态机的动力是 遍历Word
		for (int i = 0;  i<word.size(); i++)
		{
		  // std:cout << res << " ";
			switch (state)
			{
			case   'x':
				if (word[i] == 'a')
				{
					state = word[i];
					res++;
				}
				else
				{
					state = 'x';
					res = 0;
				}
				break;
			case   'a':
				if (word[i] == 'e' || word[i] == 'a')
				{
					state = word[i];
					res++;
				}
				else
				{
					state = 'x' ;    //只能从相邻状态去切换 
					res = 0;
				}

				break;
			case   'e':
				if (word[i] == 'e' || word[i] == 'i')
				{
					state = word[i];
					res++;
				}
				else if (word[i] == 'a')
				{
					state = word[i];
					res = 1;
				}else
                {
                      state = 'x' ;
                      res=0;
                }
				break;
			case   'i':
				if (word[i] == 'i' || word[i] == 'o')
				{
					state = word[i];
					res++;
				}
				else if (word[i] == 'a')
				{
					state = word[i];
					res = 1;
				}else
                {
                      state = 'x' ;
                      res=0;
                }
				break;
			case   'o':
				if (word[i] == 'o' || word[i] == 'u')
				{
					state = word[i];
					res++;
				}
				else if (word[i] == 'a')
				{
					state = word[i];
					res = 1;
				}else
                {
                      state = 'x' ;
                      res=0;
                }
				break;
			case   'u':
				if (word[i] == 'u')
				{
					state = word[i];
					res++;
				}
				else
				{
					//这里统计结果
					if (result < res) result = res;

                    if (word[i] == 'a')
                    {
                        state = word[i];
                        res = 1;
                    }else
                    {
                        state = 'x' ;
                        res=0;
                    }
				}
				break;
			default:
				assert(0);

			}

		}

        if(word[word.size()-1] =='u' && result < res )  result = res;


		return result;

	}


    int longestBeautifulSubstring(string word) 
    {
    return method4(word);
    }
};
posted @ 2021-04-27 16:32  boyang987  阅读(100)  评论(0编辑  收藏  举报