Переставьте слова в строке в алфавитном порядке

#java #arrays #string

Вопрос:

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

 public class ListString {
    String[] list = new String[20];
    int n = 0;

    public void read() {
        Scanner in = new Scanner(System.in);
        System.out.println("Please enter the sentence");
        String s = in.nextLine();
        String temp = "";
        for (int i = 0; i < s.length(); i  )
        {
            char ch = s.charAt(i);
            if ((ch >= 'a' amp;amp; ch <= 'z') || (ch >= 'A' amp;amp; ch <= 'Z'))  // range from a to z
                temp = temp   ch;
            else 
            {
                if (temp.length() > 0)
                {
                    list[n] = temp;
                    n  ;
                    temp = "";
                }
            }
        }
    }

    public void print() {
        System.out.print(list[0]);          
        for (int i = 0; i < n; i  )
            System.out.print(" "   list[i]);          
        System.out.println(" ");
    }

    public void sort() {
        for (int i = 0; i < n; i  ) { 
            String key = list[i]; 
            int j = i - 1; 
            while (j >= 0 amp;amp; (list[j].compareToIgnoreCase(key) > 0)) 
            { 
                list[j   1] = list[j]; 
                j = j - 1; 
            } 
            list[j   1] = key; 
        } 
    }  
}
 

Ответ №1:

Это происходит, когда вы нажимаете конец строки, а temp не пуст. Чтобы исправить это, вы можете добавить тот же оператор if после цикла:

 for(int i = 0; i < s.length(); i  ) {
    char ch = s.charAt(i);
    if((ch >= 'a' amp;amp; ch <= 'z') || (ch >= 'A' amp;amp; ch <= 'Z')) {
        temp = temp   ch;
    } else {
        if(temp.length() > 0) {
            list[n] = temp;
            n  ;
            temp = "";
        }
    }
}

if(temp.length() > 0) {
    list[n] = temp;
    n  ;
    temp = "";
}
 

Кроме того, вам нужно будет исправить вывод, чтобы не печатать первое слово дважды:

 public void print() {
    for(int i = 0; i < n; i  ) {
        System.out.print(list[i]   " ");
    }
    System.out.println();
}
 

Вывод перед исправлением:

 a b c d e f g h i j k l m n o p q r s t
a a b c d e f g h i j k l m n o p q r s 
 

Вывод после исправления:

 a b c d e f g h i j k l m n o p q r s t
a b c d e f g h i j k l m n o p q r s t 
 

Обновить:

Также вы можете решить свою проблему в одну строку, используя потоки

 public void read() {
    Scanner in = new Scanner(System.in);
    System.out.println("Please enter the sentence");
    String s = in.nextLine();

    String[] list = Arrays.stream(s.split(" ")).limit(20).sorted().toArray(String[]::new);
}
 

Он разбивает входную строку на символы пробела, берет первые 20 слов, сортирует их и создает массив из них.

Выход:

 t s r q p o n m l k j i h g f e d c b a z z z z z
a b c d e f g h i j k l m n o p q r s t 
 

Комментарии:

1. В потоковой версии read переменной метода list отсутствует тип в ее объявлении.

Ответ №2:

Вам не нужно явно обрабатывать конец строки: используя целочисленные указатели на начало и конец слов, вы можете сделать это следующим образом:

 int start = 0;
while (start < s.length()) {
  // Increment a start pointer until it points to the end of the string or the start of a word.
  while (start < s.length() amp;amp; !isLetter(s.charAt(start))) {
    start  ;
  }

  // Increment an end pointer until it points to the end of the string or a non-word character.
  int end = start;
  while (end < s.length() amp;amp; isLetter(s.charAt(end))) {
    end  ;
  }

  if (start == end) {
    // You reached the end of the string.
    break;
  }

  // Grab the portion of the string between start and end, this is a word.
  list[n  ] = s.substring(start, end);

  // Set up the start pointer to point to the end of this word, for the next iteration.
  start = end;
}
 

где isLetter(char) находится метод, который проверяет, находится ли аргумент между A и Z (в любом случае).

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

 for (int start = 0, end = 0; start < s.length();) {
  if (!isLetter(s.charAt(start))) {
    start  ;
    end = start;
  } else if (isLetter(s.charAt(end))) {
    end  ;

    if (end >= s.length() || !isLetter(s.charAt(end))) {
      list[n  ] = s.substring(start, end);
      start = end;
    }
  }
}