Skip to content

Instantly share code, notes, and snippets.

@jianminchen
Created July 25, 2016 17:34
Show Gist options
  • Save jianminchen/bf0f554dd32ea8f4055f86a2c569e414 to your computer and use it in GitHub Desktop.
Save jianminchen/bf0f554dd32ea8f4055f86a2c569e414 to your computer and use it in GitHub Desktop.
short palindrome - hackerRank - world code sprint #5 - add comments to review the code, and see if there is any design defects, improvements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShortPalindrome
{
class Program
{
static void Main(string[] args)
{
string s = Console.ReadLine();
//string s = "abbaab";
Console.WriteLine(getShortPalindrome(s, getAlphabetic(s)));
}
public static void testFunc()
{
int[] test1 = getAlphabetic("aaab");
string test2 = getPseudoString("abcdefac", 'a', 'c');
// test case 1: "011001" - 4
// long count = countingPalindromes("0000001", true);
// count += countingPalindromes("00000011", false);
}
public static int[] getAlphabetic(string s)
{
int[] res = new int[26];
if (s == null || s.Length == 0)
return res;
string arr = "abcdefghijklmnopqrstuvwxyz";
int TOTAL = 26;
int[] noAlph = new int[TOTAL];
char[] aA = arr.ToArray();
for (int i = 0; i < s.Length; i++)
{
int index = s[i] - 'a';
noAlph[index]++;
}
return noAlph;
}
/*
* Calculate short palindrome
* - big issues:
* 1. time out
* 2. wrong answer
* 3. run time issue
*
*/
public static long getShortPalindrome(string s, int[] input)
{
long res = 0;
int SIZE = 26;
long moduleValue = ((long)Math.Pow(10, 9) + 7);
for (int i = 0; i < SIZE; i++)
{
int num = input[i];
long product = 1;
if (num >= 4)
{
int index = 0;
while (index <= 3)
{
product = (product * (num - index)) % moduleValue;
index++;
}
product /= 24;
res += product % moduleValue;
}
}
Dictionary<string, long> dict = new Dictionary<string, long>();
Dictionary<string, long> dict2 = new Dictionary<string, long>();
for (int i = 0; i < SIZE; i++)
for (int j = i + 1; j < SIZE; j++)
{
int val1 = input[i];
int val2 = input[j];
if (val1 < 2)
break;
if (val2 < 2)
continue;
char chA = (char)(i + 'a'); // bug001 - not val1, should be i,
char chB = (char)(j + 'a'); // bug002 - not val2, should be j
string s1 = getPseudoString(s, chA, chB);
if (dict.ContainsKey(s1))
res += dict[s1] % moduleValue;
else
{
res += countingPalindromes(s1, true, dict2) % moduleValue;
res += countingPalindromes(s1, false, dict2) % moduleValue;
}
}
return res;
}
/*
* using 0 and 1 to construct the string
* 1001
* 0110
*
* There are 26 chars in alphabetic string, any two combination is 26*25/2*1 > 250
* Instead, using 0 and 1 to stand for two distinct characters.
* for example, abab
* 0101
* So, we can conclude one thing:
* ababa
* 01010
* or
* 10101
* So, use memorization, 01010 and 10101 should be same key
* See if this can solve time out issues - July 25, 2016
*
* reverse of string should be same key
*/
public static string getPseudoString(string s, char char0, char char1)
{
StringBuilder sb = new StringBuilder();
if (s == null || s.Length == 0)
return "";
char[] arr = new char[2] { char0, char1 };
for (int i = 0; i < s.Length; i++)
{
char index = s[i];
if (Array.IndexOf(arr, index) != -1)
{
if (index - char0 == 0)
sb.Append('0');
else
sb.Append('1');
}
}
return sb.ToString();
}
/*
* use two loops
*
* get 0110 pairs
* get 1001 paris
*
* Think about DP solution - dynamic programming - not working, too complicate
*
* brute force solution:
* 0 - start char, end char, and then, count how many possibilities
* Go through O(n*n) case, for any two 0 in pseudo string, check in-between
*
* For example:
* 001010110
*
* The above case, there are 5 '0',
* position of '0' is 0, 1, 3, 5, 8,
* So, any two '0' combinations are 5*4/2*1 = 10
*
* A: 0, 1, in between, there is no chars, n/a
* B: 0, 3, 2 chars in between - "01", count how many '1' in the substring, only 1.
* C: 0, 5, 4 chars in between - "0101", two one inside, so how many combination
* of 11, only 1 choice.
* D: 0, 8, 7 chars in-between - "0101011", four one's in the substring, how many combination - 4*3/2 = 6 choices
*/
public static long countingPalindromes(string s, bool first0, Dictionary<string, long> dict)
{
if (s == null || s.Length == 0)
return 0;
int len = s.Length;
char compare = first0 ? '0' : '1';
char counting = first0 ? '1' : '0';
long count = 0;
long moduleValue = ((long)Math.Pow(10, 9) + 7);
for (int i = 0; i < len; i++)
for (int j = i + 3; j < len; j++)
{
char first = s[i];
bool firstOne = (first - compare) == 0;
if (!firstOne)
break;
char second = s[j];
bool secondOne = (second - compare) == 0;
if (secondOne)
{
// count how many 1 in-between
string s1 = s.Substring(i, j - i);
long oneC = 0;
if (dict.ContainsKey(s1))
oneC = dict[s1];
else
{
oneC = getCompareCount(s1, counting);
dict[s1] = oneC;
}
count += (oneC * (oneC - 1) / 2) % moduleValue;
}
}
return count % moduleValue;
}
/*
* pseudo string:
* using 0 and 1 instead of real alphabetic chars
* For example,
* "akkak", a- 0, k - 1,
* pseudo string is
* "10010",
* compare = '1', count how many 1's in the string
* the above case is 2
*
* Time complexity: O(N) - N string length
*
*/
public static long getCompareCount(string s, char compare)
{
if (s == null || s.Length == 0)
return 0;
long count = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == compare)
count++;
}
return count;
}
}
}
@ibrahim01832891988
Copy link

this is not pass all the test case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment