leetcode 466. Count The Repetitions

466. Count The Repetitions

Hard

10279FavoriteShare

Define S = [s,n] as the string S which consists of n connected strings s. For example, ["abc", 3] ="abcabcabc".

On the other hand, we define that string s1 can be obtained from string s2 if we can remove some characters from s2 such that it becomes s1. For example, “abc” can be obtained from “abdbec” based on our definition, but it can not be obtained from “acbbe”.

You are given two non-empty strings s1 and s2 (each at most 100 characters long) and two integers 0 ≤ n1 ≤ 106 and 1 ≤ n2 ≤ 106. Now consider the strings S1 and S2, where S1=[s1,n1] and S2=[s2,n2]. Find the maximum integer M such that [S2,M] can be obtained from S1.

Example:

Input:
s1="acb", n1=4
s2="ab", n2=2

Return:
2

我发现我做题思路有点偏了。思路侧重于寻找特殊规律而不是一般规律,结果自然而然是不能AC。

这道题的暴力方法很简单,就是s1和s2循环遍历,每次遍历s1下标+1;只有当s1[i]==s2[j]时j++;如果i==len1;i=0;如果j==len2,则找到的次数加+1;时间复杂度是O(len1*n1);

因为[s1,n1]这个字符串是s1的n1次重复,所以有一些重复的模式在里面,主要是找到这个重复的模式,就可以省去重复模式的遍历;

举个例子:

                    0 1    2 3 0      1    2 3 0      1    2 3 0  
S1 --------------> abacb | abacb | abacb | abacb | abacb | abacb 

repeatCount ----->    0  |   1   |   1   |   2   |   2   |   3

Increment of 
repeatCount     ->    0  |   1   |   0   |   1   |   0   |   1

nextIndex ------->    2  |   1   |   2   |   1   |   2   |   1
                                     ^
									 |
									 repetitive pattern found here (we've met 2 before)!
									 The pattern repeated 3 times

所以只要当某个nextindex出现第二次,就可以判断重复模式出现。

所以n1段s1可以分为prefixseg,repeatseg,suffixseg.

这里有个小技巧:将哪几段划分为重复模式?假设第k段的nextindex在第i段已经出现过一次, 我第一次的做法是将[i,k-1]段划为重复模式,当计算repeatseg的不同part时第一part和第二part的重复次数不一样。

第一part为[i,k-1]  重复次数 = repeatcnt[k-1] - repeat[i-1];

第二part为[k,2k-i-1] 重复次数 = repeatcnt[2k-i-1] - repeatcnt[k-1];

第三part为[2k-i,3k-2i-1] 重复次数 = repeatcnt[3k-2i-1] - repeatcnt[2k-i-1];

因为nextindex[i-1]≠nextindex[k-1]=nextindex[2k-i-1]

所以repeatcnt[i]-repeatcnt[i-1] ≠repeatcnt[k]-repeatcnt[k-1]=repeatcnt[2k-i]-repeatcnt[2k-i-1];

所以不能将[i,k-1]划为重复模式,而是将[i+1,k]划为重复模式;

在判断第k段的nextindex是否已经出现过的时候,需要查找之前的nextindex,如果是向量的话,查找次数为O(n),这里可以采用哈希表(unordered_map)可以在O(1)时间内找到。

class Solution {
public:
    int getMaxRepetitions(string s1, int n1, string s2, int n2) 
    {
        int len1 = s1.size();
        int len2 = s2.size();
        unordered_map<int,int> repeatcnt;
        unordered_map<int,int> nextindex;
        int j = 0, cnt =0;
        int prefixcnt = 0, middlecnt = 0, suffixcnt = 0; 
        for(int k=1;k<=n1;k++)
        {
            for(int i=0;i<len1;i++)
            {
                if(s1[i]==s2[j])
                    j++;
                if(j == len2)
                {
                    j = 0;
                    cnt++;
                }   
            }
            if(nextindex.count(j) > 0 )
            {
                int i = nextindex[j];
                prefixcnt = repeatcnt[i];
                middlecnt = (n1-i)/(k-i)*(cnt-repeatcnt[i]);
                suffixcnt = repeatcnt[i+(n1-i)%(k-i)] - repeatcnt[i];
                return (prefixcnt+middlecnt+suffixcnt)/n2;
            }
            repeatcnt[k] = cnt;
            nextindex[j] = k;            
        }
        return repeatcnt[n1]/n2;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值