简体   繁体   中英

Is there a more efficient way to count the number of times each consecutive letter appears in a string? (java)

I'm making a method that takes a specified string and counts the number of times each consecutive letter appears.
For example: encode("aabbcc"); should give the output 2 2 2, since there are 2 letters appearing in sequence

My code was:

for(int i=0;i<word.length()-1;i++) {
    int count=1;

    if(i!=word.length()-1) {
        //System.out.println(word.charAt(i));
        //System.out.println(word.charAt(i+1));
        try {
            while(word.charAt(i)==word.charAt(i+1)) {
                count++;
                i++;
            }
        } catch (Exception e) {}

        System.out.print(count+" ");
    }
}

But it kept giving me an IndexOutOfBoundsException so i just added a try and catch block but I know there is a better way

Dont look ahead like this word.charAt(i)==word.charAt(i+1) as this gives you the error. Instead, check if letter at index i is the same as letter from previous iteration - and if so - increment the counter.

Another approach would be to use regex.

String str = "aabbccxa";
String result = Pattern.compile("(?<=(.))(?!\\1)")
                       .splitAsStream(str)
                       .map(e -> String.valueOf(e.length()))
                       .collect(Collectors.joining(" "));
System.out.println(result);

How it works:

  • split the string at groups of same chars
  • map each group to its length
  • collect using space as a delimeter

I think it's a matter of taste if this is better than the other answers. More efficient than a simple loop? I think that also depends on the input.

Welcome to SO. In general if you receive an exception you need to work out why rather than adding a catch.

A simpler solution would be:

Deque<Integer> counts = new LinkedList<>();
for (int i = 0; i < word.length(); i++) {
    if (i > 0 && word.charAt(i) == word.charAt(i - 1))
        counts.addLast(count.removeLast() + 1);
    else
        counts.addLast(1);
}

At the end of the loop, i+1 is out of bounds.

You can count them like this:

if(i > 0 && word.charAt(i) == word.charAt(i - 1))

You could test that i + 1 is less than word.length() in your while loop condition. You might also save word.length() to a local variable. Like,

int len = word.length();
for (int i = 0; i < len - 1; i++) {
    int count = 1;
    while (i + 1 < len && word.charAt(i) == word.charAt(i + 1)) {
        count++;
        i++;
    }
    System.out.print(count + " ");
}
    String str="aabbbccaaaacds";
    boolean flag=false;
    int cnt=1;
    for (int i = 0; i < (str.length()-1); i++) {  // iterate till length -1 as we are using str.charAt(i+1) 
        if(str.charAt(i)==str.charAt(i+1)) {
            flag=true; // keep flag as true till matching chars
            cnt=cnt+1;
        }
        else {
            flag=false; 
        }
        if(flag==false && cnt>=2) {
            System.out.println("char="+str.charAt(i)+", occurance="+cnt);
            cnt=1;
        }
        if(i==(str.length()-2) && flag) { // only used when we are at comparing last two characters
            System.out.println("char="+str.charAt(i)+", occurance="+cnt);
        }

    }

Output:

char=a, occurance=2
char=b, occurance=3
char=c, occurance=2
char=a, occurance=4

You could collect them in a map and and print them out. This prints out the actual strings that match the count but it could easily be tailored however you want.

      String str = "aabbbbcccccdddddaaaaz";

      Map<Integer, List<String>> freq = Arrays.stream(
            str.replaceAll("(([a-z])\\2*)", "$1,").split(",")).filter(
                  a -> a.length() > 1).collect(
                        Collectors.groupingBy(String::length));

      freq.forEach((k, v) -> System.out.println(k + " : " + v));

prints the following.

2: [aa]
4: [bbbb, aaaa]
5: [ccccc, ddddd]

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