forked from AllenDowney/ThinkPython
-
Notifications
You must be signed in to change notification settings - Fork 0
/
reducible.py
120 lines (89 loc) · 2.82 KB
/
reducible.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""This module contains code from
Think Python by Allen B. Downey
http://thinkpython.com
Copyright 2012 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
"""
def make_word_dict():
"""Reads the words in words.txt and returns a dictionary
that contains the words as keys."""
d = dict()
fin = open('words.txt')
for line in fin:
word = line.strip().lower()
d[word] = word
# have to add single letter words to the word list;
# also, the empty string is considered a word.
for letter in ['a', 'i', '']:
d[letter] = letter
return d
"""memo is a dictionary that maps from each word that is known
to be reducible to a list of its reducible children. It starts
with the empty string."""
memo = {}
memo[''] = ['']
def is_reducible(word, word_dict):
"""If word is reducible, returns a list of its reducible children.
Also adds an entry to the memo dictionary.
A string is reducible if it has at least one child that is
reducible. The empty string is also reducible.
word: string
word_dict: dictionary with words as keys
"""
# if have already checked this word, return the answer
if word in memo:
return memo[word]
# check each of the children and make a list of the reducible ones
res = []
for child in children(word, word_dict):
t = is_reducible(child, word_dict)
if t:
res.append(child)
# memoize and return the result
memo[word] = res
return res
def children(word, word_dict):
"""Returns a list of all words that can be formed by removing one letter.
word: string
Returns: list of strings
"""
res = []
for i in range(len(word)):
child = word[:i] + word[i+1:]
if child in word_dict:
res.append(child)
return res
def all_reducible(word_dict):
"""Checks all words in the word_dict; returns a list reducible ones.
word_dict: dictionary with words as keys
"""
res = []
for word in word_dict:
t = is_reducible(word, word_dict)
if t != []:
res.append(word)
return res
def print_trail(word):
"""Prints the sequence of words that reduces this word to the empty string.
If there is more than one choice, it chooses the first.
word: string
"""
if len(word) == 0:
return
print word,
t = is_reducible(word, word_dict)
print_trail(t[0])
def print_longest_words(word_dict):
words = all_reducible(word_dict)
# use DSU to sort by word length
t = []
for word in words:
t.append((len(word), word))
t.sort(reverse=True)
# print the longest 5 words
for length, word in t[0:5]:
print_trail(word)
print '\n'
if __name__ == '__main__':
word_dict = make_word_dict()
print_longest_words(word_dict)