[C#] Домашно Strings and Text Processing - 20 задача


8

Условие: Write a program that extracts from a given text all palindromes, e.g. "ABBA", "lamal", "exe".

Решениеsource.

Обяснение: Разделяме стринга на отделни думи. За всяка от тях проверяваме дали е палиндром, като сравняваме първата буква с последната, втората с предпоследната и т.н. докато стигнем средата на думата.




Отговори



5

Тази задача ми напомня много задачата за симетричните масиви, алгоритъмът е същият.

Първо разделям текста на отделните думи в него с масив от символи -разделители (интервал, точка, запетая, нов ред). После обикалям всяка дума, и всеки символ в думата и сравнявам дали са еднакви първата с последната, втора с предпоследната, точно като при симетричните масиви. Ако една от двойките символи не е еднаква, значи думата не е палиндром и излизам с break от цикъла.

Ако булевата ми променлива isPalindrome е true, и думата е по-голяма от един символ (т.е. е поне два), отпечатвам палиндрома на конзолата.

http://pastebin.com/VKdLh0Vv




0
Аууу, красота само че някой трябва да се сети моето стана лудница. Ама пък си ме кефи, а и се ползват точно нещата от стринговете. Докато решавах някви масиви случайно цъкнах тая задача и много ми се дорешава, защото веднага ми щракна в главата как да я реша :) Решение: http://pastebin.com/Vdesmv2z

от Assi.NET (3050 точки)

0
И аз я реших подобно , ама кой да се сети че можем да разделим думата по такъв лесен начин. Аз вземам думата правя я в Char[] след това Array.Reverse и обратно в string. Ето и моето решение: http://pastebin.com/129bRY4u

от hudsonvsm (25 точки)


0

 

малко инфо какво е полиндром и примерен код - http://www.rbukvar.eu/%D0%BF%D0%B0%D0%BB%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC.html

ето и моето решение - http://pastebin.com/u5ufnfhh

с две думи - резбивам стринга на думи, пускам един цикъл през резултата от думите - докато е на якоя дума ползвам вложен цикъл за да обиколя по буквите на думата.

Като проверката е буква по буква първата с последната и т.н. Проверката върви паралелно като ако стигна до разлика от 1 (между текущия индекса на буквата) и (дължината на думата минус индекса) - значи има попадение - печатаме

 

EDIT

Малко допълнение към задачата ""алена фанела", "аз обичам мач и боза"" реално тези словосъчетания също са полиндроми което добавя още едно ниво на трудност към задачата - аз все още не съм се справил с него ако някой има идея може да я сподели. По услови не става ясно дали се търсят само думи или и фрази. Аз съм решил че са само думи ;)

Може би ако се направи да не сплитва а да долепя всички думи една до друга и след това да ги обхожда буква по буква и т.н. може и да проработи

 

 


от ge_or_gi (110 точки)


2

Пускам нещо интересно, като решение стига да има търпение да го разгледа човек:

Интересни неща:

  • Метода който ми генерира всички пунктуационни знаци според VS
  • Решението на задачата е повече с стрингове каквато е и идеята

Решение:

http://pastebin.com/Vdesmv2z

Обяснение:

1. Правя си метод който ми генерира всички пунктуационни знаци VS. Като използвам метода char.IsPunctuation( ), което връща True / False според това дали даден char е пунктуационен знак или не.

2. Пускам for цикъл от 0 до 128 , с цел да хвана цялата ASCII таблица. След което проверявам за всеки номер от таблица дали е пункт. знак и ако Да го набутвам в лист на име allPunctiation

if (char.IsPunctuation((char)i))

3. Отивам вече в същинската част. Сплитвам по листа със знаците /allPunctiation/. След което пускам for цикъл до strArr.Length. Тъй като в strArr имам вече всички думи, започвам да проверявам всяка една, дали като я разделя на 2 и дясната част я reverse-na ще получа 2-е еднакви думи.

!!! В сорса съм добавил малко коментари, за това в тази точка не съм толкова изчерпателен.

4. Ако има съвпадение на лявата и дясната част на думата то тогава добавям самата дума в списък от думи палиндроми.

EDIT: По препоръка на jasssonpet, за оптимизация на кода, по добра четимост и без повторение.

 

Асси


от Assi.NET (3050 точки)


0
Тези последните два блока може да ги обединиш, като имаш предвид целочисленото деление и че средната буква не се повтаря. Примерно махаш if-а и слагаш: //Get lengths int halfLength = wordLength / 2; int righSideStartIndex = wordLength - halfLength; //Get Left and Right Side of word string leftSide = strArr[i].Substring(0, halfLength); string rightSide = strArr[i].Substring(righSideStartIndex, halfLength);

от jasssonpet (6814 точки)

0
Много си прав, още докато го пишех точно там нещо не ми хареса. И го гледах и се чудих кво да го правя, накрая нищо не измислих Мерси за Препоръката ей сега го оправям:)

от Assi.NET (3050 точки)



2

Задачата има и по-хитро и ефективно решение. Вместо да се проверяват за полондроми всички думи в текста, може да се извлекът само тези които имат еднаква първа и последна буква( плюс еднобуквените думи) и да се проверят само те. Това би ускорило алгоритъма в пъти. Ето и решение:

source code


от ivanbuhov (417 точки)


2

Ето и моя вариант, както и готини палиндроми, на които попаднах:

"Ядох и ходя."

"Самара кара мас."

"За авер рева аз."

"Насила закараха свинете ни в Сахара! - каза Лисан"

"Ядох не сарми, а бозава зоб. А и мръсен ходя.

"Мида, свещ и хероин! Щом с апатия и веща тактика ни черпи мечтан шум, а катетърът е така мушнат, че ми пречи на китката, ще вия и тапа с мощни орехи ще всадим."

"На морава режат сиртаки, Марек. А на керамика, триста жерава. Роман!"


от Ognyan.Petkov (1044 точки)


2

С .Split извеждам всички думи, като сплитвам по интервал и всички препитателни знаци. Завъртам цикъл по елементите на масива и по думите, като за всяка дума прверявам първия и последния символ дали са енакви и продължавам с проверките и за останалите символи, ако всички проверки върнат true то думата е Палиндром и я разпечатвам, ако някоя проверка не е изпълнена break-вам вътрешния цикъл и преминавам към следващата дума.
Решението ми е http://pastebin.com/UiJHA0AF


от AsenVal (3487 точки)


0
Аз май го направих по хамалския начин. Сплит по спейс и знаци, обръщам всяка дума и сравнявам с оригинала.
Ако съвпадат и имат повече от една буква, печатам.
Така хващам и ако полиндромът започва с главна буква.
http://pastebin.com/aXVsZA8n

от arabella (2576 точки)


0
Намерих регулярен израз, който мачва палиндроми: @"\b(?

от FerdiNebi (20 точки)


1

\b(?<N>.)+.?(?<-N>\k<N>)+(?(N)(?!))\b

не работи съвсем коректно. В следния стринг

@"____ ''''' a.a";

разпознава 3 палиндроми, а не би трябвало да отчете нито една. Ако след като сте прочели разясненията на Leviathan все още не ви е ясно, кодът прави следното:

\b[...]\b взима обособени части, т.е. не точно думи, а поредица от символи. В случая обаче не са коректни разрешените символи.

(?<N>.)+

Това е група с име "N", в която имаме произволен символ (без нов ред) един или повече пъти. Тук идва първият проблем, защото всъщност искаме думи, а не "всякакви символи". Тук може да се промени на 

(?<N>(група от символи, срещащи се в дума)+

Не задавам нещо конкретно, защото например 

(?<N>\w)+

ще включи и '_', който не трябва да е валиден символ. Тук трябва да се поиграе, за да се уточни какво е дума ("C#" или "C++" думи ли са?).

.?

Това въобще не го разбирам. Трябва да означава какъвто и да е символ нула или повече пъти.  Това означава какъвто и да е символ нула или един път. Заради него "bb?bb" и подобни излизат като палиндроми, доста голям пропуск. Трябва да се промени отново на "буква", за да обхване палиндромите с нечетен брой символи, както FerdiNebi правилно споменава.

(?<-N>\k<N>)+

Това е същината на израза, т.е. тук се проверява еднаквост. Влиза в сила по средата на поредицата, т.е. когато намери елемент, равен на последния. От тук до края се "попват" всички еднакви елементи (от "N") и накрая се прави проверка

(?(N)(?!))

която се превежда "Има ли елементи в групата "N"?". Ако има, то нямаме съвпадение (не е палиндром), ако няма, то значи имаме симетрия (съвпадение, палиндром).

Edit: Подобрен regex

\b(?<N>[A-Z])+[A-Z]?(?<-N>\k<N>)+(?(N)(?!))\b

Работи с RegexOptions.IgnoreCase.


от Anubis_Black (1521 точки)


0
Да, прав си, че регулярният израз не уточнява палиндромите да са само от букви (в смисъла на букви от азбуката), но това лесно може да се оправи:
\b(?

от FerdiNebi (20 точки)

0
В последствие и аз достигнах до подобно заключение, почти същото като твоето. Вместо [a-zA-Z] ползвам [A-Z] и RegexOptions.IgnoreCase, което е абсолютно еквивалентно.
А всъщност .? в случая означава какъвто и да е символ нула или един път, аз съм го разбрал погрешно (като повече от веднъж). Ще си едитна поста с подобрен regex.

от Anubis_Black (1521 точки)


1

Това е моето решение на задачата –> http://pastebin.com/LqVcG4NQ 
Направил съм програмата да отделя както единични думи палиндроми, така и палиндроми съставени от повече думи. Самата програма протича по следния начин:
1. Разделяме текстът на отделни думи
2. След което в един списък добавяме всяко словосъчетание в текста, заедно с единичните думи
3. Обхождаме списъка със словосъчетанията и отделните думи и в отделна функация проверяваме дали елементът от списъка е палиндром. Преди да се провери самия елемент се премахват всички празни интервали и главни букви. Ако е палиндром се отпечатва на конзолата. Ако не е се преминава на следващият елемент.
Поздрави!


от Nikolay_Radkov (2911 точки)