![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
Simple, contrived programming exercise
Most of us know how to test a word (or phrase) to see if it's a palindrome. This exercise is, therefore, somewhat artificial. Consider a phrase written on the side of a flexible material. Presuming that you can visualize characters upside down, you may locate palindromes by bending the material back on itself and sliding it along, looking for matches. Duplicate this method, using any language you like. Use a greedy search. That is, find the longest palindrome present at any given point. No need to find a short palindrome located within a longer one. No need to detect a palindrome that overlaps another. Most famous palindromes ignore spaces and punctuation (including apostrophes and quotation marks). That will be the case here. When you have discovered the first, longest palindrome, substitute for it the character sequence, **PALINDROME**, and proceed with the remainder of the phrase.
1. Show your 'stripped' material (less punctuation, etc.). 2. Output your first palindrome. 3. Output the remainder. 4. Do it all again with the remainder. 5. Output the substituted phrase. Here are a couple of test phrases: Makeable was I ere I saw Elba from the racecar (Madam, I'm Adam). "Am I mad, eh?" Giselle sighed, "Am I, Ma?" Critique each other's code, offering suggestions for improvement. Be big boys, don't get pissed at criticism.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#2 |
|
Battle Programmer
Join Date: Feb 2006
Location: Bellevue, WA, USA
Posts: 773
Rep Power: 3
![]() |
Does the "do it all again" in #4 mean to do steps 1-3, as though recursive? I.e. on your first sample, it would result in
1) MakeablewasIereIsawElbafromtheracecarMadamImAdam
2) ablewasiereisawelba
3) MakefromtheracecarMadamImAdam
4) 1) MakefromtheracecarMadamImAdam
2) madamimadam
3) makefromtheracecar
4) 1)makefromtheracecar
2) racecar
... (didn't want to bother with this, and I think the example will suffice)
5) makefromthe**PALINDROME**
5) makefromthe**PALINDROME****PALINDROME**
5) make**PALINDROME**from the**PALINDROME****PALINDROME**I dunno if I even worked things out right, I was just doing them quickly here to illustrate my question. |
|
|
|
|
|
#3 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
No, minimum palindrome of length three. I didn't mean to imply recursion, but to find the first, longest palindrome, get rid of that part of the phrase, and find the next.
The intent of the problem was to force development of a contrived solution (the folded phrase) despite the fact that it's not the most effective method. This provides a 'game' programming exercise that should result in some thought and considerations, as opposed to the 'add a line' thing. One aspect of creativity in developing solutions is to consider as many methods as possible, rejecting the worst. One may discover a new method. Also, sometimes one is forced to solve a problem as the client wishes it solved, not in the best possible way. Just an attempt to fill a seeming void. "Am I mad, eh?" Giselle sighed, "Am I, Ma?" The 'drome after 17 invalid characters removed: AmImadehGisellesighedAmIMa First palindrome: AmIma Remainder: dehGisellesighedAmIMa Next palindrome: dehGisellesighed Remainder: AmIMa Next palindrome: AmIMa Substituted result: **PALINDROME****PALINDROME****PALINDROME** Notice that this isn't truly the greediest, as the entire phrase is a palindrome. I don't really know how to explain it, and won't be picky at the solutions. I want to see the fold method implemented, simply because it's a humanistic solution forced on the machine, as opposed to a von Neumann solution forced on the coder.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#4 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
Okay, this is what I mean to say. Find the first palindrome of any length (minimum 3 to qualify). No need to find a palindrome within or overlapping. This is taken care of by discarding the found palindrome (and by substituting in the **PALINDROME** in the final output string) and working with the remainder. You new guys that are trying to learn to code, here's your chance to solve a problem on demand and to a specification, however silly the overall concept might be, and to express that solution in the language of your choice.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#5 |
|
Newbie
Join Date: May 2006
Posts: 28
Rep Power: 0
![]() |
Sounds fun, ill try to work this out when i get home from work.
|
|
|
|
|
|
#6 |
|
Programming Guru
![]() |
This was a surprisingly difficult challenge (at least, for me). My Python code is below:
"""Overlapping Palindrome Test"""
_debug = True
min_len = 1
### The phrase ###
phrase = '"Am I mad, eh?" Giselle sighed, "Am I, Ma?"';
if _debug: print 'The phrase:', phrase
### Strip the phrase ###
phrase = phrase.lower()
alphabet = 'abcdefghijklmnopqrstuvwxyz'
phrase = [letter for letter in phrase if letter in alphabet]
if _debug: print 'The stripped phrase:', ''.join(phrase)
if _debug: print # Newline (for aesthetics)
# Pop the last min_len characters from phrase into reversed
reversed = []
for i in range(min_len):
reversed.append(phrase.pop())
results = []
# t holds odd letters (for example, 'i' in 'madamimadam')
t = None
for pos in range( len(phrase) ):
# Try each match with and without t
if t == None:
t = phrase.pop()
else:
reversed.append(t)
t = None
phr_len = len(phrase)
rev_len = len(reversed)
# Store letters in temp as we accumulate a palindrome
temp = ''
for i in range(rev_len):
# Attempt to match corresponding indices of phrase and reversed
j = phr_len - rev_len + i
if reversed[i] != phrase[j] and i != rev_len - 2:
# If unsuccessful, try again with new letters
break
else:
# We have begun to accumulate a palindrome
temp += reversed[i]
if i == rev_len - 1:
# We have a palindrome!
# Assemble the palindrome
palindrome = temp
if t != None:
palindrome += t
palindrome += temp[::-1]
if _debug:
print 'Palindrome: ', palindrome
print 'Remainder: ', ''.join(phrase)
print
# Add the palindrome to the list of results
results.append(palindrome)
### Print the palindromes (if not in debug mode) ###
if not _debug:
print "\n".join([result for result in results])The phrase: "Am I mad, eh?" Giselle sighed, "Am I, Ma?" The stripped phrase: amimadehgisellesighedamima Palindrome: amima Remainder: amimadehgisellesighedam Palindrome: amimadehgisellesighedamima Remainder: amimadehgisel Last edited by titaniumdecoy; Jun 13th, 2006 at 3:29 PM. |
|
|
|
|
|
#7 | ||
|
Battle Programmer
Join Date: Feb 2006
Location: Bellevue, WA, USA
Posts: 773
Rep Power: 3
![]() |
first thing I whipped together (in C++). It iterates through the input string (passed as argv[1]), and replaces the longest palindrome (if any) from whatever index it's at.
#include <string>
#include <cctype>
#include <iostream>
const int MINPALINDROMESIZE = 3;
std::string strip(const std::string& s)
{
std::string stripped;
for(int i = 0; i < s.length(); ++i)
if(std::isalpha(s[i]))
stripped += s[i];
return stripped;
}
bool isPalindrome(const std::string& s)
{
for(int i = 0, j = s.length() - 1; i < j; ++i, --j)
if(std::tolower(s[i]) != std::tolower(s[j]))
return false;
return true;
}
std::string firstPalindrome(const std::string& s)
{
int start = 0, len = 1;
for(int i = 0; i < s.length(); ++i)
{
int curStart = i, curLen = 1;
for(int k = s.length() - 1; i < k; --k)
{
if(std::tolower(s[i]) == std::tolower(s[k])) // ends match, so check insid
e
{
curLen = k - i + 1; // length of substring being considered
if(curLen >= MINPALINDROMESIZE && isPalindrome(s.substr(i, curLen)))
{
if(curLen > len)
start = curStart, len = curLen;
goto end; // found largest pdrome for this starting letter
}
}
}
}
end:
std::string result;
if(len >= MINPALINDROMESIZE)
result = s.substr(start, len);
return result;
}
int main(int argc, char** argv)
{
if(argc != 2)
{
std::cerr << "Usage: " << argv[0] << " <phrase>" << std::endl;
return 1;
}
std::string s = strip(argv[1]);
std::cout << "The phrase after being stripped: " << std::endl;
std::cout << s << std::endl << std::endl;
std::string pal, res, rem;
pal = firstPalindrome(s);
if(pal == "")
std::cout << "No palindromes found in this string.";
else
{
rem = s.substr(s.find(pal)+pal.length());
res = s.substr(0, s.find(pal)) + "**PALINDROME**";
std::cout << "First Palindrome: " << pal << std::endl;
if(rem != "")
std::cout << "Remainder: " << rem << std::endl;
while((pal = firstPalindrome(rem)) != "")
{
res += rem.substr(0, rem.find(pal)) + "**PALINDROME**";
rem = rem.substr(rem.find(pal) + pal.length());
std::cout << std::endl;
std::cout << "Next Palindrome: " << pal << std::endl;
if(rem != "")
std::cout << "Remainder: " << rem << std::endl;
}
if(rem != "")
res += rem;
std::cout << std::endl;
std::cout << "Substituted Result: " << res << std::endl;
}
return 0;
}Sample output: Quote:
Quote:
Last edited by Jimbo; Jun 13th, 2006 at 4:00 PM. |
||
|
|
|
|
|
#8 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 655
Rep Power: 4
![]() |
I have just finished my program in Ruby, but I am in the process of adding comments and such. I'm just posting so that you know there is interest, David.
![]()
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS! |
|
|
|
|
|
#9 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 655
Rep Power: 4
![]() |
Ok, here goes.
#Set this to true for a better understanding of how the program works
$DEBUG = false
# Return the largest palindrome anywhere in the string.
# It is assumed that the input has been passed first through process_string to
# rid it of only alphabetic characters.
# nil is returned if there are no palindromes in the string.
def find_largest_palindrome(raw_str)
puts "Raw string = #{raw_str.join}"
# an array to hold all the palindromes in the string
pals = Array.new
# loop through the indexes of the character array
raw_str.each_index do |a|
# set the string to be tested for palindromes one letter less each time
testing_str = raw_str[a..raw_str.length]
if $DEBUG
puts "Testing String: #{testing_str.join}"
sleep(0.1)
end
0.upto(testing_str.length) do |b|
# set the reversed string to the reverse of the testing string, but
# cycle through all the possible reverses to find all the possible
# matches.
reversed_str = testing_str.reverse[b..testing_str.length]
if $DEBUG
puts "\tReversed String: #{reversed_str.join}"
end
sub_str = String.new
testing_str.each_index do |j|
if testing_str[j] == reversed_str[j]
sub_str << testing_str[j]
else
break
end
end
unless sub_str.empty? or pals.include?(sub_str) or sub_str.length < 3
pals << sub_str
if $DEBUG
puts "\t\t\t\tAdding palindrome: * #{sub_str} *"
sleep(1)
end
end
end
end
return pals.max { |a, b| a.length <=> b.length }
end
# Process the input string.
# First, all instances of **PALINDROME** are removed
# so they are not included in the search for palindromes.
# Second, all characters are removed except for letters of the alphabet.
# An Array containing all the letters of the string is returned.
def process_string(string)
string.chomp.gsub("**PALINDROME**", '').gsub(/[^a-z]/i, '').downcase.split(//)
end
def dawei_challenge(phrase)
result = process_string(phrase).join
loop do
pal = find_largest_palindrome(process_string(result))
puts "Largest palindrome = #{pal or "None"}"
if $DEBUG
sleep(2)
end
if not pal
puts "No more palindromes!"
puts "Final result is \"#{result}\"."
return
else
result.sub!(pal, '**PALINDROME**')
puts "Result so far: #{result}\n\n"
end
end
result
end
text1 = "Makeable was I ere I saw Elba from the racecar (Madam, I'm Adam)."
text2 = "\"Am I mad, eh?\" Giselle sighed, \"Am I, Ma?\""
dawei_challenge(text1)EDIT:Helps if I post the code :p This is very hard for me to explain, so I recommend setting $DEBUG to true to get a better sense of this program. A string is first processed, and then passed to find_largest_palindrome() repeatedly, each time substituting the largest one out. find_largest_palindrome() took a lot of trial and error to write. Basically, it will go through all possible combinations of strings, and go through all possible strings to test it against. Here is sample output if somebody does not have Ruby on their home computer: $ ruby palindrome.rb Raw string = makeablewasiereisawelbafromtheracecarmadamimadam Largest palindrome = ablewasiereisawelba Result so far: make**PALINDROME**fromtheracecarmadamimadam Raw string = makefromtheracecarmadamimadam Largest palindrome = madamimadam Result so far: make**PALINDROME**fromtheracecar**PALINDROME** Raw string = makefromtheracecar Largest palindrome = racecar Result so far: make**PALINDROME**fromthe**PALINDROME****PALINDROME** Raw string = makefromthe Largest palindrome = None No more palindromes! Final result is "make**PALINDROME**fromthe**PALINDROME****PALINDROME**". My next challenge would be to attempt this in C or C++, but it was challenging enough for me using a scripting language! :p
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS! Last edited by Jessehk; Jun 13th, 2006 at 5:12 PM. |
|
|
|
|
|
#10 |
|
Programming Guru
![]() Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5
![]() |
I took a somewhat functional approach:
import string import sys def parts(text, size): for i in xrange(len(text) - size + 1): yield text[i:i + size] def substrings(text, min): for size in xrange(min, len(text) + 1): for part in parts(text, size): yield part def maxlen(x, y): if len(x) > len(y): return x else: return y def reverse(text): return "".join(list(reversed(text))) def palindrones(text, min = 3): return set(s for s in substrings(text, min) if s == reverse(s)) def keep_only(text, keep): return "".join(c for c in text if c in keep) def sanitise(text): return keep_only(text.lower(), string.lowercase) def max_palindrone(text, min = 3): found = palindrones(sanitise(text), min) if found: return reduce(maxlen, found) def split_at_substring(text, s): index = text.find(s) return text[:index], text[index:index + len(s)], text[index + len(s):] def mark_palindrones(text, min = 3): palindrone = max_palindrone(text, min) if palindrone: before, _, after = split_at_substring(sanitise(text), palindrone) return mark_palindrones(before, min) + "**PALINDROME**" + \ mark_palindrones(after, min) else: return text print mark_palindrones(sys.argv[1]) $ python palindrome.py "Makeable was I ere I saw Elba from the racecar (Madam, I'm Adam)." make**PALINDROME**fromthe**PALINDROME****PALINDROME** $ python palindrome.py '"Am I mad, eh?" Giselle sighed, "Am I, Ma?"' **PALINDROME** |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|