Remove characters from the middle of a String

Asked

Viewed 745 times

-1

Write a program that, starting with a word defined by you, prints on the screen the words resulting from removing, one by one, the middle characters of the previous word, until you reach a word with a single character. If the number of characters in the word is even, the first of the two characters in the middle.

Example: if the word is rapsodia, the program should print the words:

Rhapsody, rhapsody, rhapsody, rhapsody, rhapsody, rhapsody.

This is what I started to do:

public class Exercicios {

    //5
    static String semLetraMeio(String s) {

        int sLength = s.length();
        while(sLength > 1) {

            int midIndex = sLength / 2;
            s = s.substring(0, midIndex).concat(s.substring(midIndex + 1, sLength));
            System.out.println(s);

        }

        return s;
    }


    public static void main(String[] args) {
        semLetraMeio("zero");

    }

}
  • In my opinion it would be better to make a recursive call and create fewer variables, like here: java
static String semLetraMeio(String s) {
 if (s != null) {
 if (s.length() == 0)
 return s;
 System.out.println(s);
 return semLetraMeio(new StringBuilder(s).deleteCharAt(s.length() % 2 == 0 ? s.length() / 2 - 1 : s.length() / 2).toString());
 }
 return s;
 }


  • @I don’t see why recursion is better for this case. You may have created fewer variables, but it will take up more space in the stack with this bunch of recursive calls (maybe it’s even worse than "avoid variables") - and doing everything in a row just to avoid variables doesn’t always make the code "better". Variables are not an evil to be avoided, you use when it makes sense and it’s only bad to create variables that serve no purpose or make the code less clear. And I think it makes sense to create one for the index to be removed, for example, since it is the central point of the algorithm :-)

  • In this case: static String semLetraMeio(String s) {
 if (s != null) {
 if (s.length() == 0)
 return s;
 while (s.length() > 0) {
 System.out.println(s);
 s = new StringBuilder(s)
 .deleteCharAt(s.length() % 2 == 0 ? s.length() / 2 - 1 : s.length() / 2)
 .toString());
 }
 return s;
 }
 return s;
}

  • Only since strings are immutable, that would be better: static String semLetraMeio(String s) {
 if (s != null) {
 if (s.length() == 0)
 return s;
 StringBuilder sb = new StringBuilder(s);
 while (sb.length() > 0) {
 System.out.println(sb);
 sb.deleteCharAt(sb.length() % 2 == 0 ? sb.length() / 2 - 1 : sb.length() / 2);
 }
 return sb.toString();
 }
 return s;
}

2 answers

0


The problem is that you calculate the size of String only at the beginning, before the while. But after the first iteration, the String will have one character less, and then you will try to catch a substring until sLength, which is now larger than the size of String (after all, you removed a character), and this will cause a StringIndexOutOfBoundsException. And even if this error did not occur, the program would go into loop infinite, after all sLength is never updated on while.

Then one solution would be to upgrade the size of the String with each iteration. Another detail is that when the size of the String is par, you are picking up the second character of the middle, so an adjustment has to be made for this case:

static void semLetraMeio(String s) {
    System.out.println(s);
    int sLength = s.length();
    while (sLength > 1) {
        int midIndex = sLength / 2;
        if (sLength % 2 == 0) { // ajuste para quando o tamanho é par
            midIndex--;
        }
        s = s.substring(0, midIndex).concat(s.substring(midIndex + 1, sLength));
        System.out.println(s);
        sLength = s.length();
    }
}

Another detail is that I changed the return of the method to void, because it doesn’t seem to make sense for him to return anything (he will return the last substring found). Well, if you think it makes sense, just put back the return and the return of the method to String.

I also put a println at the beginning to print the String original. Calling semLetraMeio("rapsodia"), the exit is:

rapsodia
rapodia
rapdia
radia
raia
ria
ra
a

Another alternative is to use a StringBuilder, that has the method deleteCharAt, which serves precisely to erase a character in a given position:

static void semLetraMeio(String s) {
    System.out.println(s);
    StringBuilder sb = new StringBuilder(s);
    while (sb.length() > 0) {
        int midIndex = sb.length() / 2;
        if (sb.length() % 2 == 0) {
            midIndex--;
        }
        sb.deleteCharAt(midIndex);
        System.out.println(sb);
    }
}

If you want the method to return one String, as your original code does, switch to:

static String semLetraMeio(String s) {
    System.out.println(s);
    StringBuilder sb = new StringBuilder(s);
    while (sb.length() > 0) {
        int midIndex = sb.length() / 2;
        if (sb.length() % 2 == 0) {
            midIndex--;
        }
        sb.deleteCharAt(midIndex);
        System.out.println(sb);
    }
    return sb.toString();
}

0

Your logic is right, you just forgot a few details:

public class Main {
   // ja que a função apenas printa as Strings não há necessidade de retornos
   static void semLetraMeio(String s) {
        int sLength = s.length();
        while(sLength > 1) {
          int midIndex = (sLength - 1) / 2; // vc deve diminuir 1 no length para pegar o primeiro char do meio caso o numero seja par
          s = s.substring(0, midIndex).concat(s.substring(midIndex + 1));
          sLength = s.length(); // vc tbm esqueceu de definir o novo tamanho da string, causando um loop infinto
          System.out.println(s);
        }
    }


    public static void main(String[] args) {
      semLetraMeio("rapsodia");
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.