跳到主要内容

東京大学 情報理工学系研究科 コンピュータ科学専攻 2019年8月実施 専門科目I 問題3

Author

zephyr

Description

In this problem, the length of a string ss is written l(s)l(s), and the ii-th character of ss is written s[i]s[i], where the first character is s[0]s[0]. The string obtained by removing the first ii characters from ss is written s+is + i. We assume 0i<l(s)0 \leq i < l(s) in s[i]s[i] and s+is + i. For example, if s=PROBLEMs = \text{PROBLEM}, then s[0]=Ps[0] = \text{P} and s+3=BLEMs + 3 = \text{BLEM}. The set of characters consists of NN characters, where NN is an integer constant no less than 2, and for each character cc a distinct positive integer numval(c)N\text{numval}(c) \leq N is defined. Suppose that the computation of s+is + i for given ss and ii, and that of numval(c)\text{numval}(c) for given cc, take O(1)O(1) time. Also suppose that each of integer addition, multiplication and remainder takes O(1)O(1) time, and that overflow will never occur in integer operations.

We consider the following problem FIND: For given strings pp and ss, find the first position ii at which ss matches pp. In other words, ii is the least non-negative integer that satisfies

j{0,1,,l(p)1}.s[i+j]=p[j].\forall j \in \{0, 1, \dots, l(p) - 1\}. \, s[i + j] = p[j].

In case there is no such ii, we define i=1i = -1. In the following, we assume l(s)>l(p)>0l(s) > l(p) > 0.

For strings rr and pp with 0<l(p)l(r)0 < l(p) \leq l(r), let function eq(r,p)\text{eq}(r, p) return 1 if the first l(p)l(p) characters of rr equal pp, and return 0 otherwise. Suppose that the time complexity of eq(r,p)\text{eq}(r, p) is O(l(p))O(l(p)). The following algorithm SS solves the problem FIND:

for (i = 0; i <= l(s) - l(p); i++)
if (eq(s + i, p) == 1)
return i;
return -1;

Answer the following questions.

(1) Express the order of the worst-case time complexity of algorithm SS in terms of l(s)l(s) and l(p)l(p).

In the following, the hash value h(s,m)h(s, m) of the first mm characters of string ss is defined by

h(s,m)=(i=0m1numval(s[i])dmi1)modq,h(s, m) = \left(\sum_{i=0}^{m-1} \text{numval}(s[i]) \cdot d^{m-i-1}\right) \mod q,

where dd and qq are positive integer constants, and 0<ml(s)0 < m \leq l(s) is assumed.

(2) Assume that i<l(s)mi < l(s) - m holds, and that h=h(s+i,m)h' = h(s + i, m) and dm=dm1d_m = d^{m-1} have been precomputed. Show an algorithm or an expression to compute h(s+i+1,m)h(s + i + 1, m) in O(1)O(1) time.

(3) Give an algorithm H0H_0 that finds the least non-negative integer ii that satisfies h(p,l(p))=h(s+i,l(p))h(p, l(p)) = h(s + i, l(p)) (but answers 1-1 if no such ii exists) in time O(l(s)+l(p))O(l(s) + l(p)). Also, answer in what condition the algorithm H0H_0 outputs a value which is not the solution of problem FIND.

(4) Give an algorithm HH that satisfies all of the following conditions: (a) it always answers the solution of problem FIND, (b) it searches for the answer by using hash h(s,m)h(s, m) and function eq(r,p)\text{eq}(r, p), and (cc) if we assume that the number of integers ii that satisfy h(p,l(p))=h(s+i,l(p))h(p, l(p)) = h(s + i, l(p)) for given ss and pp is O(1)O(1) independently of ss and pp, then the algorithm HH runs in time O(l(s)+l(p))O(l(s) + l(p)). In addition, show in what condition the time complexity of the algorithm HH is larger than O(l(s)+l(p))O(l(s) + l(p)). Also, answer the order of the worst-case time complexity of the algorithm HH in terms of l(s)l(s) and l(p)l(p).

Kai

(1)

Algorithm SS iterates over all possible starting positions in the string ss to check if the substring of ss starting at position ii matches the pattern pp. For each starting position, the function eq(s + i, p) is called, which has a time complexity of O((p))O(\ell(p)).

Thus, the total time complexity of Algorithm SS is:

O(((s)(p)+1)(p))=O((s)(p))O((\ell(s) - \ell(p) + 1) \cdot \ell(p)) = O(\ell(s) \cdot \ell(p))

(2)

To compute h(s+i+1,m)h(s + i + 1, m) in O(1)O(1) time, we can use the rolling hash technique:

h(s+i+1,m)=((hnumval(s[i])dm)d+numval(s[i+m]))modqh(s + i + 1, m) = ((h' - \text{numval}(s[i]) \cdot d_m) \cdot d + \text{numval}(s[i+m])) \mod q

Explanation:

  • We remove the contribution of s[i]s[i] from hh'.
  • We multiply the result by dd to shift all values left.
  • We add the contribution of the new character s[i+m]s[i+m].
  • We take the modulo qq to keep the hash value in the correct range.

This computation can be done in O(1)O(1) time as all operations (subtraction, multiplication, addition, and modulo) are assumed to take constant time.

(3)

Algorithm H0H_0:

  1. Precompute h(p,(p))h(p, \ell(p)).
  2. Precompute h(s,(p))h(s, \ell(p)) and check if it matches h(p,(p))h(p, \ell(p)). If it matches, return 0.
  3. For i=1i = 1 to (s)(p)\ell(s) - \ell(p):
    • Compute h(s+i,(p))h(s + i, \ell(p)) from h(s+i1,(p))h(s + i - 1, \ell(p)) using the formula derived in Q2.
    • If h(s+i,(p))h(s + i, \ell(p)) matches h(p,(p))h(p, \ell(p)), return ii.
int H_0(string s, string p) {
int lp = ell(p);
int ls = ell(s);
int hp = h(p, lp);
int hs = h(s, lp);

if (hp == hs) return 0;

for (int i = 1; i <= ls - lp; i++) {
hs = (d * (hs - numval(s[i - 1]) * d_m) + numval(s[i + lp - 1])) % q;
if (hp == hs) return i;
}

return -1;
}

The time complexity of H0H_0 is O((s)+(p))O(\ell(s) + \ell(p)) since we are computing the hash values in constant time for each position and there are O((s))O(\ell(s)) positions.

Condition when H0H_0 does not give the correct solution: The algorithm H0H_0 only checks for hash matches. In the rare case where different strings have the same hash value (hash collision), the algorithm might mistakenly report a false match.

(4)

Algorithm HH:

  1. Precompute h(p,(p))h(p, \ell(p)).
  2. For i=0i = 0 to (s)(p)\ell(s) - \ell(p):
    • Compute h(s+i,(p))h(s + i, \ell(p)).
    • If h(s+i,(p))=h(p,(p))h(s + i, \ell(p)) = h(p, \ell(p)), then check eq(s + i, p). If eq(s + i, p) == 1, return ii.
int H(string s, string p) {
int lp = ell(p);
int ls = ell(s);
int hp = h(p, lp);
int hs = h(s, lp);

if (hp == hs && eq(s, p) == 1) return 0;

for (int i = 1; i <= ls - lp; i++) {
hs = (d * (hs - numval(s[i - 1]) * d_m) + numval(s[i + lp - 1])) % q;
if (hp == hs && eq(s + i, p) == 1) return i;
}

return -1;
}

Time Complexity:

  • Best Case: O((p))O(\ell(p)) if the first occurrence matches.
  • Average Case: If the number of hash matches (that require further checking with eq) is O(1)O(1), then the average case time complexity is O((s)+(p))O(\ell(s) + \ell(p)).
  • Worst Case: The worst-case complexity can be O((s)(p))O(\ell(s) \cdot \ell(p)) if there are many hash collisions, causing frequent calls to eq.

Condition for O((s)+(p))O(\ell(s) + \ell(p)): The time complexity will be O((s)+(p))O(\ell(s) + \ell(p)) if the expected number of hash collisions is O(1)O(1). In other words, if the hash function has good distribution and the probability of collisions is low, the algorithm runs efficiently.

Worst-case Complexity: The worst-case time complexity of algorithm HH is O((s)(p))O(\ell(s) \cdot \ell(p)) when there are many hash collisions, leading to frequent evaluations of eq.

Knowledge

字符串匹配 哈希算法 Rabin-Karp算法 复杂度分析

难点思路

此题的难点在于如何高效地计算字符串的哈希值,并利用哈希值进行匹配。在应对哈希碰撞时,我们需要进行字符串的实际比较,保证算法的正确性。

解题技巧和信息

  1. 哈希算法: 使用适当的哈希函数和模数 qq 来降低哈希碰撞的概率。
  2. 滚动哈希: 是一种高效的技术,可以在 O(1) 时间内更新哈希值。
  3. 字符串比较: 当哈希值匹配时,需要使用实际的字符串比较来确认结果。
  4. 复杂度分析: 分析算法的平均情况和最坏情况的复杂度,以便选择合适的解决方案。

重点词汇

  1. Hash Function (哈希函数): A function that maps data of arbitrary size to fixed-size values.
  2. Collision (碰撞): When two different inputs produce the same hash output.
  3. Rabin-Karp Algorithm (Rabin-Karp 算法): A string matching algorithm that uses hash values for efficient searching.
  • string matching 字符串匹配
  • rolling hash 滚动哈希
  • time complexity 时间复杂度
  • worst-case scenario 最坏情况
  • hash collision 哈希冲突

参考资料

  1. T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein, Introduction to Algorithms, 3rd Edition, Chapter 32: "String Matching".