-
Notifications
You must be signed in to change notification settings - Fork 299
/
Copy pathZAlgorithm.cs
105 lines (91 loc) · 3.33 KB
/
ZAlgorithm.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
namespace Advanced.Algorithms.String;
/// <summary>
/// A Z-algorithm implementation for string search.
/// </summary>
public class ZAlgorithm
{
/// <summary>
/// Returns the start index of first appearance
/// of pattern in input string.
/// returns -1 if no match.
/// </summary>
public int Search(string input, string pattern)
{
var z = this.Z(pattern + input, pattern.Length);
for (var i = pattern.Length; i < z.Length; i++)
//if match length equals pattern Length + separator length
if (z[i] == pattern.Length)
//substract pattern length and separator length
return i - pattern.Length;
return -1;
}
/// <summary>
/// The z function computes the length of matching prefix at each char
/// in given input.
private int[] Z(string input, int patternLength)
{
var result = new int[input.Length];
var prefixIndex = 0;
for (var i = 1; i < input.Length; i++)
{
var k = i;
//increment prefixIndex (count of matching chars)
while (k < input.Length
&& prefixIndex < patternLength
&& input[prefixIndex] == input[k])
{
prefixIndex++;
k++;
}
//assign result
result[i] = prefixIndex;
//is prefixIndex > 1 we have a choice to use earlier values
//in result
if (prefixIndex > 1)
{
//z-box left and right
var left = i;
var right = i + prefixIndex;
prefixIndex = 1;
for (var m = left + 1; m < right; m++)
if (m + result[prefixIndex] < right)
{
result[m] = result[prefixIndex];
prefixIndex++;
}
else
{
//move left end of z box to current element
prefixIndex = result[prefixIndex];
//cannot exceed size of input
if (m + prefixIndex < input.Length)
{
//increment right end of Z box as far as match goes
while (right < input.Length
&& prefixIndex < patternLength
&& input[prefixIndex] == input[right])
{
right++;
prefixIndex++;
}
result[m] = prefixIndex;
prefixIndex = 1;
}
else
{
//since i is assigned with right below
//and i is incremented by for loop do a right--
right--;
break;
}
}
//move i to end of z box
//since i is incremented by for loop do a right - 1
i = right - 1;
}
//reset prefix Index
prefixIndex = 0;
}
return result;
}
}