Created
April 11, 2016 23:02
-
-
Save jianminchen/0f561b8afc1cdf23ab95a8b603cd2a3e to your computer and use it in GitHub Desktop.
String Calculate Function - HackerRank - suffixArray solution C# - still time out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Diagnostics.Contracts; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace StringCalculateFunctionSuffixArray | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
string s = Console.ReadLine(); | |
Console.WriteLine(getMaximumValue(s).ToString()); | |
} | |
public static int getMaximumValue(string s) | |
{ | |
if (s == null || s.Length == 0) return 0; | |
int n = s.Length; | |
int pValue = 1; | |
HashSet<string> set = new HashSet<string>(); | |
for (int i = 1; i <= n; i++) // substring length: i bug01: should be i<= n, not i< n | |
{ | |
int start = 0; | |
int end = i - 1; | |
while (start <= n - 1 && end <= n - 1) | |
{ | |
//string s1 = s.Substring(0, i); // bug 001 - i length of substring, but start position should vary | |
string s1 = s.Substring(start, i); | |
if (!set.Contains(s1)) // check if set has string | |
{ | |
set.Add(s1); | |
int current = i * getCountSubstringUsingSuffixArray(s1, s); | |
if (current > pValue) | |
pValue = current; | |
} | |
start++; | |
end++; | |
} | |
} | |
return pValue; | |
} | |
/* | |
* using Boyer Algorithm | |
*/ | |
private static int getCountSubstringUsingSuffixArray(string substring, string s) | |
{ | |
var sa = SuffixArray.Build(s); | |
string pat = substring; | |
sa = sa.Search(pat); | |
return sa.Count(); | |
} | |
} | |
/* | |
* source code from: | |
* https://blogs.msdn.microsoft.com/dhuba/2010/04/04/suffix-array/ | |
* | |
* April 11, 2016 | |
* | |
* Julia has to learn how to implement IEnumerable interface in a new class: SuffixArray | |
* here is the blog to read: | |
* https://msdn.microsoft.com/en-us/library/x7tax739(v=vs.110).aspx | |
* | |
* And then, | |
* public IEnumerator<int> GetEnumerator() | |
* | |
* IEnumerator IEnumerable.GetEnumerator() | |
* | |
* IEnumberable.GetEnumerator() has to be implmentated. | |
*/ | |
// Suffix array represents simple text indexing mechanism. | |
public class SuffixArray : IEnumerable<int> | |
{ | |
private const int c_lower = 0; | |
private const int c_upper = -1; | |
private readonly string m_text; | |
private readonly int[] m_pos; | |
private readonly int m_lower; | |
private readonly int m_upper; | |
SuffixArray(string text, int[] pos, int lower, int upper) | |
{ | |
m_text = text; | |
m_pos = pos; | |
// Inclusive lower and upper boundaries define search range. | |
m_lower = lower; | |
m_upper = upper; | |
} | |
/* | |
* Julia goes over the function in detail: | |
* "aaaaaa" | |
*/ | |
public static SuffixArray Build(string text) | |
{ | |
// Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(text)); | |
var length = text.Length; | |
// Sort starting positions of suffixes in lexicographical | |
// order. | |
var pos = Enumerable.Range(0, length).ToArray(); | |
Array.Sort(pos, (x, y) => String.Compare(text, x, text, y, length)); | |
// By default all suffixes are in search range. | |
return new SuffixArray(text, pos, 0, text.Length - 1); | |
} | |
public SuffixArray Search(string str) | |
{ | |
//Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(str)); | |
// Search range is empty so nothing to narrow. | |
if (m_lower > m_upper) | |
return this; | |
// Otherwise search for boundaries that enclose all | |
// suffixes that start with supplied string. | |
var lower = Search(str, c_lower); | |
var upper = Search(str, c_upper); | |
// Once precomputed sorted suffixes positions don't change | |
// but the boundaries do so that next refinement | |
// can be done within smaller range and thus faster. | |
// For example, you may narrow search range to suffixes | |
// that start with "ab" and then search within this smaller | |
// search range suffixes that start with "abc". | |
return new SuffixArray(m_text, m_pos, lower + 1, upper); | |
} | |
public IEnumerator<int> GetEnumerator() | |
{ | |
// Enumerates starting positions of suffixes that fall | |
// into search range. | |
for (var i = m_lower; i <= m_upper; i++) | |
yield return m_pos[i]; | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return GetEnumerator(); | |
} | |
/* | |
* Julia: | |
* read String.Compare example, understand this api: | |
* https://msdn.microsoft.com/en-us/library/x7tax739(v=vs.110).aspx | |
*/ | |
private int Compare(string w, int i) | |
{ | |
// Comparison takes into account maximum length(w) | |
// characters. For example, strings "ab" and "abc" | |
// are thus considered equal. | |
return String.Compare(w, 0, m_text, m_pos[i], w.Length); | |
} | |
private int Search(string w, int bound) | |
{ | |
// Depending on bound value binary search results | |
// in either lower or upper boundary. | |
int x = m_lower - 1, y = m_upper + 1; | |
if (Compare(w, m_lower) < 0) | |
return x; | |
if (Compare(w, m_upper) > 0) | |
return y; | |
while (y - x > 1) | |
{ | |
var m = (x + y) / 2; | |
// If bound equals to 0 left boundary andvances to median | |
// only // if subject is strictly greater than median and | |
// thus search results in lower bound (position that | |
// preceeds first suffix equal to or greater than | |
// subject w). Otherwise search results in upper bound | |
// (position that preceeds fisrt suffix that is greater | |
// than subject). | |
if (Compare(w, m) > bound) | |
x = m; | |
else | |
y = m; | |
} | |
return x; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment