Обратные слова в строке

Мне нужно перевернуть строку «Он есть один», чтобы «один был Он». Я написал несколько программ на Java, но ищу другие лучшие решения. Предложите любые возможные способы минимизации текущей программы.

Первый подход:

class StringRev{
    public static void main(String args[]){
    String str = "He is the one";
    String temp = "";
    String finalString = "";
        for(int i =str.length()-1;i>=0;i--){
            temp +=i!=0?str.charAt(i):str.charAt(i)+" ";
            if(str.charAt(i) == ' '||i==0){
                for(int j=temp.length()-1;j>=0;j--){
                    finalString += temp.charAt(j);
                }
                temp = "";
            }
        }
            System.out.println(finalString);
    }
}

Второй подход:

class StringRev2{
    public static void main(String args[]){
    String str[] = "He is the one".split(" ");
    String finalStr="";
        for(int i = str.length-1; i>= 0 ;i--){
            finalStr += str[i]+" ";
        }
        System.out.println(finalStr);
    }
}
11 голосов | спросил Sumeet 14 SatEurope/Moscow2013-12-14T21:21:13+04:00Europe/Moscow12bEurope/MoscowSat, 14 Dec 2013 21:21:13 +0400 2013, 21:21:13

7 ответов


8

Наполнение всего вашего кода на main() - плохая практика. Эта функциональность принадлежит своей собственной функции.

При выполнении нескольких конкатенаций строк вы действительно хотите использовать StringBuilder. Если вы этого не сделаете, компилятор сделает все для вас, каждый раз, когда вы объединяете две строки, используя + . Лучше сделать это явным образом и контролировать, сколько из этих временных объектов создано.


Ваш первый подход работает персонажем за раз. Я предлагаю следующий подход «по-разному», который выделяет только один большой временный буфер.

private static void reverse(char[] buf, int start, int end) {
    for (int i = start, j = end - 1; i < j; i++, j--) {
        char swap = buf[i];
        buf[i] = buf[j];
        buf[j] = swap;
    }
}

public static String reverseWords1(String sentence) {
    char[] buf = sentence.toCharArray();

    // Reverse the string, character-wise
    reverse(buf, 0, buf.length);

    // Within each word, reverse the characters again
    int wordEnd = 0;
    for (int wordStart = 0; wordStart < buf.length; wordStart = wordEnd + 1) {
        for (wordEnd = wordStart; wordEnd < buf.length && buf[wordEnd] != ' '; wordEnd++) {}

        // wordStart is at the start of a word.
        // wordEnd is just past the end of the word.
        reverse(buf, wordStart, wordEnd);
    }
    return new String(buf);
}

Я предпочитаю ваш второй подход, который более краткий. Здесь он очищается с помощью StringBuilder.

public static String reverseWords2(String sentence) {
    StringBuilder sb = new StringBuilder(sentence.length() + 1);
    String[] words = sentence.split(" ");
    for (int i = words.length - 1; i >= 0; i--) {
        sb.append(words[i]).append(' ');
    }
    sb.setLength(sb.length() - 1);  // Strip trailing space
    return sb.toString();
}
ответил 200_success 15 SunEurope/Moscow2013-12-15T15:48:00+04:00Europe/Moscow12bEurope/MoscowSun, 15 Dec 2013 15:48:00 +0400 2013, 15:48:00
11

«Свернуть» - это очень плохое слово для использования при попытке рассмотреть качество вашего кода. Это расплывчато, и это может привести к нежелательным результатам, таким как сломанный или непригодный код.

Например, ваша цель - минимизировать количество использованных байтов для хранения исходного кода на жестком диске? Возможно, это было важно, когда бумажная лента была популярным носителем информации, но сегодня это не имеет значения. Это настолько неуместно, что разница между этими двумя файлами меньше, чем размер сектора, поэтому оба фактически занимают одинаковое количество пространства для хранения.

Является ли ваша цель сократить количество циклов процессора? Учитывая, что в наши дни на сотовых телефонах работают процессоры с частотой 100 МГц, вам нужно сделать больше работы, чтобы выяснить, будут ли усилия, которые вы тратите на размышления о проблеме, когда-либо восполнят эффективность ваших пользователей. Если это выполняется один или два раза, эффективность просто не важна. С другой стороны, если это может стать частью сетевого протокола, эффективность чрезвычайно важна. Честно говоря, английское разворот слов кажется слишком специализированным, чтобы соответствовать проверке практичности для эффективности.

В общем, к чему большинство людей должно стремиться в своем коде, это «правильность» и «ясность». Вы хотите знать, что он работает правильно во всех ситуациях. Ответ на это - написать модульные тесты. Для ясности вы хотите, чтобы код был читаемым, понятным и удобным для использования. Убедитесь, что вы выбрали хорошие имена. Модулируйте функции. Например, вы должны рассмотреть возможность извлечения зависимости от System.out.println, поскольку вывод строки не имеет ничего общего с изменением строки.

ответил John Deters 14 SatEurope/Moscow2013-12-14T22:05:14+04:00Europe/Moscow12bEurope/MoscowSat, 14 Dec 2013 22:05:14 +0400 2013, 22:05:14
6

В вашем первом подходе у вас есть правильная идея начать в конце строки и работать назад. У вас есть проблемы:

  • вы должны использовать StringBuilder вместо конкатенации String ....
  • используя строку temp, которую вы добавляете в обратном порядке, а затем снова обращайтесь к результату, это медленный подход. .. но эффективный.
  • вы должны делать это более 1 символа за раз.

В вашем втором подходе мне не нравится:

  • у вас снова есть конкатенация строк use a StringBuilder()
  • вы предполагаете, что все пробелы «равны» ... что касается разметки нескольких пробелов "Hello There" с этим кодом станет "There Hello"

Итак, с небольшой настройкой на ваше регулярное выражение (возможно, "\\b" ...) и преобразование в StringBuilder, я думаю, что вторая вариант хорош.

Первый вариант, если он написан правильно, будет быстрее, чем разделенный (хотя код длиннее) ....

Вот попытка сделать это с помощью первых принципов:

private static String reverse(String string) {
    if (string.isEmpty()) {
        return string;
    }
    int last = string.length();
    StringBuilder sb = new StringBuilder(string.length());
    boolean contextspace = ' ' == string.charAt(string.length() - 1);
    for (int i = string.length() - 1; i >= 0; i--) {
        if (contextspace != (string.charAt(i) == ' ')) {
            sb.append(string.substring(i + 1, last));
            last = i + 1;
            contextspace = !contextspace;
        }
    }
    sb.append(string.substring(0, last));
    return sb.toString();
}
ответил rolfl 14 SatEurope/Moscow2013-12-14T22:32:17+04:00Europe/Moscow12bEurope/MoscowSat, 14 Dec 2013 22:32:17 +0400 2013, 22:32:17
2

Есть много способов сделать это, в зависимости от того, что вы собираетесь делать.

Если вы застряли в Java, тогда, вероятно, посмотрите на общие ресурсы Apache:

StringUtils.reverseDelimited(st, ' ');

Попробуйте использовать Scala, если это возможно, что намного лучше:

st.split(" ").reverse.mkString(" ")
ответил Dino Fancellu 15 SunEurope/Moscow2013-12-15T04:19:42+04:00Europe/Moscow12bEurope/MoscowSun, 15 Dec 2013 04:19:42 +0400 2013, 04:19:42
2

Повторно использовать существующий код.

Библиотеки допускают максимальное повторное использование. Используйте их!

Если вам не нравятся библиотеки, попробуйте повторно использовать столько, сколько предлагает Java. Посмотрите документацию, примеры и т. Д.

  • Разделительные строки: java default split()
  • Реверсирование можно выполнить с помощью превосходного класса Collections
  • В Java8 есть несколько хороших материалов для объединения строк.

Я также пытаюсь сделать код максимально читаемым, имея короткие инструкции и избегая циклов (для, while и т. д.), когда они вам не нужны.

Мой подход:

public static String reverseWords (String s) 
{
    String delimiter = " ";
    List<String> words = Arrays.asList(s.split(delimiter));
    Collections.reverse(words);
    return String.join(delimiter, words);
}

public static void main(String[] args) 
{
    System.out.println(reverseWords("He is the one"));
} 
ответил RobAu 14 Jpm1000000pmThu, 14 Jan 2016 12:36:37 +030016 2016, 12:36:37
1

Вот чистый подход к изменению строки по частям:

public class Main {

    // ReverseParts: reverses a string by words as opposed to characters.
    public static String ReverseParts(String input, String splitBy, String joinBy) {
        StringBuilder built = new StringBuilder();

        // Note: String.split uses regex. See its definition
        String[] list = input.split(splitBy);

        // Rejoin all the characters into a StringBuilder.
        for ( String part: list ) {
            built.insert(0, part);
            built.insert(0, joinBy);
        }

        // Remove the unnecessary 'joinBy bit'.
        built.delete(0, 1);

        // Get back the final string.
        return built.toString();
    }
    public static void main(String[] args) {
        final String input = "Hello  Johnny's World!";

        System.out.println("Result: '" + ReverseParts(input, " +", " ")+"'");
        // Output:
        // Result: 'World! Johnny's Hello'
    }
}
ответил Scala William 14 SatEurope/Moscow2013-12-14T22:00:49+04:00Europe/Moscow12bEurope/MoscowSat, 14 Dec 2013 22:00:49 +0400 2013, 22:00:49
-3

Подход 1:

JDK предоставляет java.util.StringTokenizer, чтобы выполнить разделение или токенизацию заданного текста. Этот API помогает избежать появления персонажа по характеру. Никаких внешних банок /библиотек не требуется. Tokenizing дает вам каждое разделенное слово как элемент массива, который вы можете распечатать в обратном порядке.

import java.util.ArrayList;
import java.util.StringTokenizer;


public class reverseString {
    public static void main(String args[])
    {
            StringTokenizer st = new StringTokenizer("this is a string");
            ArrayList<String> arrLstStrings = new ArrayList<>();
            while (st.hasMoreTokens()) {
                arrLstStrings.add(st.nextToken());
            }

            for(int loop=arrLstStrings.size()-1;loop>=0;loop--)
                System.out.println(arrLstStrings.get(loop));
    }
}

Подход 2:

import java.util.regex.*;

public class reverseString {
    public static void main(String args[])
{
        String strSource = "This is a string";
        // give a max int as limit in next stmt.
        String[] tokens = Pattern.compile(" ").split(strSource,15) ;
        for (int loop=tokens.length-1;loop>=0;loop--)
            System.out.println(tokens[loop]);
    }
}
ответил jaadhimalli 15 SunEurope/Moscow2013-12-15T13:41:17+04:00Europe/Moscow12bEurope/MoscowSun, 15 Dec 2013 13:41:17 +0400 2013, 13:41:17

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132