Function Anagram - c#

An anagram is a word formed from another by rearranging its letters, using all the original letters exactly once; for example, orchestra can be rearranged into carthorse.
I want to write a function to return all anagrams of a given word (including the word itself) in any order.
For example GetAllAnagrams("abba") should return a collection containing "aabb", "abab", "abba", "baab", "baba", "bbaa".
Any help would be appreciated.

Here is a working function, making use of a GetPermutations() extension found elsewhere on stack overflow
public static List<string> GetAnagrams(string word)
{
HashSet<string> anagrams = new HashSet<string>();
char[] characters = word.ToCharArray();
foreach (IEnumerable<char> permutation in characters.GetPermutations())
{
anagrams.Add(new String(permutation.ToArray()));
}
return anagrams.OrderBy(x => x).ToList();
}
Here is the GetPermutations() extension and it's other necessary extensions:
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> enumerable)
{
var array = enumerable as T[] ?? enumerable.ToArray();
var factorials = Enumerable.Range(0, array.Length + 1)
.Select(Factorial)
.ToArray();
for (var i = 0L; i < factorials[array.Length]; i++)
{
var sequence = GenerateSequence(i, array.Length - 1, factorials);
yield return GeneratePermutation(array, sequence);
}
}
private static IEnumerable<T> GeneratePermutation<T>(T[] array, IReadOnlyList<int> sequence)
{
var clone = (T[])array.Clone();
for (int i = 0; i < clone.Length - 1; i++)
{
Swap(ref clone[i], ref clone[i + sequence[i]]);
}
return clone;
}
private static int[] GenerateSequence(long number, int size, IReadOnlyList<long> factorials)
{
var sequence = new int[size];
for (var j = 0; j < sequence.Length; j++)
{
var facto = factorials[sequence.Length - j];
sequence[j] = (int)(number / facto);
number = (int)(number % facto);
}
return sequence;
}
static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
private static long Factorial(int n)
{
long result = n;
for (int i = 1; i < n; i++)
{
result = result * i;
}
return result;
}
}
Here is a screenshot of the result:
And, finally, a github repository of the complete Visual Studio solution: Github

import java.util.Scanner;
import java.lang.String;
public class KrishaAnagram
{
public static void main(String[] args) {
Scanner Scan = new Scanner(System.in);
String s1, s2;
int sum1, sum2;
sum1 = sum2 = 0;
System.out.print("Enter fisrt string: ");
s1 = Scan.next();
System.out.print("Enter Second string: ");
s2 = Scan.next();
if (s1.length() != s2.length()) {
System.out.println("NOT ANAGRAM");
} else {
for (int i = 0; i < s1.length(); i++) {
char ch1 = s1.charAt(i);
char ch2 = s2.charAt(i);
sum1 += (int) ch1;
sum2 += (int) ch2;
}
if (sum1 == sum2)
System.out.println("IT IS AN ANAGRAM : s1 = " + sum1 + "s1 = " + sum2);
else
System.out.println("IT IS NOT AN ANAGRAM : s1 = " + sum1 + "s1 = " + sum2);;
}
}
}
//This is My way of solving anagram in java,Hope it helps.

Related

Find permutation of one string into other string program

Trying to make an program where it just check, if permutation of string s1 exists in string s2 or not.
Created below program and it works for below test case.
Input:
s1 = "ab"
s2 = "eidballl"
Output:
True
Explanation: s2 contains one permutation of s1 (that is ba).
But this get fail when, input s2="sdfdadddbd" , s1="ab", expected as, false, but got true.
I'm trying to figure out what is missing here. Using a sliding window approach. Below my code in c#:
public bool CheckInclusion(string s1, string s2) {
var intCharArray = new int[256];
foreach(char c in s1)
{
intCharArray[c]++;
}
int start=0,end=0;
int count=s1.Length;
bool found=false;
while(end<s2.Length)
{
if (intCharArray[s2[end]]>0) { count--;}
intCharArray[s2[end]]--;
Console.WriteLine("end:" + end + " start:"+ start);
if(end-start==s1.Length) {
if (count==0) {return true;}
if (intCharArray[s2[start]]>=0)
{
count++;
}
intCharArray[s2[start]]++;
start++;
}
end++;
}
return false;
}
you need to check all characters of permutation exist in any range of [i, i + p.Length) of the string
static class StringExtensions
{
public static bool ContainsAnyPermutationOf(this string str, string p)
{
Dictionary<char, int> chars_count = p.CreateChar_CountDictionary();
for (int i = 0; i <= str.Length - p.Length; i++)
{
string subString = str.Substring(i, p.Length);
if (DictionaryMatch(chars_count, subString.CreateChar_CountDictionary()))
{
return true;
}
}
return false;
}
private static bool DictionaryMatch(Dictionary<char, int> dictionary1, Dictionary<char, int> dictionary2)
{
if (dictionary1.Count != dictionary2.Count)
{
return false;
}
foreach (var kvp in dictionary1)
{
if (!dictionary2.ContainsKey(kvp.Key))
{
return false;
}
dictionary2[kvp.Key] = dictionary2[kvp.Key] - 1;
if (dictionary2[kvp.Key] == 0)
{
dictionary2.Remove(kvp.Key);
}
}
return true;
}
private static Dictionary<char, int> CreateChar_CountDictionary(this string str)
{
Dictionary<char, int> dic = new Dictionary<char, int>();
for (int i = 0; i < str.Length; i++)
{
if (!dic.ContainsKey(str[i]))
{
dic.Add(str[i], default);
}
dic[str[i]] = dic[str[i]] + 1;
}
return dic;
}
}
usage:
static void Main(string[] args)
{
Console.WriteLine("sdfdadddbd".ContainsAnyPermutationOf("ab"));
}
I guess the question is similar to LeetCode 567. These are simple, efficient, low-complexity accepted solutions:
C#
class Solution {
public bool CheckInclusion(string s1, string s2) {
int lengthS1 = s1.Length;
int lengthS2 = s2.Length;
if (lengthS1 > lengthS2)
return false;
int[] countmap = new int[26];
for (int i = 0; i < lengthS1; i++)
countmap[s1[i] - 97]++;
int[] bCount = new int[26];
for (int i = 0; i < lengthS2; i++) {
bCount[s2[i] - 97]++;
if (i >= (lengthS1 - 1)) {
if (allZero(countmap, bCount))
return true;
bCount[s2[i - (lengthS1 - 1)] - 97]--;
}
}
return false;
}
private bool allZero(int[] s1, int[] s2) {
for (int i = 0; i < 26; i++) {
if (s1[i] != s2[i])
return false;
}
return true;
}
}
Java
class Solution {
public boolean checkInclusion(String s1, String s2) {
int lengthS1 = s1.length();
int lengthS2 = s2.length();
if (lengthS1 > lengthS2)
return false;
int[] countmap = new int[26];
for (int i = 0; i < lengthS1; i++) {
countmap[s1.charAt(i) - 97]++;
countmap[s2.charAt(i) - 97]--;
}
if (allZero(countmap))
return true;
for (int i = lengthS1; i < lengthS2; i++) {
countmap[s2.charAt(i) - 97]--;
countmap[s2.charAt(i - lengthS1) - 97]++;
if (allZero(countmap))
return true;
}
return false;
}
private boolean allZero(int[] count) {
for (int i = 0; i < 26; i++)
if (count[i] != 0)
return false;
return true;
}
}
Python
class Solution:
def checkInclusion(self, s1, s2):
count_map_s1 = collections.Counter(s1)
count_map_s2 = collections.Counter(s2[:len(s1)])
for i in range(len(s1), len(s2)):
if count_map_s1 == count_map_s2:
return True
count_map_s2[s2[i]] += 1
count_map_s2[s2[i - len(s1)]] -= 1
if count_map_s2[s2[i - len(s1)]] == 0:
del(count_map_s2[s2[i - len(s1)]])
return count_map_s2 == count_map_a
Reference
The codes are explained in the following links:
LeetCode 567 Solution
LeetCode 567 Discussion Board
These two answers are also useful to look into:
Link 1
Link 2
private static bool CheckPermutationInclusion(string s1, string s2)
{
return Enumerable.Range(0, s2.Length - s1.Length)
.Select(i => s2.Substring(i, s1.Length))
.Any(x => x.All(y => s1.Contains(y)));
}
Description:
Enumerable.Range(Int32, Int32) Method: Generates a sequence of integral numbers within a specified range.
Enumerable.Select Method: Projects each element of a sequence into a new form.
Enumerable.All Method: Determines whether all elements of a sequence satisfy a condition.
Enumerable.Any Method: Determines whether any element of a sequence exists or satisfies a condition.
Do not forget using System.Linq;.

how to fix stringBuilder to string and reverse?

I have a StringBuilder result and I want to reverse it but in C# the StringBuilder doesn't support .Reverse() so first I cast it to a string and then I reverse it and add a "$" to the end of string.
but the answer is like this:
System.Linq.Enumerable+<ReverseIterator>d__75`1[System.Char]" string
how can I fix this?
StringBuilder result = new StringBuilder();
List<string> matrix = new List<string>();
List<int> indexes = new List<int>();
for (int i = 0; i < bwt.Length; i++)
{
matrix.Add("" + bwt[i]);
indexes.Add(i);
}
indexes.Sort((o1, o2) => matrix[o1].CompareTo(matrix[o2]));
int current = indexes[0];
for (int i = 0; i < bwt.Length - 1; i++)
{
int index = indexes.IndexOf(current);
string next = bwt[index].ToString();
result.Append(next);
current = index;
}
// return result.ToString().ToString() + "$";
StringBuilder allows you to access and manipulate the characters through their indexes.
string stringToReverse = "abcdefghijk";
var sb = new StringBuilder(stringToReverse);
for (int i = 0, j = sb.Length - 1; i < sb.Length / 2; i++, j--) {
char temp = sb[i];
sb[i] = sb[j];
sb[j] = temp;
}
string reversed = sb.ToString();
But I made a Test which shows that #Mendhak's version is faster. One million repetitions with strings of length 100
StringBuilder: 974 ms
Mendhak: 209 ms
So on my PC it takes just 209 ns to reverse the string with Mendhak's solution. Just because a solution looks faster it must not be faster. Array.Reverse calls the external method private static extern bool TrySZReverse(Array array, int index, int count); which is highly optimized.
The test:
static class ReverseString
{
const string stringToReverse = "abcdex.dfkjvhw4o5i8yd,vfjhe4iotuwyflkcjadhrlniqeuyfmln mclf8yuertoicer,tpoirsd,kfngoiw5r8t7ndlrgjhfg";
public static string TestStringBuilder()
{
var sb = new StringBuilder(stringToReverse);
for (int i = 0, j = sb.Length - 1; i < sb.Length / 2; i++, j--) {
char temp = sb[i];
sb[i] = sb[j];
sb[j] = temp;
}
return sb.ToString();
}
// By Mendhak
public static string TestArrayReverse()
{
char[] arr = stringToReverse.ToString().ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
public static void Compare()
{
string result1 = TestStringBuilder();
string result2 = TestArrayReverse();
Console.WriteLine($"Are result1 and 2 equal? {result1 == result2}");
Measure("StringBuilder", TestStringBuilder);
Measure("Array.Reverse", TestArrayReverse);
Console.ReadKey();
}
public static void Measure(string method, Func<string> sut)
{
const int NTests = 1000000;
var stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < NTests; i++) {
sut();
}
stopWatch.Stop();
Console.WriteLine($"{method} = {stopWatch.ElapsedMilliseconds} ms");
}
}
You will need to take a few extra steps to reverse your string. Build it as you normally would in your stringbuilder (result), then
char[] arr = result.ToString().ToCharArray();
Array.Reverse(arr);
return new string(arr) + "$";

Permutations with constant prefix numbers

I have an array of integers where each value will have distinct meanings.The first value means the length of permutation, the second value represent the length of initial prefix and rest of integers are single integer that make up prefix of all permutations.
For e.g. if the array has elements {5,2,1,4}
where 5 is the number of elements in the permutation array.
and 2 is the length of the integer that will makeup the first 2 elements prefix in the array permutation. 1,4 are the prefix integers i.e. length 2 in 5 element permutation combination so missing elements are 2,3,5 where 1&4 being common prefix across all permutations as below
[14235][14253][14325][14352][14523][14532] where input array is {5,2,1,4}
How to achieve this?
I have below code to get the permutation of one missing elements 2,3 & 5 but I am not getting how to program the entire the solution
static void Main(string[] args)
{
int output;
int ip1;
ip1 = Convert.ToInt32(Console.ReadLine());
int ip2_size = 0;
ip2_size = Convert.ToInt32(Console.ReadLine());
int[] ip2 = new int[ip2_size];
int ip2_item;
for (int ip2_i = 0; ip2_i < ip2_size; ip2_i++)
{
ip2_item = Convert.ToInt32(Console.ReadLine());
ip2[ip2_i] = ip2_item;
}
output = correctResult(ip1, ip2);
Console.WriteLine(output);
}
static int correctResult(int n, int[] arr)
{
int permLength = 0;
int prefLength = 0;
int result = 0;
permLength = n;
prefLength = arr.Length;
int[] permArray = new int[permLength];
int len = 0;
var missingNum = Enumerable.Range(1,
permLength).Except(arr).ToArray<int>();
if (permLength < (missingNum.Length + len))
{
result = -1;
}
else
{
for (int i = 0; i < missingNum.Length; i++)
{
permArray[prefLength + i] = missingNum[i];
}
result = permute(missingNum, 0, missingNum.Length - 1);
}
return result;
}
static int permute(int[] arry, int i, int n)
{
int j;
if (i == n)
{
int s1, s2;
s1 = s2 = 0;
for (int a = 0; a < n - 1; a++)
{
for (int b = a + 1; b < n; b++)
{
if (arry[a] > arry[b])
{
s1++;
}
}
s2 = s2 + Math.Max(0, a + 1 - arry[a]);
}
int count = 0;
if (s1 == s2)
count++;
return count;
}
else
{
int count = 0;
for (j = i; j <= n; j++)
{
swap(ref arry[i], ref arry[j]);
count += permute(arry, i + 1, n);
swap(ref arry[i], ref arry[j]);
}
return count;
}
}
static void swap(ref int a, ref int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
Try solving this with immutable types, its easier to reason about them. If, after solving the problem, you have a performance goal you haven't met then you can start trying to optimize the code.
Consider the following approach with an immutable stack that keeps track of the current permutation:
static IEnumerable<IEnumerable<int>> GetPermutations(IList<int> input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (input.Count < 2)
throw new ArgumentException("Input does not have a valid format.");
var setSize = input[0];
var prefixSize = input[1];
if (prefixSize != input.Count - 2)
throw new ArgumentException("Input does not have a valid format.");
if (input.Skip(2).Any(i => i > setSize)) //we are assuming, per example, that valid range starts at 1.
throw new ArgumentException("Input does not have a valid format.");
//Ok, we've got a valid input, interesting stuff starts here.
var prefix = input.Skip(2).ToArray();
var initialSet = Enumerable.Range(1, setSize)
.Except(prefix)
.ToArray();
foreach (var p in getPermutations(ImmutableStack<int>.Empty, initialSet))
{
yield return prefix.Concat(p);
}
IEnumerable<IEnumerable<int>> getPermutations(ImmutableStack<int> permutation, IEnumerable<int> set)
{
if (permutation.Count == setSize - prefixSize)
{
yield return permutation;
}
else
{
foreach (var i in set)
{
foreach (var p in getPermutations(permutation.Push(i), set.Except(new[] { i })))
{
yield return p;
}
}
}
}
}
And that is it, solving your problem was about 10-12 lines of real code (not considering input validation). Note that I am using some c#7 features here, but its easily translatable to previous versions of the language. Also I'd like to underline the argument validation we are doing upfront; make sure you have a valid input before trying out anything.
For ImmutableStack<T> you can use the one in System.Collections.Immutable (you have to download the NuGet package) or implement your own, its simple:
private class ImmutableStack<T>: IEnumerable<T>
{
public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
private readonly T head;
private readonly ImmutableStack<T> tail;
private ImmutableStack() { }
private ImmutableStack(T head, ImmutableStack<T> tail)
{
Debug.Assert(tail != null);
this.head = head;
this.tail = tail;
Count = tail.Count + 1;
}
public int Count { get; }
public T Peek() =>
this != Empty ? head : throw new InvalidOperationException("Empty stack.");
public ImmutableStack<T> Pop() =>
this != Empty ? tail : throw new InvalidOperationException("Empty stack.");
public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);
public IEnumerator<T> GetEnumerator()
{
var current = this;
while (current != Empty)
{
yield return current.head;
current = current.tail;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
If you use the collections in System.Collections.Immutable, then you'll probably want to use some kind of immutable set for initalSet and set.
You can rewrite your permute method (based on this answer):
private static IEnumerable<IEnumerable<T>> Permute<T>(List<T> prefix, List<T> suffix)
{
for (var i = 0; i < suffix.Count; ++i)
{
var newPrefix = new List<T>(prefix) {suffix[i]};
var newSuffix = new List<T>(suffix.Take(i).Concat(suffix.Skip(i + 1)));
if (newSuffix.Count == 0)
{
yield return newPrefix;
continue;
}
foreach (var permutation in Permute(newPrefix, newSuffix))
yield return permutation;
}
}
And use it like this:
public static void PrintAllPermutations()
{
var input = new[] {5, 2, 1, 4};
var prefix = input.Skip(2).Take(input[1]).ToList();
var suffx = Enumerable.Range(1, input[0]).Except(prefix).ToList();
foreach (var permutation in Permute(prefix, suffx))
Console.WriteLine(string.Join(", ", permutation));
}
Reult would be:
1, 4, 2, 3, 5
1, 4, 2, 5, 3
1, 4, 3, 2, 5
1, 4, 3, 5, 2
1, 4, 5, 2, 3
1, 4, 5, 3, 2

Removing Leading Zeros in a Char Array

I'm attempting to subtract two strings (of theoretically infinite length) without the use of libraries like BigIntbut I was wondering if anybody has any good ideas on how to remove the leading zeros in the corner cases like the one below?
static void Main(string[] args)
{
Console.WriteLine(Subtract("10", "10005"));
}
static string ReverseInput(string inputString)
{
char[] charArray = inputString.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
static string Subtract(string firstNumInput, string secondNumInput)
{
string firstNum = String.Empty;
string secondNum = String.Empty;
bool negative = false;
// Reverse order of string input
if (firstNumInput.Length > secondNumInput.Length)
{
firstNum = ReverseInput(firstNumInput);
secondNum = ReverseInput(secondNumInput);
}
else if (firstNumInput.Length < secondNumInput.Length)
{
negative = true;
firstNum = ReverseInput(secondNumInput);
secondNum = ReverseInput(firstNumInput);
}
else if (firstNumInput.Length == secondNumInput.Length)
{
// iterate through string to find largest
}
char[] result = new char[firstNum.Length + 1];
int resultLength = 0;
int carry = 0;
for (int i = 0; i < firstNum.Length; i++)
{
int an = (i < firstNum.Length) ? int.Parse(firstNum[i].ToString()) : 0;
int bn = (i < secondNum.Length) ? int.Parse(secondNum[i].ToString()) : 0;
int rn = an - bn - carry;
if (rn < 0)
{
carry = 1;
rn += 10;
}
else
{
carry = 0;
}
result[resultLength++] = (char)(rn + '0');
}
// create the result string from the char array
string finalResult = ReverseInput(new string(result, 0, resultLength));
if (negative)
{
finalResult = '-' + finalResult;
}
return finalResult;
}
Are you looking for TrimStart?
// create the result string from the char array
string finalResult = ReverseInput(new string(result, 0, resultLength)).TrimStart('0');

how can i find lcs length between two large strings

I've written the following code in C# for obtaining the length of longest common subsequence of two texts given by use, but it doesn't work with large strings. Could you please help me. I'm really confused.
public Form1()
{
InitializeComponent();
}
public int lcs(char[] s1, char[] s2, int s1size, int s2size)
{
if (s1size == 0 || s2size == 0)
{
return 0;
}
else
{
if (s1[s1size - 1] == s2[s2size - 1])
{
return (lcs(s1, s2, s1size - 1, s2size - 1) + 1);
}
else
{
int x = lcs(s1, s2, s1size, s2size - 1);
int y = lcs(s1, s2, s1size - 1, s2size);
if (x > y)
{
return x;
}
else
return y;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
string st1 = textBox2.Text.Trim(' ');
string st2 = textBox3.Text.Trim(' ');
char[] a = st1.ToCharArray();
char[] b = st2.ToCharArray();
int s1 = a.Length;
int s2 = b.Length;
textBox1.Text = lcs(a, b, s1, s2).ToString();
}
Here you are using the Recursion method. So it leads the program to occur performance problems as you mentioned.
Instead of recursion, use the dynamic programming approach.
Here is the C# Code.
public static void LCS(char[] str1, char[] str2)
{
int[,] l = new int[str1.Length, str2.Length];
int lcs = -1;
string substr = string.Empty;
int end = -1;
for (int i = 0; i < str1.Length; i++)
{
for (int j = 0; j < str2.Length; j++)
{
if (str1[i] == str2[j])
{
if (i == 0 || j == 0)
{
l[i, j] = 1;
}
else
l[i, j] = l[i - 1, j - 1] + 1;
if (l[i, j] > lcs)
{
lcs = l[i, j];
end = i;
}
}
else
l[i, j] = 0;
}
}
for (int i = end - lcs + 1; i <= end; i++)
{
substr += str1[i];
}
Console.WriteLine("Longest Common SubString Length = {0}, Longest Common Substring = {1}", lcs, substr);
}
Here is a solution how to find the longest common substring in C#:
public static string GetLongestCommonSubstring(params string[] strings)
{
var commonSubstrings = new HashSet<string>(strings[0].GetSubstrings());
foreach (string str in strings.Skip(1))
{
commonSubstrings.IntersectWith(str.GetSubstrings());
if (commonSubstrings.Count == 0)
return string.Empty;
}
return commonSubstrings.OrderByDescending(s => s.Length).DefaultIfEmpty(string.Empty).First();
}
private static IEnumerable<string> GetSubstrings(this string str)
{
for (int c = 0; c < str.Length - 1; c++)
{
for (int cc = 1; c + cc <= str.Length; cc++)
{
yield return str.Substring(c, cc);
}
}
}
I found it here: http://www.snippetsource.net/Snippet/75/longest-common-substring
Just for fun, here is one example using Queue<T>:
string LongestCommonSubstring(params string[] strings)
{
return LongestCommonSubstring(strings[0], new Queue<string>(strings.Skip(1)));
}
string LongestCommonSubstring(string x, Queue<string> strings)
{
if (!strings.TryDequeue(out var y))
{
return x;
}
var output = string.Empty;
for (int i = 0; i < x.Length; i++)
{
for (int j = x.Length - i; j > -1; j--)
{
string common = x.Substring(i, j);
if (y.IndexOf(common) > -1 && common.Length > output.Length) output = common;
}
}
return LongestCommonSubstring(output, strings);
}
It's still using recursion though, but it's a nice example of Queue<T>.
I refactored the C++ code from Ashutosh Singh at https://iq.opengenus.org/longest-common-substring-using-rolling-hash/ to create a rolling hash approach in C# - this will find the substring in O(N * log(N)^2) time and O(N) space
using System;
using System.Collections.Generic;
public class RollingHash
{
private class RollingHashPowers
{
// _mod = prime modulus of polynomial hashing
// any prime number over a billion should suffice
internal const int _mod = (int)1e9 + 123;
// _hashBase = base (point of hashing)
// this should be a prime number larger than the number of characters used
// in my use case I am only interested in ASCII (256) characters
// for strings in languages using non-latin characters, this should be much larger
internal const long _hashBase = 257;
// _pow1 = powers of base modulo mod
internal readonly List<int> _pow1 = new List<int> { 1 };
// _pow2 = powers of base modulo 2^64
internal readonly List<long> _pow2 = new List<long> { 1L };
internal void EnsureLength(int length)
{
if (_pow1.Capacity < length)
{
_pow1.Capacity = _pow2.Capacity = length;
}
for (int currentIndx = _pow1.Count - 1; currentIndx < length; ++currentIndx)
{
_pow1.Add((int)(_pow1[currentIndx] * _hashBase % _mod));
_pow2.Add(_pow2[currentIndx] * _hashBase);
}
}
}
private class RollingHashedString
{
readonly RollingHashPowers _pows;
readonly int[] _pref1; // Hash on prefix modulo mod
readonly long[] _pref2; // Hash on prefix modulo 2^64
// Constructor from string:
internal RollingHashedString(RollingHashPowers pows, string s, bool caseInsensitive = false)
{
_pows = pows;
_pref1 = new int[s.Length + 1];
_pref2 = new long[s.Length + 1];
const long capAVal = 'A';
const long capZVal = 'Z';
const long aADif = 'a' - 'A';
unsafe
{
fixed (char* c = s)
{
// Fill arrays with polynomial hashes on prefix
for (int i = 0; i < s.Length; ++i)
{
long v = c[i];
if (caseInsensitive && capAVal <= v && v <= capZVal)
{
v += aADif;
}
_pref1[i + 1] = (int)((_pref1[i] + v * _pows._pow1[i]) % RollingHashPowers._mod);
_pref2[i + 1] = _pref2[i] + v * _pows._pow2[i];
}
}
}
}
// Rollingnomial hash of subsequence [pos, pos+len)
// If mxPow != 0, value automatically multiply on base in needed power.
// Finally base ^ mxPow
internal Tuple<int, long> Apply(int pos, int len, int mxPow = 0)
{
int hash1 = _pref1[pos + len] - _pref1[pos];
long hash2 = _pref2[pos + len] - _pref2[pos];
if (hash1 < 0)
{
hash1 += RollingHashPowers._mod;
}
if (mxPow != 0)
{
hash1 = (int)((long)hash1 * _pows._pow1[mxPow - (pos + len - 1)] % RollingHashPowers._mod);
hash2 *= _pows._pow2[mxPow - (pos + len - 1)];
}
return Tuple.Create(hash1, hash2);
}
}
private readonly RollingHashPowers _rhp;
public RollingHash(int longestLength = 0)
{
_rhp = new RollingHashPowers();
if (longestLength > 0)
{
_rhp.EnsureLength(longestLength);
}
}
public string FindCommonSubstring(string a, string b, bool caseInsensitive = false)
{
// Calculate max neede power of base:
int mxPow = Math.Max(a.Length, b.Length);
_rhp.EnsureLength(mxPow);
// Create hashing objects from strings:
RollingHashedString hash_a = new RollingHashedString(_rhp, a, caseInsensitive);
RollingHashedString hash_b = new RollingHashedString(_rhp, b, caseInsensitive);
// Binary search by length of same subsequence:
int pos = -1;
int low = 0;
int minLen = Math.Min(a.Length, b.Length);
int high = minLen + 1;
var tupleCompare = Comparer<Tuple<int, long>>.Default;
while (high - low > 1)
{
int mid = (low + high) / 2;
List<Tuple<int, long>> hashes = new List<Tuple<int, long>>(a.Length - mid + 1);
for (int i = 0; i + mid <= a.Length; ++i)
{
hashes.Add(hash_a.Apply(i, mid, mxPow));
}
hashes.Sort(tupleCompare);
int p = -1;
for (int i = 0; i + mid <= b.Length; ++i)
{
if (hashes.BinarySearch(hash_b.Apply(i, mid, mxPow), tupleCompare) >= 0)
{
p = i;
break;
}
}
if (p >= 0)
{
low = mid;
pos = p;
}
else
{
high = mid;
}
}
// Output answer:
return pos >= 0
? b.Substring(pos, low)
: string.Empty;
}
}

Categories