6

I need an algorithm that verify with the fastest possible execution time, if a string is a palindrome ( the string can be a proposition with uppercase or lowercase letter, spaces etc.). All of this in Java. I got a sample :

bool isPalindrome(string s) {
    int n = s.length();
    s = s.toLowerCase();
    for (int i = 0; i < (n / 2) + 1; ++i) {
        if (s.charAt(i) != s.charAt(n - i - 1)) {
            return false;
        }
    }
    return true;
}

I transformed the string in lowercase letter using .toLowerCase() function, but I don't know how much it affects the execution time .

And as well I don't know how to solve the problem with punctuation and spaces between words in a effective way.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Bogdan Mursa
  • 63
  • 1
  • 2
  • 10

7 Answers7

10

I think you can just check for string reverse, not?

StringBuilder sb = new StringBuilder(str);
return str.equals(sb.reverse().toString());

Or, for versions earlier than JDK 1.5:

StringBuffer sb = new StringBuffer(str);
return str.equals(sb.reverse().toString());
Joetjah
  • 6,292
  • 8
  • 55
  • 90
Andrey
  • 1,476
  • 1
  • 11
  • 17
  • StringBuilder have one, still not the same as in the answer. – 3yakuya Jan 28 '14 at 11:09
  • 1
    @AndreyKnuppVital Haha agreed, you were at least 0.1 seconds faster! – Joetjah Jan 28 '14 at 11:13
  • @Joetjah: Or not. [Benchmarking is hard](http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java). – maaartinus Jan 28 '14 at 11:43
  • The expression `sb.toString()` returns `str`, so it's wasting time. – maaartinus Jan 28 '14 at 11:46
  • 2
    @AndreyKnuppVital: :D:D:D OK, I can see my reading skills could use some upgrade. – maaartinus Jan 28 '14 at 11:48
  • @maaartinus I wanted to reply something like that to your comment, but Andrey was at least 0.1s faster. Again. – Joetjah Jan 28 '14 at 11:49
  • 1
    @maaartinus On topic: the problem is that `String` doesn't have a `reverse()` method. If you try `str.equals(str.reverse())`, you'll get a compile error. Besides that, trying `.equals()` on StringBuilder-objects will check if they are the same reference, not if they contain the same String value. Therefore, I used `.toString()`. – Joetjah Jan 28 '14 at 11:53
  • 1
    @Joetjah: My reading skills might be even worse than I thought, but no. There's `toString` used twice. What you're saying concerns the second use. The first one just returns the original `str`. – maaartinus Jan 28 '14 at 12:03
  • @maaartinus 10 points for Griffondor, I've edited! Good call! – Joetjah Jan 28 '14 at 12:08
3

This avoids any copying. The functions isBlank and toLowerCase are rather unspecified in your question, so define them the way you want. Just an example:

boolean isBlank(char c) {
    return c == ' ' || c == ',';
}

char toLowerCase(char c) {
    return Character.toLowerCase(c);
}

Don't worry about the costs of method calls, that's what the JVM excels at.

for (int i = 0, j = s.length() - 1; i < j; ++i, --j) {
    while (isBlank(s.charAt(i))) {
        i++;
        if (i >= j) return true;
    }
    while (isBlank(s.charAt(j))) {
        j--;
        if (i >= j) return true;
    }
    if (toLowerCase(s.charAt(i)) != toLowerCase(s.charAt(j))) return false;
}
return true;

Try to benchmark this... I'm hoping mu solution could be the fastest, but without measuring you never know.

Raman Sahasi
  • 30,180
  • 9
  • 58
  • 71
maaartinus
  • 44,714
  • 32
  • 161
  • 320
2

Your solution seems just fine when it comes to effectiveness.

As for your second problem, you can just remove all spaces and dots etc before you start testing:

String stripped = s.toLowerCase().replaceAll("[\\s.,]", "");
int n = stripped.length();
for (int i = 0; i < (n / 2) + 1; ++i) {
    if (stripped.charAt(i) != stripped.charAt(n - i - 1)) {
...
Keppil
  • 45,603
  • 8
  • 97
  • 119
1

Effective is not the same of efficient.

Your answer is effective as long you consider spaces, special characters and so on. Even accents could be problematic.

About efficiency, toLowerCase is O(n) and any regexp parsing will be O(n) also. If you are concerning about that, convert and compare char by char should be the best option.

rdllopes
  • 4,897
  • 4
  • 19
  • 36
1

Here is my try:

public static boolean isPalindrome(String s)
 {
    int index1 = 0;
    int index2 = s.length() -1;

    while (index1 < index2)
    {
        if(s.charAt(index1) != s.charAt(index2))
        {
            return false;
        }
        index1 ++;
        index2 --;
    }
    return true;
 }
guest
  • 11
  • 1
0

In normal cases :

 StringBuilder sb = new StringBuilder(myString);
 String newString=sb.reverse().toString();
 return myString.equalsIgnoreCase(newString); 

In case of case sensitive use :

StringBuilder sb = new StringBuilder(myString);
String newString=sb.reverse().toString();
return myString.equals(newString); 
Lovis
  • 9,513
  • 5
  • 31
  • 47
Raj Kumar
  • 402
  • 4
  • 9
0

Here's some insight to my way of detecting a palindrome using Java. Feel free to ask question :) Hope I could help in some way....

import java.util.Scanner;
public class Palindrome  {
   public static void main(String[]args){
      if(isReverse()){System.out.println("This is a palindrome.");}
      else{System.out.print("This is not a palindrome");}
   }
   public static boolean isReverse(){
     Scanner keyboard =  new Scanner(System.in);
      System.out.print("Please type something: "); 
      String line = ((keyboard.nextLine()).toLowerCase()).replaceAll("\\W","");
      return (line.equals(new StringBuffer(line).reverse().toString()));
   }
}