我们必须找到包含一些另一个字符串的字符串作为子序列的字符串的子串数。
只有当起点或终点位置不同时,子串才被认为是不同的。
String="aba"
anotherString="a"
Occurence of "a" in "aba" is as follows :
a at index 0..0
ab at index 0..1
aba at index 0..2
ba at index 1..2
a at index 2..2
i.e total of 5 times...so o/p=5
(the start and end points here, are inclusive)
我认为这个问题是“字符串中子序列的出现次数”和“查找包含另一个字符串的所有字符的字符串中的最小窗口”的应用之一。
但即使在组合代码中进行了许多更改后,我也无法提出解决方案。 粘贴我的代码没有用,因为我知道我错在哪里。我想知道的是如何在没有强力解决方案的情况下有效地解决这个问题。
代码:
public static void findLengthAndSequence(String str1,String str2){
int begin=0,biginWith=0,endWith=0,count=0,minLen=Integer.MAX_VALUE,len=0;
int l=0;
int [] hasFound=new int[256];
int [] toFound=new int[256];
for(int i=0;i<str2.length();++i){
toFound[(int)str2.charAt(i)]++;
}
for(int end=0;end<str1.length();++end){
if(toFound[(int)str1.charAt(end)]==0)
continue;
hasFound[(int)str1.charAt(end)]++;
if(hasFound[(int)str1.charAt(end)]<=toFound[(int)str1.charAt(end)]){
count++;
}
if(count==str2.length()){
l++; //add this to find number of such anagram in string
System.out.println("l= "+l+" "+begin+" "+end);
while(toFound[(int)str1.charAt(begin)]==0 || hasFound[(int)str1.charAt(begin)]>toFound[(int)str1.charAt(begin)] )
{
if(hasFound[(int)str1.charAt(begin)]>toFound[(int)str1.charAt(begin)]){
hasFound[(int)str1.charAt(begin)]-=1;
}
begin++;
}//while
len=end-begin+1;
if(minLen>len){
minLen=len;
endWith=end;
biginWith=begin;
}
}//if
}//end
for(int i=biginWith;i<=endWith;++i){
System.out.print(""+str1.charAt(i));
}
}
此代码为上述问题提供输出= 3。 我知道一旦我到达第一个字符串的末尾,我遍历剩余的子字符串后,我无法检查此中的每个子字符串。
e.g in "aba" my code checks for a,ab,aba.but once I reach the end it will not check
ba,a .since we need to count this also as they are having different index values.
除了指数时间复杂度的蛮力之外,还有什么方法可以检查每个可能的子串..
答案 0 :(得分:5)
这是一个时间复杂度O(n + m)
的简单解决方案(我假设字母大小是一个常量(其中n
是第一个字符串的长度(我们想要计算子字符串的长度)和{ {1}}是第二个字符串(anagram字符串)的长度。)我将调用一个子字符串,其中包含第二个字符串“good”的字谜。
让我们将m
定义为字符串count(x, y)
中y
个字符的出现次数。然后,当且仅当x
用于所有s
时,任意字符串t
包含字符串count(s, c) >= count(t, c)
的字谜作为子序列(证明很简单,所以我将省略它)
让我们将c
定义为最小的firstRight(L)
,以便R
子字符串是一个好字符串(可能没有这样的[L, R]
)。然后R
为所有有效firstRight(L) <= firstRight(L + 1)
(由于1.和L
函数的属性)。
声明1.暗示任何字符串都可以表示为具有count(x, y)
元素的向量,其中此向量的alphabetSize
- 元素是字符的出现次数{ {1}}。声明2.暗示我们可以使用两个指针。
所以这个算法的伪代码如下所示:
i
这里的想法是计算从固定位置开始到任何地方结束的好子串的数量,并使用两个指针,两个有效地调整右边界。此实现的时间复杂度为i
(如果我们将字母大小视为常量,则为def getCharacterVector(string s):
result = a vector filled with zeros
for c in s
result[c]++
return result
// Checks that all elements of the first vector
// are greater than or equal to the corresponding
// elements of the second vector
def isGreaterOrEqual(first, second)
for i = 0 ... length(first)
if first[i] < second[i]
return false
return true
def countSubstrings(string s, string t)
vT = getCharacterVector(t)
vS = a vector filled with zeros
right = 0
// computes firstRight(0)
while (right < length(s) and not isGreaterOrEqual(vS, vT))
vS[s[right]]++
right++
if not isGreaterOrEqual(vS, vT) // firstRight(0) is undefined
return 0 // there are no such substrings
res = length(s) - right + 1
for left = 1 ... length(s) - 1
vS[s[left - 1]]--
// computes firstRight(left)
while right < length(s) and vS[s[left - 1]] < vT[s[left - 1]]
vS[s[right]]++
right++
if vS[s[left - 1]] < vT[s[left - 1]] // firstRight(left) is undefined
break // we are done
res += length(s) - right + 1
return res
,但实际上可以通过跟踪来更有效地执行O(N * ALPHABET_SIZE + M)
计算O(N + M)
和firstRight(0)
向量中的“坏”位置,并将此向量表示为哈希表,以实现vS
复杂性,无论字母大小如何。