Разбор примеров из книги
Модераторы: Oleg_D, Модераторы
Извиняюсь, я туда еще не дошел был...
Например, так:или даже так:
Код: Выделить всё
var
s: string;
i: integer;
p: boolean;
begin
write('Введите слово: '); readln(s);
p := true;
for i := length(s) div 2 downto 1 do
if s[i] <> s[length(s) - i + 1] then begin
p := false; break;
end;
if p then writeln('Слово - палиндром')
else writeln('Слово - НЕ палиндром');
end.
Код: Выделить всё
function IsPalindrom(s: string): boolean;
var
i: integer;
begin
IsPalindrom := true;
for i := length(s) div 2 downto 1 do
if s[i] <> s[length(s) - i + 1] then begin
IsPalindrom := false; break;
end;
end;
begin
write('Введите слово: '); readln(s);
if IsPalindrom(s) then writeln('Слово - палиндром')
else writeln('Слово - НЕ палиндром');
end.
Последний раз редактировалось bormant 25.11.2012 11:26:22, всего редактировалось 1 раз.
Код: Выделить всё
if s[i] <> s[length(s) - i - 1] then beginВы, наверное, имели ввиду
Код: Выделить всё
if s[i] <> s[length(s) - i + 1] then beginА теперь вопрос, зачем мы делим строку на 2, мы обрезаем конец строки и средний символ?
Т.е. с слова "потоп" остается "по"? Но я не пойму логики, если так, то, к примеру слово "порок", тоже остается лишь "по", то почему он не выдает как палиндром? Это вопрос к Олегу, к решению задачи, которое предложено в книге.
Последний раз редактировалось deka47 25.11.2012 00:59:28, всего редактировалось 1 раз.
Если количество букв в слове НЕЧЁТНОЕ, то среднюю букву сравнивать саму с собой нет смысла.
Oleg_D писал(а):Если количество букв в слове НЕЧЁТНОЕ, то среднюю букву сравнивать саму с собой нет смысла.
Но я не пойму логики, если так, то, к примеру слово "порок", тоже остается лишь "по", то почему он не выдает как палиндром?
Потому, что в выражении:
сравниваются первая и последняя буква, вторая и предпоследняя и т.д. в цикле вплоть до средней буквы (но исключая её), если длина нечётная.
Завтра утром вам это станет ясно, как белый день.
Код: Выделить всё
if arg[i] <> arg[Length(arg)-i+1]
Завтра утром вам это станет ясно, как белый день.
Oleg_D писал(а):Потому, что в выражении:сравниваются первая и последняя буква, вторая и предпоследняя и т.д. в цикле вплоть до средней буквы (но исключая её), если длина нечётная.Код: Выделить всё
if arg[i] <> arg[Length(arg)-i+1]
Завтра утром вам это станет ясно, как белый день.
Минутку, а разве команда:
Код: Выделить всё
for i:=1 to Length(arg) div 2Не делит, к примеру, слово с 13 символом на 2 и оставляет только первых 6 символов?
Ну 13 div 2 = 6, 15 div 2 = 7. Остаются же лишь 6/7 первых символов? Также слово "потоп", разделить его на 2, то останется первых два символа "по", и после этой команды
Код: Выделить всё
if arg[i] <> arg[Length(arg)-i+1]Здесь уже будет браться не полная длина строки (5 символов), а уже урезанная в 2 символа (после div).
У меня к вам еще один личный вопрос, вот я застреваю на таких задачках, с меня что-то будет? Потому-что я решил поступить на программирование, но не знаю получится ли что-то. Кажется что я туплю в каждой задаче и достаю вас здесь... Подскажите мне, вот сколько вы учились, чтобы понимать паскаль, как вы понимаете сейчас?
Подскажите мне, вот сколько вы учились, чтобы понимать паскаль, как вы понимаете сейчас?
Он учился всю жизнь и до сих пор учится.
У каждого время и способ учёбы свои. Равняться тут на кого-либо не стоит.
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
deka47 всё просто.
Вот мой вариант:
Вот мой вариант:
Код: Выделить всё
function checkword(var arg:string):boolean;
var i,j:integer;
begin
checkword:=true;
j:=0;
for i:=length(arg) downto 1 do begin
while j<length(arg) do begin
inc(j);
break;
end;
if arg[i]<>arg[j] then begin
checkword:=false;
break;
end;
end;
end;
var s:string;
begin
writeln('введите слово');
readln(s);
if checkword(s) then
writeln('это слово палиндром')
else
writeln('слово не является палиндромом');
readln;
end.deka47 писал(а):Минутку, а разве команда: for i:=1 to Length(arg) div 2 не делит, к примеру, слово с 13 символом на 2 и оставляет только первых 6 символов?
Нет, не делит. Здесь строка никак не затрагивается. Делится одно число -- длина строки -- на другое число, и получается предел для цикла.
deka47 писал(а):У меня к вам еще один личный вопрос, вот я застреваю на таких задачках, с меня что-то будет? Потому-что я решил поступить на программирование, но не знаю получится ли что-то. Кажется что я туплю в каждой задаче и достаю вас здесь... Подскажите мне, вот сколько вы учились, чтобы понимать паскаль, как вы понимаете сейчас?
Vadim писал(а):Он учился всю жизнь и до сих пор учится.
Это точно.
Paster Fob писал(а):Код: Выделить всё
while j<length(arg) do begin
inc(j);
break;
end;
Мудро накручено, не сразу понял.
Проще так:
Код: Выделить всё
if j<length(arg) then Inc(j);
Код: Выделить всё
Inc(j);
абсолютно верно.deka47 писал(а):Код: Выделить всё
if s[i] <> s[length(s) - i - 1] then begin
Вы, наверное, имели ввидуКод: Выделить всё
if s[i] <> s[length(s) - i + 1] then begin
Мы с самой строкой ничего не делаем. length(s) возвратит нам число -- длину строки, пусть n. Затем, мы будем проверять условие палиндромности исходя из его определения, сравнивая 1-ю букву с n-ной, 2-ю с (n-1) и т. д. То есть, сравниваем [i]-ю с [n-i+1]-ой. Как только найдем неравенство, условие палиндромности нарушено и можно завершать проверку. Перебрав индексы от 1 до (n div 2) заметим, что дальше продолжать нет смысла: при четном количестве одна половина уже полностью была сравнена с другой, а при нечетном -- остался один один символ, который сравнивать с самим собой смысла не имеет. Но если продолжить до конца -- на результат это не повлияет, просто работа будет проделана дважды: [1] с [n] и [n] с [1] и т.д.deka47 писал(а):А теперь вопрос, зачем мы делим строку на 2, мы обрезаем конец строки и средний символ?
Т.е. с слова "потоп" остается "по"? Но я не пойму логики, если так, то, к примеру слово "порок", тоже остается лишь "по", то почему он не выдает как палиндром? Это вопрос к Олегу, к решению задачи, которое предложено в книге.
Еще один мрмент: если прямой цикл без дублирования: от 1 до n div 2 (или наоборот), то обратный будет от n до (n+1) div 2 (или наоборот), например:
для 6: 1-3, 6-3
для 7: 1-3, 7-4
...
Последний раз редактировалось bormant 25.11.2012 13:00:11, всего редактировалось 1 раз.
- Paster Fob
- постоялец
- Сообщения: 188
- Зарегистрирован: 22.02.2011 20:53:36
- Откуда: Новосибирск.
Oleg_D писал(а):Paster Fob писал(а):Код: Выделить всё
while j<length(arg) do begin
inc(j);
break;
end;
Мудро накручено, не сразу понял.![]()
Проще так:А ещё проще:Код: Выделить всё
if j<length(arg) then Inc(j);поскольку IF тоже лишний. К тому же в вашем решении цикл вдвое длиннее. Ну, опыт -- дело наживное.Код: Выделить всё
Inc(j);
М-да,поторопился.Вот исправленный вариант.
Код: Выделить всё
function checkword(var arg:string):boolean;
var i,j:integer;
begin
checkword:=true;
j:=0;
for i:=length(arg) downto length(arg) div 2 do begin
inc(j);
if arg[i]<>arg[j] then begin
checkword:=false;
break;
end;
end;
end;
var s:string;
begin
writeln('введите слово');
readln(s);
if checkword(s) then
writeln('это слово палиндром')
else
writeln('слово не является палиндромом');
readln;
end.Paster Fob,
я переписал бы так:3 отличия:
1) список параметров: переменная arg внутри функции не меняется, поэтому, если компилятор поддерживает const в списке параметров, то нет повода использовать var;
2) в цикле "for i := выражение1 to/downto выражение2 do" выражение1 вычисляется единожды, а выражение2 -- на каждой итерации цикла (если только оптимизатор не умеет выводить его независимость от тела цикла). В данном примере это несущественно, для коротких строк length(s) -- это всего лишь byte(s[0]), но вот операция деления, пусть и целочисленного, намного более ресурсоёмка.
3) в предварительном выполнении inc(j) мало смысла, начальному значению j вне цикла приходится давать значение заведо уменьшенное на 1, а это не способствует лёгкости понимания кода.
Первые 2 замечания -- они скорее из области оптимизации, поэтому сразу оговорьсь, что преждевременная оптимизация зло, если она затрудняет понимание кода. Но это не наш случай.
Добавлено спустя 15 минут 36 секунд:
Но мне более нравится другой вариант, вообще без делений и каких бы то ни было расчётов, просто идём навстречу с разных концов слова, сравнивая символы. Если встретились, то палиндром:
Добавлено спустя 28 минут 33 секунды:
И прогоны:
я переписал бы так:
Код: Выделить всё
function checkword(const arg: string): boolean;
var i, j: integer;
begin
checkword:=true;
j := (length(arg) + 1) div 2 + 1;
for i := length(arg) div 2 downto 1 do begin
if arg[i]<>arg[j] then begin
checkword:=false; break;
end;
inc(j);
end;
end;
1) список параметров: переменная arg внутри функции не меняется, поэтому, если компилятор поддерживает const в списке параметров, то нет повода использовать var;
2) в цикле "for i := выражение1 to/downto выражение2 do" выражение1 вычисляется единожды, а выражение2 -- на каждой итерации цикла (если только оптимизатор не умеет выводить его независимость от тела цикла). В данном примере это несущественно, для коротких строк length(s) -- это всего лишь byte(s[0]), но вот операция деления, пусть и целочисленного, намного более ресурсоёмка.
3) в предварительном выполнении inc(j) мало смысла, начальному значению j вне цикла приходится давать значение заведо уменьшенное на 1, а это не способствует лёгкости понимания кода.
Первые 2 замечания -- они скорее из области оптимизации, поэтому сразу оговорьсь, что преждевременная оптимизация зло, если она затрудняет понимание кода. Но это не наш случай.
Добавлено спустя 15 минут 36 секунд:
Но мне более нравится другой вариант, вообще без делений и каких бы то ни было расчётов, просто идём навстречу с разных концов слова, сравнивая символы. Если встретились, то палиндром:
Код: Выделить всё
function IsPalindrom(s: string): boolean;
var
i, j: integer;
begin
i := 1; j := length(s);
while (i < j) and (s[i] = s[j]) do begin
inc(i); dec(j);
end;
IsPalindrom := i >= j;
end;
Добавлено спустя 28 минут 33 секунды:
Например, если речь идёт о показе отличающихся символов:deka47 писал(а):как бы сделать так, чтобы "запоминались" все местоположения?
Код: Выделить всё
procedure ShowPalDiff(const s: string; MarkSame, MarkDiff: char);
var
i, j: integer;
p: boolean;
begin
writeln(s);
j := length(s); p := true;
for i := 1 to length(s) do begin
if s[i] = s[j] then write(MarkSame)
else begin
write(MarkDiff); p := false;
end;
dec(j);
end;
if p then writeln(^M'Это палиндром.', '':length(s)-14)
else begin
writeln; writeln('Это НЕ палиндром.');
end;
end;
var
s: string;
begin
write('Введите слово: '); readln(s);
ShowPalDiff(s, '_', '^');
end.
Код: Выделить всё
Введите слово: pascal
pascal
^_^^_^
Это НЕ палиндром.
Введите слово: potop
potop
Это палиндром.
Разобрался со всеми вариантами задачи, с inc вообще гениально, как по мне! Спасибо за помощь.
Т.е. мы отсекаем первую часть "строки". Мы сравнивамем 1 с последним, 2 с последним минус 1, 3 с последним минус 2. А потом уже нету смысла сравнивать последний минус 1 с вторым? Выходит слово "потоп", мы оставляем "оп" и сравниваем: "п"="п", "о"="о", верно? Буква "т" уже не затрагивается, потому что нету разницы какая она. Я верно понял?
bormant писал(а):Перебрав индексы от 1 до (n div 2) заметим, что дальше продолжать нет смысла: при четном количестве одна половина уже полностью была сравнена с другой, а при нечетном -- остался один один символ, который сравнивать с самим собой смысла не имеет.
Т.е. мы отсекаем первую часть "строки". Мы сравнивамем 1 с последним, 2 с последним минус 1, 3 с последним минус 2. А потом уже нету смысла сравнивать последний минус 1 с вторым? Выходит слово "потоп", мы оставляем "оп" и сравниваем: "п"="п", "о"="о", верно? Буква "т" уже не затрагивается, потому что нету разницы какая она. Я верно понял?
Да. Только "отсекаем" -- это в переносном смысле, строку мы никак не модифицируем, только берём из неё символы по индексу. Дело в чём, если мы в качестве инструмента выбрали по каким-то причинам цикл for, мы должны указать начальное и конечное значения счётчика цикла. Счётчиком нам достаточно пробежать только половину, посколько вторую половину мы будем получать "зеркально" от противоположного конца строки.deka47 писал(а):Т.е. мы отсекаем первую часть "строки". Мы сравнивамем 1 с последним, 2 с последним минус 1, 3 с последним минус 2. А потом уже нету смысла сравнивать последний минус 1 с вторым? Выходит слово "потоп", мы оставляем "оп" и сравниваем: "п"="п", "о"="о", верно? Буква "т" уже не затрагивается, потому что нету разницы какая она. Я верно понял?
В варианте с циклом while и парой индексов ничего предварительно рассчитывать не приходится, достаточно тривиального контроля "встречи" индексов на каждой итерации. Кроме того его возможно легко модифицировать под расширенные условия, например, на проверку "палиндромности" без учёта пробелов и знаков препинания, как в фразе "а роза упала на лапу азора".
