We use cookies to ensure you have the best browsing experience on our website. Please read our cookie policy for more information about how we use cookies.
Really simple 3 pass solution:
1. Build a list of tuples such that the string "aaabbc" can be squashed down to [("a", 3), ("b", 2), ("c", 1)].
2. add to answer all combinations of substrings from these tuples which would represent palindromes which have all same letters.
3. traverse this list to specifically find the second case mentioned in probelm
The trick to solve this problem is to find all substring for each of the two cases.
Case 1: All characters are same.
For a string with n characters, we can make a total of n*(n+1)/2 substrings. Note substrings keep the same order and don't skip characters. For instance, aaaa will make a, aa, aa, aa, aaa, aaa and aaaa
This is because, for a string of size n we can make n - 1 substrings of size 2 and n - 2 substrings of size 3 and so on. This can be generalized as n-(k-1) where k is the length of the substring.
So total number of substrings (of all lenghts) is then n-1 + n-2 + ... + n - (k-1) + ... + n - (n-1).
This when written in reverse is same as 1 + 2 + ... + n-2 + n-1 + n.
The sum of an arithmetic sequence is = n*(first+last)/2. Therefore, the sum of above sequence is n*(1+n)/2
Case 2: Odd length string with all characters same except the middle one
For a string like aaabaaa, the total number of special substrings is equal to the number of repeated characters.
For the example above it will be, aba, aabaa, aaabaaa.
So when we find a character, c, such that its previous character, pc, is same as its next character, nc, i.e. pc == nc but not same as itself, i.e. pc != c, we can count the number of times that pc and nc are repeated. Note that, number of times pc is repated may be different than the number of times nc is repated, for instance aaabaa. We take the minimum of the repeated times.
To add effeciency, we can create an array that stores the number of times a character is repated at every index. For example, for a string like aaabaa the array will contain 333122
Python3 - one loop counting sequences and branch out for xx.xx patterns:
defsubstrCount(n,s):tot=0count_sequence=0prev=''fori,vinenumerate(s):# first increase counter for all seperate characterscount_sequence+=1ifiand(prev!=v):# if this is not the first char in the string # and it is not same as previous char, # we should check for sequence x.x, xx.xx, xxx.xxx etc# and we know it cant be longer on the right side than# the sequence we already found on the left side.j=1while((i-j)>=0)and((i+j)<len(s))andj<=count_sequence:# make sure the chars to the right and left are equal# to the char in the previous found squenceifs[i-j]==prev==s[i+j]:# if so increase total score and step one step further outtot+=1j+=1else:# no need to loop any further if this loop did # not find an x.x patternbreak#if the current char is different from previous, reset counter to 1count_sequence=1tot+=count_sequenceprev=vreturntot
Tried to simplify the code above and optimize a little bit by avoiding iterating over the repeatable symbols and jumping straight to the distinct by incrementing for loop counter and replacing sum with n*(n+1)/2
publicstaticlongsubstrCount(intlength,Strings){longcounter=0;for(inti=0;i<length;i++){// if the current symbol is in the middle of palindrome, e.g. abaintoffset=1;while(i-offset>=0&&i+offset<length&&s.charAt(i-offset)==s.charAt(i-1)&&s.charAt(i+offset)==s.charAt(i-1)){counter++;offset++;}// if this is repeatable characters aaintrepeats=0;while(i+1<length&&s.charAt(i)==s.charAt(i+1)){repeats++;i++;}counter+=repeats*(repeats+1)/2;}returncounter+length;}
Super-cool! I used it (together with some luck that allowed me to find more small and meaningful test cases) to debug a similar idea I had, only that it works strictly forward rather than expanding from the middle:
staticlongsubstrCount(finalintn,finalStrings){longspecials=n;inti=0,j=1;while(j<n){if(s.charAt(i)!=s.charAt(j)){// Different char and maybe middle char of special substringfinalintrepeatedCharStringLen=j-i;// All len 2+ substrings of same-char string with fixed start are specialspecials+=repeatedCharStringLen-1;// If there is a mirrored same-char substring after the different char, then specialfinalintnewStringAfterSpecialIdx=j+1+repeatedCharStringLen;if(j+1<n&&newStringAfterSpecialIdx<=n&&s.substring(i,j).equals(s.substring(j+1,newStringAfterSpecialIdx))){specials++;}// Advancei++;j=i;}// Expand substring to the rightj++;}specials+=substringsInLen(j-i)-(j-i);// All len 2+ substringsreturnspecials;}privatestaticlongsubstringsInLen(finalintlen){if(len<=0)return0;returnlen*(len+1)/2;}
It comes from calculate the number of substring in the string. I saw it using an old technique, imagine that "0" are characters and "1" are separators between chars. Then a string can be represented as a binary chain "101010101...1". And a substring is then any subchain which start in "1" and ends in another different "1", being the chars between "1" the substring. Then, is just calculate how many differents ways there are to take two differents "1" in this repr, due two differents "1" always define a substring. If there are n "0" then there are n+1 "1" and to take two "1" in n + 1 possibles is equal to combinations(n + 1, 2) = n+ 1!/(n+1 - 2)!* 2, wich is equals to (n+1) * n / 2.
This is what I came up with. It works for the cases given in the description. But not for the submit cases. Do you have any idea as to why it doesn't work for other cases
static long substrCount(int n, String s) {
char chAr[] = s.toCharArray();
long res = 1l;
int m = 1;
for (int i = 0; i < n - 1; i++) {
if (chAr[i] == chAr[i + 1]) {
m++;
res += m;
} else {
m = n - 2 - i >= m ? m : n - i - 2;
for (int j = 0; j < m; j++) {
if (chAr[i - j] == chAr[i + j + 2]) {
res++;
}
}
m = 1;
res += 1;
}
}
return res;
Checks if it forms a palindrome.
The condition for that is the current element should have count 1, and we take the least of the counts on either side of the current element if they are equal.
Eg., aaabaa
b is the current element and we take the palindrome (aabaa)
i didn't understand here,
for i in range(1, len(l) - 1):
f l[i - 1][0] == l[i + 1][0] and l[i][1] == 1:
ans += min(l[i - 1][1], l[i + 1][1])
please explain me..!!
This is the 3rd pass, it tries to find a letter cluster with length 1, and its left letter cluster and right letter cluster are the same letter. For example bbbabb. 'a' it the letter cluster with length 1, and its left letter cluster "bbb" and its right letter cluster "bb" have the same letter 'b'. And number of the palindrome is limited by the min length of those two side letter cluster. For example, it has "bab", "bbabb", two palindrome, equals to the length of right letter cluster. I am sorry for my English. Hope you can understand.
How this logic will work to count 'cbbabbc' ? Since it's checking only i-1, i and i+1 it will count 'bbabb' correctly but how about 'cbbabbc' palindrome string ?
Because this is special palindrome string, case 2: All characters except the middle one are the same, e.g. aadaa. So there is no need to consider i-2 and i+2. two neibors should be same.
Why this approach return 11 for input 'cbbabbc' as an example ?
Correct answer should be 12 in this case. (c, b, b, a, b, b, c, bb, bb, bab, bbabb, cbbabbc)
I think there is a bug in 3rd testCase as its only checking i-1, i and i+1.
There should be a recursive way to keep check n-1 and n+1 terms until they are matching or something like that, then start taking min of each of those.
"cbbabbc" is a palindrome, but the question is asking for special palindromes, which are palindromes that consist of only one letter (e.g., "bbbb", "aa", "ccccc") or palindromes that consist of only one letter and are separated by a single letter (e.g., "bbbabbb", "cac").
Since "cbbabbc" contains two different letters on either side of the dividing letter, it's not counted
I used two regular expressions, this is my python 3 code:
count = len(s)
exp1 = r'(([a-z])\2*)(?!\1)(?=[a-z]\1)'
m = re.finditer(exp1,s)
count += sum([len(x.group(0)) for x in m])
exp2 = r'([a-z])\1+'
m = re.finditer(exp2,s)
count += sum([triangular_number(len(x.group(0))-1) for x in m])
return count
I used triangular number to sum all repeated words:
def triangular_number(n):
return (pow(n,2)+n)//2
triangular number function t1=1, t2=3, t3=6, t4=10, t5=15
that is if you sum (len -1) of repeated words sequence, you'll have all combinations. eg. aaaa:
(3²)+3//2 = 6
Hi. I'm not sure if is possible to solve the problem using triangular number only. Triangular number is just an especific sequence and in this solution, triangular number is part of the solution. I'll try explain the solution step by step :
1) len(s) -> count all char of the word;
2) exp1 -> count all words that follow this rule: a_a also aaaa_aaaa;
3) exp2 -> count all repeated char of the word and with triangular number all combinations of these repeated chars. Example of this step is: aaaa has the combination of:
'aa'+'aa'+'aa'
+'aaa'+'aaa'
+'aaaa' = 6 (realize 6 is the same T3 of triangular number sequence).
I little late but ... I'll try to explain.
As I said before, exp1 -> count all words that follow this rule: a_a also aaaa_aaaa;
So, in this case the middle word needs to be different from match group 1, that's why this negative lookahead(?!\1) is required.
No Need for the // in ans += (i[1] * (i[1] + 1)) // 2 as i[1] will always be greater than 1 and hence i[1]+1 will be even when i[1] is odd and vice-versa. So this formula yeilds only integer results.
Thanks for the logic and style, I'm sure many have learned from it!
Following the same logic described, I have the same solution written in C++ for anyone who wanted to see it in the language
Here it is:
long substrCount(int n, string s)
{
long count = 0;
vector<std::pair<char, int>> frequencies;
int i=0, j=0;
for ( i = 0; i < n; i++)
{
for( j = i+1; j < n; j++)
{
if (s[j] == s[i])
continue;
else
break;
}
frequencies.push_back(std::make_pair(s[i],j-i));
i = j-1;
}
for (i=0; i < frequencies.size(); i++)
count += (frequencies[i].second+1) * frequencies[i].second / 2;
for (i=1; i < frequencies.size()-1; i++)
{
if ( frequencies[i].second == 1 && frequencies[i-1].first == frequencies[i+1].first)
count += min(frequencies[i-1].second, frequencies[i+1].second);
}
return count;
After this, my code passed all tests. I really like the logic. The for inside for actually could be done with just one for loop. Here is my relevant JAVA solution. It passed all the tests.
static class Point{
char text;
long counter;
Point(char t, long c){
text = t;
counter = c;
}
}
// Complete the substrCount function below.
static long substrCount(int n, String s) {
long palindromeCount = 0L;
long equalCounter = 1L;
List<Point> countList = new ArrayList<Point>();
for(int i=1; i<s.length();i++){
if(s.charAt(i)==s.charAt(i-1)){
equalCounter++;
}
else{
countList.add(new Point(s.charAt(i-1),equalCounter));
equalCounter = 1L;
}
}
countList.add(new Point(s.charAt(s.length()-1), equalCounter));
for(int i=0; i<countList.size(); i++){
palindromeCount += (countList.get(i).counter+1)*countList.get(i).counter/2;
}
for (int i = 1; i < countList.size()-1; i++) {
if(countList.get(i).counter == 1
&& countList.get(i-1).text == countList.get(i+1).text){
palindromeCount += Math.min(countList.get(i-1).counter,countList.get(i+1).counter);
}
}
return palindromeCount;
}
how on earth did you came up with this solution?
can someone be trained on being able to find such logics?
do you have an advice? because i would have never found the solution you made yet i want to be this good at finding solutions like this.
its from a formula n(n+1)/2 which give the sum of all term, like n = 5, 1+2+3+4+5 = 5(5+1)/2 = 15.
Its used because if you have "aaaa" , you can have "a,a,a,a", "aa,aa,aa", "aaa,aaa" and "aaaa", we can see the partern of 4,3,2,1 groups, so in this case there's 15 groups!
Wow nice solution. I didn't understand the intuition behind this line:
ans += (i[1] * (i[1] + 1)) i.e if all chars are same.
Can anyone comment on that ?
i think it's looking to count all possible sub-strings of a string.
so if the string length is n, the number of sub-strings will be (n*(n+1))/2.
you can see the 2 commented out in the solution - not sure why
Appears that RLE (run length encoding) compression is the consensus; I did so too.
My implementation ran through the list twice instead - just makes the code all the more clear.
I feel this is a very complicated answer. You can solve this problem in 10 lines, using the same logic as you would manually do when you solve it by hand :
For each index i in the string, I create a cursor k that starts from i and goes forward until it meets a different letter than s[i] at s[i+k]. Then I check if the string starting from s[i] centrered on s[i+k] could be a palindrome.
staticintpalindromHalfLength(inti,Strings){intstep=1;charpalChar=s.charAt(i-1);while(i-step>=0&&i+step<s.length()&&s.charAt(i-step)==palChar&&s.charAt(i+step)==palChar)step++;returnstep-1;}// Complete the substrCount function below.staticlongsubstrCount(intn,Strings){if(s.length()==0)return0;longres=1;intcountSimChar=1;for(inti=1;i<s.length();i++){if(s.charAt(i-1)==s.charAt(i)){countSimChar++;}else{res+=palindromHalfLength(i,s);countSimChar=1;}res+=countSimChar;}returnres;}
If there are k similar characters in a raw, number of palindroms will be 1+2+..+k;
If current character differs from the prvious one it might also be a palindrom, and half length of the palindrom would be the number of palindroms: aaacaaa -> half length is 3 and there are 3 palindroms: aca, aacaa, aaacaaa
I passed 3 test cases but when I click on submit it doesn't pass any other. I can't even debug as the data is very large and I can only feed 40kb in the input field. Please help me!
def substrCount(n, s):
import itertools as it
if n == 1:
return 1
s = [list(g) for k, g in it.groupby(s)]
res = sum([int(len(i)*(len(i)+1)/2) for i in s])
for i in range(len(s)):
if i == 0 or i == len(s)-1 or len(s[i]) > 1 :
continue
if s[i-1][0] == s[i+1][0]:
res+= min(len(s[i-1]), len(s[i+1]))
return res
def substrCount(n, s):
counts = []
for i in range(len(s)):
if counts == []:
counts.append([s[i], 1])
elif s[i] == counts[-1][0]:
counts[-1][1] = counts[-1][1] + 1
else:
counts.append([s[i], 1])
ans = 0
for pair in counts:
ans += pair[1] * (pair[1] + 1) / 2
for i in range(len(counts) - 2):
if counts[i + 1][1] == 1 and counts[i][0] == counts[i + 2][0]:
m = min(counts[i][1], counts[i + 2][1])
ans += m
return int(ans)
First pass can be done without using second variable 'cur'
l = []
count = 1
for i in range(len(s)):
try:
if s[i] == s[i+1]:
count+=1
else:
l.append((s[i],count))
count = 1
except:
l.append((s[i],count))
ans = 0
I have explained in detail the complete logic and program for beginners while intermediates can just read the logic part to get the idea. The logic is faster than using regex method by 5% and the complexity is O(n). I have used recursions. The link to the github page is here.
The raw code is here,
# Complete the substrCount function below.defcount_centered(s,i,j,length,n):if(i<n-1)and(j>0)and(s[i+1]==s[j-1])and(s[i+1]==s[i]):returncount_centered(s,i+1,j-1,length+1,n)else:returnlength+1defcount_same(s,i,length,n):if(i<n-1)and(s[i+1]==s[i]):returncount_same(s,i+1,length+1,n)else:return(length*(length+1)/2)-1,idefsubstrCount(n,s):count=1i=1whilei<n:ifs[i]==s[i-1]:temp,i=count_same(s,i,2,n)count+=tempelif(i>1)ands[i]==s[i-2]:count+=count_centered(s,i,i-2,1,n)else:count+=1i+=1returnint(count)
Thank you for the solution! I've implemented it similarly in C#:
staticlongsubstrCount(intn,strings){intresult=0;// Gather sequences of characters into a list of tuples.List<(char,int)>sequences=newList<(char,int)>();intfirstCharInSequence=0;for(inti=1;i<n;i++){if(s[i]!=s[i-1]){// Save the sequence to our listsequences.Add((s[i-1],i-firstCharInSequence));// Reset the countersfirstCharInSequence=i;}}// Add the remaindersequences.Add((s[n-1],n-firstCharInSequence));// now e.g. for aabaa we have a list of ('a', 2), ('b', 1), ('a', 2).// Second pass - add all repeated sequences of chars into the total countforeach(varseqinsequences)result+=seq.Item2*(seq.Item2+1)/2;// triangular number sequence// Third pass - account for all palindromes with a different char in the middleintj=0;while(j<sequences.Count-2){// We're moving the window of 3 numbers, from left to right.varleft=sequences[j];varcenter=sequences[j+1];varright=sequences[j+2];// If the characters are the same on the sides,// and if there's only one character in the middle// Then count the widest substring, and all narrower ones.// e.g. aaa_aaa gives us 3 substrings: aaa_aaa, aa_aa, a_a. if(left.Item1==right.Item1&¢er.Item2==1)result+=Math.Min(left.Item2,right.Item2);j++;// Move the window one position to the right}returnresult;}
I do not understand why in the 3rd pass is ans+=min(l[i - 1][1], l[i + 1][1])
and not the summatory of min
f.e in aaabaaa the possible ones aren't
aba
aabaa
aaabaaa
???
whith your code is only aaabaaa
This was alot of help thanks. got really confused at one point, becuase i thought the 2 substrings on the sides of the single character substring had to be the same number of chars.
thanks :D
sdict = []
x = 1
for i in range(1,n):
if s[i] != s[i-1]:
sdict.append((s[i-1],x))
x = 1
else:
x += 1
sdict.append((s[n-1],x))
count = 0
# xxxxx....... etc condition count
for x in sdict:
count += (x[1] * (x[1] + 1)) // 2
# x.x, xx.xx, xxx.xxx .... etc condition count
for i in range(1,len(sdict)-1):
if sdict[i][1] == 1:
if sdict[i-1][0] == sdict[i+1][0]:
count += min(sdict[i-1][1],sdict[i+1][1])
return count
One pass solution with backtracking, collecting all valid palindromes. Passes all tests.
def substrCount(n, s):
# print('---', s)
subs = []
for i, l in enumerate(s):
# collect all single chars
subs.append(l)
if i > 0:
# collect all substrings of same chars behind i
j = i - 1
sub = l
while j >= 0 and s[j] == l:
sub += s[j]
subs.append(sub)
j -= 1
# collect all substrings where middle char is different
# and all chars on left and right are the same
j = i - 1
if s[j] != l:
k = i + 1
sub = l
while j >= 0 and k < n and s[j] == s[k]:
if j+1 < i and s[j] != s[j+1]:
break
sub = f'{s[j]}{sub}{s[k]}'
subs.append(sub)
j -= 1
k += 1
# print(subs)
return len(subs)
Special String Again
You are viewing a single comment's thread. Return to all comments →
Really simple 3 pass solution: 1. Build a list of tuples such that the string "aaabbc" can be squashed down to [("a", 3), ("b", 2), ("c", 1)]. 2. add to answer all combinations of substrings from these tuples which would represent palindromes which have all same letters. 3. traverse this list to specifically find the second case mentioned in probelm
Here is my code:
Implemented your logic in Java. Had to tweak the code to optimise it and also reduced it to 2 passes
Can you please explain the logic/algo in words?
here is problem solution in python java and c++ programming. https://programs.programmingoneonone.com/2021/03/hackerrank-special-string-again-solution.html
My full python implementation and logic is explained in detail.
Hackerrank - Special String Again Solution
The trick to solve this problem is to find all substring for each of the two cases.
Case 1: All characters are same.
For a string with n characters, we can make a total of n*(n+1)/2 substrings. Note substrings keep the same order and don't skip characters. For instance, aaaa will make a, aa, aa, aa, aaa, aaa and aaaa This is because, for a string of size n we can make n - 1 substrings of size 2 and n - 2 substrings of size 3 and so on. This can be generalized as n-(k-1) where k is the length of the substring. So total number of substrings (of all lenghts) is then n-1 + n-2 + ... + n - (k-1) + ... + n - (n-1). This when written in reverse is same as 1 + 2 + ... + n-2 + n-1 + n. The sum of an arithmetic sequence is = n*(first+last)/2. Therefore, the sum of above sequence is n*(1+n)/2
Case 2: Odd length string with all characters same except the middle one
For a string like aaabaaa, the total number of special substrings is equal to the number of repeated characters. For the example above it will be, aba, aabaa, aaabaaa. So when we find a character, c, such that its previous character, pc, is same as its next character, nc, i.e. pc == nc but not same as itself, i.e. pc != c, we can count the number of times that pc and nc are repeated. Note that, number of times pc is repated may be different than the number of times nc is repated, for instance aaabaa. We take the minimum of the repeated times. To add effeciency, we can create an array that stores the number of times a character is repated at every index. For example, for a string like aaabaa the array will contain 333122
really apperciated, you gave answer to a question asked 2 yrs ago.. it is helpfull for future viewers.
thanks :) here's the code in c++:
kya baat bhaiya mst mtlb gjb explanation .
Thank you! I was looking for this explanation.
Thanks mahak_vmukhi ! I can finally understand everything clearly!
Thank you, Really appriceated.
It is possible to solve with one loop. :)
Sweet! I also wanted to solve it with a single pass and no extra structures. I struggled much more than I was hoping for... here for the curious.
All I learned here is that I don't know how to read C++ lol
I'm In the same boat too lol
O(n) time complexity and O(1) space complexity
Python3 - one loop counting sequences and branch out for xx.xx patterns:
liked your approach.
Thanks mate, this is very clear and concise
It would be very helpful. If you could provide the explanation of your code, or what is the approach.!
Now I am waiting for the solution without using any loop :p
That would be possible with regex, if that would allow to match a matched substring :D
:D:D:D
this looks a lot like my code - also using 2 passes only and also declared a inner class to store the string in a different format
One more Java solution :)
Tried to simplify the code above and optimize a little bit by avoiding iterating over the repeatable symbols and jumping straight to the distinct by incrementing for loop counter and replacing sum with n*(n+1)/2
Crazy thinking... Good one bro
beauty
Super-cool! I used it (together with some luck that allowed me to find more small and meaningful test cases) to debug a similar idea I had, only that it works strictly forward rather than expanding from the middle:
Just as a question,
Where is this formula from?
Mount the sequence and you will have a better idea:
2 chars: 2 + 1 = 3
3 chars: 3 + 2 + 1 = 6
4 chars: 4 + 3 + 2 + 1 = 10
Notice? The val of 2 chars is ( 2 + 1 ) * 2 / 2
Total number of substring that can be produced out of string of length n is n*(n+1)/2.
it's the triangle numbers!
It comes from calculate the number of substring in the string. I saw it using an old technique, imagine that "0" are characters and "1" are separators between chars. Then a string can be represented as a binary chain "101010101...1". And a substring is then any subchain which start in "1" and ends in another different "1", being the chars between "1" the substring. Then, is just calculate how many differents ways there are to take two differents "1" in this repr, due two differents "1" always define a substring. If there are n "0" then there are n+1 "1" and to take two "1" in n + 1 possibles is equal to combinations(n + 1, 2) = n+ 1!/(n+1 - 2)!* 2, wich is equals to (n+1) * n / 2.
very good man ,impressed
Brilliant man!!
Thank you Your code helped me and it is easy to understand.
here is my java solution
This is an absolutely brilliant approach
This is what I came up with. It works for the cases given in the description. But not for the submit cases. Do you have any idea as to why it doesn't work for other cases
}
Here is my C# version:
Here is another solution in C# without using additional list:
class point{ public: char key; long count; point(char key,long count){ this->key = key; this->count = count; } };
int main() { std::vector _v; long count = 1; int n; scanf("%d",&n); char str[n]; std::cin >> str; char ch = str[0];
}
can youb explain me 3rd pass
Checks if it forms a palindrome. The condition for that is the current element should have count 1, and we take the least of the counts on either side of the current element if they are equal. Eg., aaabaa b is the current element and we take the palindrome (aabaa)
Smart solution. Thank you!
i didn't understand here, for i in range(1, len(l) - 1): f l[i - 1][0] == l[i + 1][0] and l[i][1] == 1: ans += min(l[i - 1][1], l[i + 1][1]) please explain me..!!
This is the 3rd pass, it tries to find a letter cluster with length 1, and its left letter cluster and right letter cluster are the same letter. For example bbbabb. 'a' it the letter cluster with length 1, and its left letter cluster "bbb" and its right letter cluster "bb" have the same letter 'b'. And number of the palindrome is limited by the min length of those two side letter cluster. For example, it has "bab", "bbabb", two palindrome, equals to the length of right letter cluster. I am sorry for my English. Hope you can understand.
How this logic will work to count 'cbbabbc' ? Since it's checking only i-1, i and i+1 it will count 'bbabb' correctly but how about 'cbbabbc' palindrome string ?
Can you please explain ?
Because this is special palindrome string, case 2: All characters except the middle one are the same, e.g. aadaa. So there is no need to consider i-2 and i+2. two neibors should be same.
Why this approach return 11 for input 'cbbabbc' as an example ?
Correct answer should be 12 in this case. (c, b, b, a, b, b, c, bb, bb, bab, bbabb, cbbabbc)
I think there is a bug in 3rd testCase as its only checking i-1, i and i+1.
There should be a recursive way to keep check n-1 and n+1 terms until they are matching or something like that, then start taking min of each of those.
"cbbabbc" is a palindrome, but the question is asking for special palindromes, which are palindromes that consist of only one letter (e.g., "bbbb", "aa", "ccccc") or palindromes that consist of only one letter and are separated by a single letter (e.g., "bbbabbb", "cac").
Since "cbbabbc" contains two different letters on either side of the dividing letter, it's not counted
Is there any way to do it using regex?
Yes, in some way.
I used two regular expressions, this is my python 3 code:
I used triangular number to sum all repeated words:
triangular number function t1=1, t2=3, t3=6, t4=10, t5=15
that is if you sum (len -1) of repeated words sequence, you'll have all combinations. eg. aaaa: (3²)+3//2 = 6
This works! I wish I understood the triangular number part
The triangular number sequence is simple:
(sequence number) -> (value)
t0 -> 0
t1 -> 1
t2 -> 3
t3 -> 6
t4 -> 10
...
The result of next value is the sum of previous sequence number (t+1) plus previous value.
There are many applications using this sequence. You can see more about here: https://en.wikipedia.org/wiki/Triangular_number
In this problem it's possible to find the number of repeated char combinations throught triangular number sequence. Here an example:
t0 -> a -> 0
t1 -> aa -> 1
t2 -> aaa -> 3
t3 -> aaaa -> 6
t4 -> aaaaa -> 10
...
It's the same sequence, but you'll need to use len()-1.
So far, the best solution that I found it.
Hello, can you explain your logic without using regular expessions? How can I do this problem just using the triangle number?
thx in advance
Hi. I'm not sure if is possible to solve the problem using triangular number only. Triangular number is just an especific sequence and in this solution, triangular number is part of the solution. I'll try explain the solution step by step :
1) len(s) -> count all char of the word;
2) exp1 -> count all words that follow this rule: a_a also aaaa_aaaa;
3) exp2 -> count all repeated char of the word and with triangular number all combinations of these repeated chars. Example of this step is: aaaa has the combination of:
'aa'+'aa'+'aa'
+'aaa'+'aaa'
+'aaaa' = 6 (realize 6 is the same T3 of triangular number sequence).
The final answer is the sum of all these steps.
I don't understand exp1. I mean why do you need to put group #3 (?!\1) ? can you please explain?
I little late but ... I'll try to explain. As I said before, exp1 -> count all words that follow this rule: a_a also aaaa_aaaa; So, in this case the middle word needs to be different from match group 1, that's why this negative lookahead (?!\1) is required.
Could you please explain step by step why (([a-z])\2*)(?!\1)(?=[a-z]\1) could find out the pattern aa_aa, aaa_aaa and so forth?
there are three different character in your last substring which is not allowed.
May I know why this works?
(i[1] * (i[1] + 1)) // 2
Yeah this doesn't make sense to me. Wouldn't this result in 12 for the tuple ['a', 3]?
EDIT: Oh I see. The // 2 showed up as a comment in the code, and I forgot this was Python.
wow how did you think of that 0.o
No Need for the // in ans += (i[1] * (i[1] + 1)) // 2 as i[1] will always be greater than 1 and hence i[1]+1 will be even when i[1] is odd and vice-versa. So this formula yeilds only integer results.
very nice!
Thanks for the logic and style, I'm sure many have learned from it! Following the same logic described, I have the same solution written in C++ for anyone who wanted to see it in the language
Here it is:
long substrCount(int n, string s) {
}
After this, my code passed all tests. I really like the logic. The for inside for actually could be done with just one for loop. Here is my relevant JAVA solution. It passed all the tests.
static class Point{ char text; long counter;
Thank you
please explain or tell about your concept
how on earth did you came up with this solution? can someone be trained on being able to find such logics? do you have an advice? because i would have never found the solution you made yet i want to be this good at finding solutions like this.
Nice solution! One thing that condenses the code a bit is using itertools.groupby to turn the logic of the first loop into a 1 liner:
Thanks!
For those who doesn't understand this line,
for i in l: ans += (i[1] * (i[1] + 1)) / 2
its from a formula n(n+1)/2 which give the sum of all term, like n = 5, 1+2+3+4+5 = 5(5+1)/2 = 15.
Its used because if you have "aaaa" , you can have "a,a,a,a", "aa,aa,aa", "aaa,aaa" and "aaaa", we can see the partern of 4,3,2,1 groups, so in this case there's 15 groups!
thank you!
excellent solution - there is a detailed explanation on this page if anyone else is interested
Wow nice solution. I didn't understand the intuition behind this line: ans += (i[1] * (i[1] + 1)) i.e if all chars are same. Can anyone comment on that ?
i think it's looking to count all possible sub-strings of a string. so if the string length is n, the number of sub-strings will be (n*(n+1))/2. you can see the 2 commented out in the solution - not sure why
it's floor division and not a acomment
Appears that RLE (run length encoding) compression is the consensus; I did so too. My implementation ran through the list twice instead - just makes the code all the more clear.
Nice solution, thanks!!
I feel this is a very complicated answer. You can solve this problem in 10 lines, using the same logic as you would manually do when you solve it by hand : For each index i in the string, I create a cursor k that starts from i and goes forward until it meets a different letter than s[i] at s[i+k]. Then I check if the string starting from s[i] centrered on s[i+k] could be a palindrome.
I put my code in this discussion
I can't quite figure out the formula in the 2nd pass
How is this derived? Emprically I understand that it is correct. But I can't quite understand why.
If there are k similar characters in a raw, number of palindroms will be 1+2+..+k; If current character differs from the prvious one it might also be a palindrom, and half length of the palindrom would be the number of palindroms: aaacaaa -> half length is 3 and there are 3 palindroms: aca, aacaa, aaacaaa
Simplified way of writing 1st pass, no count, cur required:
C# Code:
I passed 3 test cases but when I click on submit it doesn't pass any other. I can't even debug as the data is very large and I can only feed 40kb in the input field. Please help me!
Thanks.
Nice solution :)
Similar solution by using groupby() function:
Here's a rendition that made a bit more sense to me. The second pass uses the "nth triangle number" https://math.stackexchange.com/questions/593318/factorial-but-with-addition
Here's my implementation your logic with 2 passes:
I programmed like a hell but turned out this much easy. Thank you!
First pass can be done without using second variable 'cur'
I have done in similar way considering a dict.Can u please explain the 3rd pass in detail(logic)
great approach
Here is a single pass implemetation of the same logic....
I pretty much had the same solution, in two passes and with a few minor differences. in c++:
That is wonderful code!
Can anyone explain me 2nd & 3rd pass?
I have explained in detail the complete logic and program for beginners while intermediates can just read the logic part to get the idea. The logic is faster than using regex method by 5% and the complexity is O(n). I have used recursions. The link to the github page is here.
The raw code is here,
Thank you for the solution! I've implemented it similarly in C#:
great solution! I implemented it in C++ Cheers!
I do not understand why in the 3rd pass is ans+=min(l[i - 1][1], l[i + 1][1]) and not the summatory of min f.e in aaabaaa the possible ones aren't aba aabaa aaabaaa ??? whith your code is only aaabaaa
I've tried to understand the algorithm at first place by just reading your 3 steps description, but I fail.
Thanks for you code (I knew it's bad not thinking by myself), but without the code I cannot make it. It's genious solution.
Hi! can you explain me why this formula: (i[1] * (i[1] + 1)) // 2 works?
Maybe is related with combinatorics, the thing is that I don't understand that.
Thank you for your time
converted to java using your logic a simplified
import java.io.; import java.math.; import java.security.; import java.text.; import java.util.; import java.util.concurrent.; import java.util.regex.*;
class point { char ch; int count; point(char ch,int count) { this.ch=ch; this.count=count; } } public class Solution {
}
Thanks for the simple solution. I especially found the 3rd pass to be verify useful (that was the 'aha' moment for me):
fucking good :)
here is java
import java.io.; import java.math.; import java.security.; import java.text.; import java.util.; import java.util.concurrent.; import java.util.regex.*;
public class Solution {
}
Thanks! I didn't think of first organising into tuple array
c++ code
long substrCount(int n, string s) {
}
}
I think people should post their pseudocode and explain how it might work to pass all test cases
Sir, can you please explain about the formula you used in second pass.
This was alot of help thanks. got really confused at one point, becuase i thought the 2 substrings on the sides of the single character substring had to be the same number of chars. thanks :D
No because ab and ba are not the same on either side of abcba. would have to be abcab. i believe havnt looked in a while
very smart approach to reduce the string to another structure
Thank you!
nice thank u
Great. Super understandable
Like! Same in java :
def substrCount(n, s):
Cool! Here's a Ruby version:
One pass solution with backtracking, collecting all valid palindromes. Passes all tests.
Here is javascript code:
function substrCount(n, s) { let count = 0; const arr = s.split(''); const tuple = [[arr[0], 1]];
}