3
\$\begingroup\$

I am trying to find the number of string pairs in an array that are palindromes.

import java.io.BufferedReader;
import java.io.InputStreamReader;
class TestClass {
public static void main(String args[] ) throws Exception {
 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 String line = br.readLine();
 int N = Integer.parseInt(line);
 int count = 0;
 String s[] = new String[N];
 for (int i = 0; i < N; i++) {
 s[i] = br.readLine(); 
 } 
 for (int i = 0; i < N; i++) {
 String str = s[i];
 for(int j=i; j<N; j++) {
 StringBuilder sb = new StringBuilder(s[j]);
 if(str.equals(sb.reverse().toString())){
 count++;
 }
 } 
 }
 System.out.print(count);
}
}

Is there a more efficient way to do this?

Quill
12k5 gold badges41 silver badges93 bronze badges
asked Jul 25, 2015 at 5:12
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Review! Please declare your cross-post to avoid wasting others' time. \$\endgroup\$ Commented Jul 25, 2015 at 5:31

3 Answers 3

4
\$\begingroup\$

Is there a more efficient way to do this?

At the moment you have an \$O(N^2)\$ algorithm as you can see from the nested loops up to N This is not as efficient as it could be.

What you should have is an \$O(N \log N)\$ or \$O(N)\$ algorithm. To achieve \$O(N)\,ドル you need to pass over the words just once, ideally as you read them avoiding the need for a String[]. To do this, you need to store the words in a data structure with \$O(1)\$ (at least amortized) access. e.g. a HashSet or a HashMap.

It could look like this:

start with a HashSet of words so far. initially empty.
for each word *as you read it*.
 compute its palindrome.
 remove this palidrome from the set 
 and see if it was there. i.e. Set.remove(reverse) will do this.
 if it was there you have a match
 otherwise add the word to the set.
done

Instead of three loops, you only need one.

You can see that you pass over the words just once and each operation is \$O(1)\$ with the number of words. This assumes that the words length has some natural upper bound and the length of the words doesn't matter.

maaartinus
13.6k1 gold badge35 silver badges73 bronze badges
answered Jul 25, 2015 at 5:49
\$\endgroup\$
5
  • 1
    \$\begingroup\$ I'd bet, he meant things like 1. N is not a good variable name according to conventions, 2. it should be more descriptive, e.g., stringCount, 3. it'd be smarter to reverse s[i] instead of s[j] as otherwise the complexity is \$N^2 \cdot L\$ where \$L\$ is the string length, etc. +++ There are many beginners here who can profit more from such step-wise advice than from a much smarter solution like yours. Sure, a complete rewrite is the way to go in this case and this makes the tiny steps irrelevant for this problem. However, it's something the OP can learn from. \$\endgroup\$ Commented Jul 25, 2015 at 8:39
  • \$\begingroup\$ I see nothing wrong with this answer, in any of the revisions. I'd definitely say this counts as a review. \$\endgroup\$ Commented Jul 25, 2015 at 13:18
  • 1
    \$\begingroup\$ A note though, there's no need to use Set.remove as Set.add will return false if it was there already. \$\endgroup\$ Commented Jul 25, 2015 at 13:20
  • 1
    \$\begingroup\$ @SimonAndréForsberg Neither do I, but Quill did (in the now removed comments), so I explained what he might have meant. +++ Without Set#remove you'll get different results in case of duplicates. It's hard to tell what's right then. \$\endgroup\$ Commented Jul 25, 2015 at 18:58
  • \$\begingroup\$ @maaartinus thank you. This example is clearer to me. The question was cross posted on stack over flow and I believe the OP really just wanted to know how to make the code more efficient that a broad code review. \$\endgroup\$ Commented Jul 26, 2015 at 13:29
0
\$\begingroup\$
  1. Make 2 sets, one for reversed strings and one for normal strings.
  2. Use the retainAll() method to eliminate all the strings that aren't in both sets.
  3. Return the size of the set.
Quill
12k5 gold badges41 silver badges93 bronze badges
answered Jul 25, 2015 at 5:23
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and how it improves upon the original) so that the author can learn from your thought process. \$\endgroup\$ Commented Jul 25, 2015 at 5:35
  • 2
    \$\begingroup\$ Note: your choice of set will matter for performance. \$\endgroup\$ Commented Jul 25, 2015 at 5:50
0
\$\begingroup\$
  • Uppercase variable names like N do not follow Java conventions, which is camelCase.

  • N, s and str aren't too descriptive names. I'd name them number, strings and string.

  • I'd simplify:

    String line = br.readLine();
    int N = Integer.parseInt(line);
    

    to:

    int number = Integer.parseInt(br.readLine());
    
  • I'd not create StringBuilder sb = new StringBuilder(s[j]), which is expensive, inside loops but outside and use Java clearing the string buffer after loop.

answered Jul 26, 2015 at 17:40
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.