Дана последовательность слов; между соседними словами запятая, за последним
словом - точка. Напечатать все слова, встречающиеся в последовательности
по одному разу.
Работа с рядками
Модератор: Модераторы
- debi12345
- долгожитель
- Сообщения: 5761
- Зарегистрирован: 10.05.2006 23:41:15
- Откуда: Ташкент (Узбекистан)
Re: Работа с рядками
Построить из этих слов хэш-таблицу с индексами, равными sha256 от каждого слова. Тогда в этой таблице автоматом останется по одному экземпляру каждого слова.Дана последовательность слов; между соседними словами запятая, за последним
словом - точка. Напечатать все слова, встречающиеся в последовательности
по одному разу.
Добавлено спустя 1 минуту 21 секунду:
Или загрузить эти слова в БД (SQLITE3 и т.п.) и сделать DISTINCT SQL-запрос
- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
Re: Работа с рядками
debi12345 писал(а):Построить из этих слов хэш-таблицу
издеваетесь?
- debi12345
- долгожитель
- Сообщения: 5761
- Зарегистрирован: 10.05.2006 23:41:15
- Откуда: Ташкент (Узбекистан)
Re: Работа с рядками
издеваетесь?
Ну "красно-черное дерево" как альтернативу, но под него придется писать функцию-компаратор - что сложнее.
Сейчас вручную тасовать список - все равно что считать числа в уме, имея под рукой калькулятор
Re: Работа с рядками
Умилился родному украинизму в заголовке (не «строки», а «рядки») и решил сделать за кого-то ДЗ.
Не использовал стандартную библиотеку (типа TStringList), современный режим {$mode ObjFPC}, свои типы, классы и записи, т.к. не знаю, проходили ли вы их. Не пытался делать эффективно или универсально (на большом количестве строк программа быстро станет тормозить).
P.S. Решения, которые написал debi12345, абсолютно правильные. Во многих реальных программах нужны именно они. Но при этом ваш_а преподаватель_ница вряд ли ожидает таких решений.
P.P.S. Не заметил, что тема в разделе «Помощь за вознаграждение», сделал бесплатно :D
P.P.P.S. Кстати, мы с debi12345 по-разному поняли задание:
«Напечатать все слова, встречающиеся в последовательности по одному разу.»
Я понял «напечатать [все слова, встречающиеся в последовательности по одному разу]». Т.е. если слово встречается один раз — печатаем, если больше — не печатаем.
debi12345 понял «напечатать [все слова, встречающиеся в последовательности] [по одному разу]», т.е. в его решениях слова, встречающиеся несколько раз, всё равно будут напечатаны (но только один раз).
Мой код делает именно первое — печатает только те, которые встречаются один раз. По-моему это правильная трактовка (с учётом того, как расставлены запятые в задании).
Но если вдруг нужно печатать все по одному разу, то код надо поменять.
Не использовал стандартную библиотеку (типа TStringList), современный режим {$mode ObjFPC}, свои типы, классы и записи, т.к. не знаю, проходили ли вы их. Не пытался делать эффективно или универсально (на большом количестве строк программа быстро станет тормозить).
Код: Выделить всё
{ Дана послідовність слів; поміж сусідніми словами кома, за останнім словом -
крапка. Надрукувати всі слова, які зустрічаються в послідовності по одному
разі. }
program StringHandling;
var
CurrentPart: String;
FinishedReading: Boolean = False;
Words: array [1..100] of String;
WordCounts: array [1..100] of Integer;
WordsLength: Integer = 0;
{ Якщо слово вже було додано в масив слів, повертає його номер індекс.
Якщо слова в послідовності немає, повертає 0. }
function GetWordIndex(S: String): Integer;
var
I: Integer;
begin
GetWordIndex := 0;
for I := 1 to WordsLength do
if Words[I] = S then begin
GetWordIndex := I;
Exit
end
end;
{ Забирає пробіли з початку або кінця рядка }
function Trim(S: String): String;
var
StartIndex: Integer = 1;
Count: Integer;
begin
while (StartIndex <= Length(S)) and (S[StartIndex] = ' ') do
Inc(StartIndex);
Count := Length(S) - StartIndex;
while (Count > 0) and (S[StartIndex + Count] = ' ') do
Dec(Count);
Trim := Copy(S, StartIndex, Count + 1)
end;
{ Додає слово в масив слів або збільшує його кількість. Якщо місця в
списку немає, закінчує процес читання та додавання, виводячи помилку
та встановлюючи FinishedReading := True }
procedure AddWord(Word: String);
var
TrimmedWord: String;
Index: Integer;
begin
TrimmedWord := Trim(Word);
Index := GetWordIndex(TrimmedWord);
if Index = 0 then begin
if WordsLength >= 100 then begin
WriteLn(StdErr, 'Ліміт слів перевищено.');
FinishedReading := True;
Exit
end;
Inc(WordsLength);
Words[WordsLength] := TrimmedWord;
WordCounts[WordsLength] := 1
end else
Inc(WordCounts[Index])
end;
{ Читає частину слів. Частина має закінчуватися на кому або крапку, інакше
останнє слово буде викнуте. }
procedure ProcessPart(Part: String);
var
CurrentWord: String = '';
I: Integer;
begin
for I := 1 to Length(Part) do begin
if Part[I] = '.' then begin
AddWord(CurrentWord);
FinishedReading := True;
Break
end else if Part[I] = ',' then begin
AddWord(CurrentWord);
CurrentWord := ''
end else
CurrentWord := CurrentWord + Part[I];
{ AddWord може закінчити читання, якщо місця в масиві слів
не залишилося, отож перевіримо цей випадок }
if FinishedReading then
Break;
end;
end;
{ Друкує список слів, які зустрілися один раз }
procedure WriteUniqueWords();
var
I: Integer;
begin
for I := 1 to WordsLength do
if WordCounts[I] = 1 then
WriteLn(Words[I])
end;
begin
while not FinishedReading do begin
ReadLn(CurrentPart);
ProcessPart(CurrentPart);
end;
WriteUniqueWords
end.P.S. Решения, которые написал debi12345, абсолютно правильные. Во многих реальных программах нужны именно они. Но при этом ваш_а преподаватель_ница вряд ли ожидает таких решений.
P.P.S. Не заметил, что тема в разделе «Помощь за вознаграждение», сделал бесплатно :D
P.P.P.S. Кстати, мы с debi12345 по-разному поняли задание:
«Напечатать все слова, встречающиеся в последовательности по одному разу.»
Я понял «напечатать [все слова, встречающиеся в последовательности по одному разу]». Т.е. если слово встречается один раз — печатаем, если больше — не печатаем.
debi12345 понял «напечатать [все слова, встречающиеся в последовательности] [по одному разу]», т.е. в его решениях слова, встречающиеся несколько раз, всё равно будут напечатаны (но только один раз).
Мой код делает именно первое — печатает только те, которые встречаются один раз. По-моему это правильная трактовка (с учётом того, как расставлены запятые в задании).
Но если вдруг нужно печатать все по одному разу, то код надо поменять.
- debi12345
- долгожитель
- Сообщения: 5761
- Зарегистрирован: 10.05.2006 23:41:15
- Откуда: Ташкент (Узбекистан)
Re: Работа с рядками
По-любому правильное (масштабируемое на большой набор данных) решение - "красно-черное дерево" (далее см. число элементов в каждом "узле", чтобы отсечь по числу повторов). В хэш-таблицах (и SQL-е) тоже оно ("дерево") используется - как внутренняя реализация хэш-индексов. Возможно если топик-стартер шиканет таким (промышленным, из реального мира) решением, то препод(ша) врядли за это жестко покарает 
