last week I entered HackerRank Week of Code 32, a week-long competition, with 6 coding challenges, ranging from easy to hard. I am satisfied with my result at this particular competition but I also would like to understand where I failed.
The competition is over since monday morning so it's not to cheat in the competition that I ask help.
The challenge I'm blocking on his of medium difficulty (says HackerRank competition, I found it hard enough^^).
I would like your advice on how I could improve my code performance-wise.
I'll announce the problem, and then show you what I've done
GEOMETRIC TRICK:
Consider a string \$s\$ of length \$n\$ consisting of the character in the set \$\{a,b,c\}\$. We want to know the number of different \$(i,j,k)\$ triplets (where \$0 \le i,j,k \lt n\$) satisfying two conditions:
\$s[i] = “a”, s[j] = “b”, s[k] = “c”\$
\$(j + 1)^2 = (i + 1)(k + 1)\$
We consider two triples \$(i,j,k)\$, and \$(x,y,z)\$, to be different if and only if \$i \ne x\$ or \$(j \ne y)\$, or \$(k \ne z)\$.
Given \$n\$ and \$s\$, find and print the number of different \$i,j,k\$ triples. My approach
Example
Given the string "ccaccbbbaccccca" of length 15, the final result is 2.
- {2,5,11} satisfy both conditions
- s[2] = 'a', s[5] = 'b' and s[11] = 'c'
- (5 + 1)² = (2 + 1)(11 + 1)
- {8,5,3} satisfy both conditions
- s[8] = 'a', s[5] = 'b' and s[3] = 'c'
- (5 + 1)² = (8 + 1)(3 + 1)
We find 2 triples that match the 2 conditions so the answer is 2.
The code
gist link = https://gist.github.com/JulienRouse/cafbce417bbc2a4f6303df10df20d445
Code here:
/**
* Consider a string s of length n with alphabet {a,b,c}.
* We look for the number of different triplet (i,j,k) where 0<=i,j,k<n, satisfying!
* - s[i] = "a", s[j] = "b", s[k] = "c"
* - (j + 1)² = (i + 1)(k + 1)
* @param s A string we look the triplet in
* @return Number of different triplets such as enonced above.
*/
public static int geometricTrickv2(String s){
Set<Integer> indexA = new HashSet<>(s.length());
Set<Integer> indexC = new HashSet<>(s.length());
List<Integer> indexB = new ArrayList<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='a')
indexA.add(i);
if(s.charAt(i)=='b')
indexB.add(i);
if(s.charAt(i)=='c')
indexC.add(i);
}
int res = 0;
for(int tmpB:indexB){
int powB = (int)Math.pow((double)(tmpB+1),2);
for(int i=2;i<=Math.sqrt((double)powB);i++){
if(powB%i==0){
if(i != powB/i)
if(indexA.contains(i-1)&&indexC.contains(powB/i-1))
res++;
if(indexC.contains(i-1)&&indexA.contains(powB/i-1))
res++;
else
if(indexA.contains(i-1)&&indexC.contains(i-1))
res++;
}
}
}
return res;
}
Explanation
First thing: I build 2 HashSet with the indexes of the letter 'a' and 'c' and a list of the indexes of the letter 'b' in the string s.
Then, I'll work with the given condition \$(j + 1)^2 = (i + 1)(k + 1)\$, which can be seen as:
- find i and k such as \$i+1\$ and \$k+1\$ are complementary divisor of \$(j+1)^2\$
(By complementary I mean: say you have 25, his divisors are 1,5 and 25. 1 and 25 are complementary in the way that 1*25 = 25, 5*5=25 but 1*5!=25. so 1 and 25 are complementary, 5 is complementary with himself but (1 and 5) and (5 and 25) are not complementary )
To find all the divisor of n, I only need to search up until sqrt(n). (It's a property I remember from high school, hope I didn't screw up) because I can calculate the divisor and their complementary counterpart on the same iteration.
Then once I am calculating those divisor, I need to check if they are in the HashSet containing the indexes of 'a' and 'c', and satisfying the condition.
Complexity
We say m = number of letters 'b' If I'm not mistaken, complexity is \$O(m \sqrt{m})\$ (For each index of 'b', I compute his divisor in \$\sqrt{m}\$ times and every other operation is \$O(1)\$ or not in the loop)
My problem
When I submitted my code to the challenge, the result where correct when string s was small, but quickly timed out for bigger input. There must be a better solution but I can't find so if anybody got suggestions on algorithms I would greatly appreciate.
Also if you have any tips to give me about code clarity, about problem solving or anything that makes me learn and improve. It will be really great.
Thanks for reading all the way, sorry for my English.