简体   繁体   中英

What is the difference between searching for a char in a char[] vs searching for a String using the String.indexOf() method?

private static int getTotalWordValue(String word) {
    int totalWordValue = 0;

    // Code that produces correct results.
    for(int i=0; i < alpha.length(); i++) {
        char letter = alpha.charAt(i);
        for(char ch: word.toCharArray()) {
            if(letter == ch) {
                totalWordValue += i+1;
            }
        }
    }

    // Code that produces incorrect results.
    totalWordValue = 0;
    for(int i=0; i < alpha.length(); i++) {
        String letter = String.valueOf(alpha.charAt(i)); // <-- here?
        if(word.indexOf(letter) != -1) {
            totalWordValue += i+1;
        }
    }

    return totalWordValue;
}

Upon running the above code to solve Project Euler Problem 42 , I am getting different results. The first 'for' loop shown above outputs the correct results and the second 'for' loop outputs incorrect results.

The above code takes a String and returns its word value. For example, the word SKY will return a word value of 55 as the letters in this word add as follows (starting at 1):

  • S = 19 (19th position of the alphabet)
  • K = 11 (11th position of the alphabet)
  • Y = 25 (25th position of the alphabet).

19 + 11 + 25 = 55.

I have reduced the problem to the above code and do not understand why this occurs. Perhaps I have missed an important piece of information as it relates to the Java String class and its methods.

I am running Java 8 in Eclipse Neon.3 Release (4.6.3) on Windows 10.

The two pieces of code are entirely different.

In both cases you have an outer loop which serves up each character of the string alpha in the variable letter .

In the first case, you then have an inner loop which runs through every character of the string word and counts every matching occurrence of letter . When the inner loop has counted every occurrence of letter in word , the outer loop moves on to the next letter .

In the second case, there's no inner loop. Each time around the outer loop you use word.indexOf(letter) to try to find the index of the first occurrence of letter in word . If there is one, you advance your count. Either way, you're now done with that letter and the outer loop moves on to the next letter . There might have been other occurrences of letter in word , but this case didn't try to find them and count them.

The word value is incorrect in the second implementation for words that contain some letters multiple times. For example for WOOD, the first method will calculate 3 + 14 + 14 + 22, but the second will calculate 3 + 14 + 22.

Why? The first method iterates over characters of the word :

 for(char ch: word.toCharArray()) { if(letter == ch) { totalWordValue += i+1; } } 

The second method iterates over characters of the alphabet :

 for(int i=0; i < alpha.length(); i++) { String letter = String.valueOf(alpha.charAt(i)); // <-- here? if(word.indexOf(letter) != -1) { totalWordValue += i+1; } } 

So in the example of "WOOD", "O" will be counted only once, instead of twice.


As an aside, the conversion to String is pointless here:

 String letter = String.valueOf(alpha.charAt(i)); if(word.indexOf(letter) != -1) { 

A better way to write the same thing:

char letter = alpha.charAt(i);
if (word.indexOf(letter) != -1) {

(But the implementation would still be incorrect.)


Finally, if the alphabet is English AZ, then a faster implementation is possible:

int totalWordValue = 0;
for (char c : word.toCharArray()) {
  if ('A' <= c && c <= 'Z') {
    totalWordValue += (c - 'A') + 1;
  }
}

return totalWordValue;

indexOf has 4 overloaded method and one of them except character argument and return the index of the first occurrence of the character in the character sequence.

Now, coming to you question. In your scenario indexOf and charAt will behave same because you are passing ONLY character. And, since internally, But, imagine, you have a String and you wanted to check and get the index of it from another long String . Then what would you do ? There comes indexOf

I know this doesn't necessarily solve your question about the differences between the mentioned methods, but others have answered well enough on that.

You want the sum of the positions in the alphabet of the letters of a String? We can do that in one loop with some arithmetic, without the added overhead of the inner loops or the alpha constant.

Like so:

public static int getWordValue(String word) {
    int value = 0; //total word value
    for(char c : word.toLowerCase().toCharArray()) { //iterate over character array of lower case string
            int charAsInt = (int) c; //cast char to int, giving the ASCII value
            if(charAsInt <= 122 && charAsInt >= 97) { //122 is the ASCII value of 'z', and 97 is 'a'
                value += (charAsInt - 96); //only subtract 96 because we want 'a' to be 1, not 0
            }
     }
    return value;
}

If the reason this works is unclear to you now, it will become evident upon examining an ASCII to decimal table. Let's check one out.

ASCII到十进制表

Make note of the values of lowercase 'a' and lowercase 'z'. They are our lower and upper bounds, respectively. We simply loop over each lower case character, converting it to its ASCII decimal value with an int cast. Then we subtract our ASCII value by the value of 'a', minus one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM