1. 程式人生 > >【練習題】第九章--案例學習:單詞遊戲(Think Python)

【練習題】第九章--案例學習:單詞遊戲(Think Python)

在此強調一點:

for i in range(1,5):
    print(i)

answer:

1
2
3
4

for i in range(5):
    print(i)

answer:

0
1
2
3
4

讀取字元列表

在 for 迴圈中也可以使用檔案物件。下面的這個程式讀取整個 words.txt 檔案,然後每行輸出一個詞:

fin = open('words.txt')
    for line in fin:
        word = line.strip()
        print(word)

練習1:

寫一個程式讀取 words.txt,然後只輸出超過20個字母長度的詞(這個長度不包括轉義字元)。

code:

fin=open('word.txt')
for line in fin:
    word=line.strip()
    if len(word)>20:
        print(word+'\n')

練習2:

在1939年,作家厄爾尼斯特·文森特·萊特曾經寫過一篇5萬字的小說《葛士比》,裡面沒有一個字母e。因為在英語中 e 是用的次數最多的字母,所以這很不容易的。事實上,不使用最常見的字元,都很難想出一個簡單的想法。一開始很慢,不過仔細一些,經過幾個小時的訓練之後,你就逐漸能做到了。

好了,我不扯淡了。 寫一個名字叫做 has_no_e 的函式,如果給定詞彙不含有 e 就返回真,否則為假。

修改一下上一節的程式程式碼,讓它只打印單詞表中沒有 e 的詞彙,並且統計一下這些詞彙在總數中的百分比例。

code:

def has_no_e(word):
    if not('e' in word):
        return True
    else:
        return False
    
fin=open('word.txt')
i=0
j=0
for line in fin:
    word=line.strip()
    if has_no_e(word):
        print(word)
        i=i+1
    j=j+1
print(i/j*100,'%')

練習3:

寫一個名叫 avoids 的函式,接收一個單詞和一個禁用字母組合的字串,如果單詞不含有該字串中的任何字母,就返回真。 修改一下程式程式碼,提示使用者輸入一個禁用字母組合的字串,然後輸入不含有這些字母的單詞數目。你能找到5個被禁用字母組合,排除單詞數最少嗎?

code:

for 1:

def avoid(no_word,word):
    for letter in no_word:
        if letter in word:
            return False
    return True

no_word=input('please input an avoiding string: ')
word=input('please input a word: ')
if avoid(no_word,word):
    print('no-avoiding word!')
else:
    print('has avoiding-word!')

for2:

def avoid(no_word,word):
    for letter in no_word:
        if letter in word:
            return False
    return True

def bubble_sort(blist,bword):
    count = len(blist)
    for i in range(0, count):
        for j in range(i + 1, count):
            if blist[i] > blist[j]:
                blist[i], blist[j] = blist[j], blist[i]
                bword[i],bword[j]=bword[j],bword[i]
    return (bword[0],blist[0])

fin=open('word.txt')
#count = len(fin.readlines())
start=ord('a')
storage_word=[]
storage_num=[]
i=0
start=ord('a')
for a in range(1,ord('z')-3):
    for b in range(a+1,ord('z')-2):
        for c in range(b+1,ord('z')-1):
            for d in range (c+1,ord('z')):                
                no_word=chr(start)+chr(start+a)+chr(start+b)+chr(start+c)+chr(start+d)
                for line in fin:
                    word=line.strip()
                    if avoid(no_word,word):
                        i=i+1
                storage_word.append(no_word)
                storage_num.append(i)
                i=0
    start=start+1

print(bubble_sort(storage_num,storage_word))
print(storage_num)
print(storage_word,len(storage_word))

由於冒泡演算法所需計算時間十分長,故沒有嘗試...(可能需要1個小時以上)

練習4:

寫一個名叫uses_only的函式,接收一個單詞和一個字母字串,如果單詞僅包含該字串中的字母,就返回真。你能僅僅用 acefhlo 這幾個字母造句子麼?或者試試『Hoe alfalfa』?

code:

import re
from functools import wraps

def get_alpha_str4(s):
    result = ''.join(re.split(r'[^A-Za-z]', s))
    return result

def uses_only(word,s):
    w=get_alpha_str4(word.lower())
    for letter in w:
        if not(letter in s):
            return False
    return True

if uses_only('Hoe alfalfa','acefhlo'):
    print('True')
else:
    print('False')

練習5:

寫一個名字叫uses_all的函式,接收一個單詞和一個必需字母組合的字串,如果單詞對必需字母組合中的字母至少都用了一次就返回真。有多少單詞都用到了所有的母音字母 aeiou?aeiouy的呢?

code:

def uses_all(word,s):
    for letter in s:
        if not(letter in word):
            return False
    return True

fin=open('word.txt')
i=0
for line in fin:
    word=line.strip()
    if uses_all(word,'aeiou'):
        i=i+1
print(i)

def uses_all(word, required):
    return uses_only(required, word)

 

這就是一種新的程式開發規劃模式,就是降低問題的複雜性和難度,還原到以前解決的問題,意思是你發現正在面對的問題是之前解決過的問題的一個例項,就可以用已經存在的方案來解決。

練習6:

寫一個名字叫is_abecedarian的函式,如果單詞中所有字母都是按照字母表順序出現就返回真(重疊字母也是允許的)。有多少這樣的單詞?

code:

def is_abecedarian(word):
    n=len(word)
    for i in range(1,n):
        last_one=ord(word[i-1])
        next_one=ord(word[i])
        if not(last_one==next_one or last_one==(next_one-1)):
            return False
    return True

fin=open('word.txt')
i=0
for line in fin:
    word=line.strip()
    if is_abecedarian(word):
        i=i+1
print(i)

一種很好的替代思路就是使用遞迴:

def is_abecedarian(word):
    if len(word) <= 1:
        return True
    if word[0] > word[1]:
        return False
    return is_abecedarian(word[1:])

另外一種方法是用 while 迴圈:

def is_abecedarian(word):
    i = 0
    while i < len(word)-1:
        if word[i+1] < word[i]:
        return False
        i = i+1
    return True

程式測試可以用來表明 bug 的存在,但永遠不能表明 bug 不存在。

— Edsger W. Dijkstra

練習7:

給我一個有三個連續雙字母的單詞。我會給你一對基本符合的單詞,但並不符合。例如, committee 這個單詞,C O M M I T E。如果不是有單獨的一個 i 在裡面,就基本完美了,或者Mississippi 這個詞:M I S I S I P I。如果把這些個 i 都去掉就好了。但有一個詞正好是三個重疊字母,而且據我所知這個詞可能是唯一一個這樣的詞。當然有有可能這種單詞有五百多個呢,但我只能想到一個。是哪個詞呢?寫個程式來找一下這個詞吧。

code:

def is_triple_double(word):
    """Tests if a word contains three consecutive double letters.
    
    word: string

    returns: bool
    """
    i = 0
    count = 0
    while i < len(word)-1:
        if word[i] == word[i+1]:
            count = count + 1
            if count == 3:
                return True
(這句加粗語句的位置不要搞錯)
            i = i + 2
        else:
            count = 0
            i = i + 1
    return False

fin=open('word.txt')
for line in fin:
    word=line.strip()
    if is_triple_double(word):
        print(word)

練習8:

有一天我在高速路上開著車,碰巧看了眼裡程表。和大多數里程錶一樣,是六位數字的,單位是英里。加入我的車跑過300,000英里了,看到的結果就是3-0-0-0-0-0.

我那天看到的很有趣,我看到後四位是迴文的;就是說後四位正序和逆序讀是一樣的。例如5-4-4-5就是一個迴文數,所以我的里程錶可能讀書就是3-1-5-4-4-5.

過了一英里之後,後五位數字是迴文的了。舉個例子,可能讀書就是3-6-5-4-5-6。又過了一英里,六個數字中間的數字是迴文數了。準備好更復雜的了麼?又過了一英里,整個六位數都是迴文的了!

那麼問題倆了:我最開始看到的里程錶的度數應該是多少?

寫個 Python 程式來檢測一下所有的六位數,然後輸出一下滿足這些要求的數字。

code:

from __future__ import print_function, division


def has_palindrome(i, start, length):
    """Checks if the string representation of i has a palindrome.

    i: integer
    start: where in the string to start
    length: length of the palindrome to check for
    """
    s = str(i)[start:start+length]
    return s[::-1] == s

    
def check(i):
    """Checks if the integer (i) has the desired properties.

    i: int
    """
    return (has_palindrome(i, 2, 4) and
            has_palindrome(i+1, 1, 5) and
            has_palindrome(i+2, 1, 4) and
            has_palindrome(i+3, 0, 6))(注意切片【2,6】則為2345)


def check_all():
    """Enumerate the six-digit numbers and print any winners.
    """
    i = 100000
    while i <= 999996:
        if check(i):
            print(i)
        i = i + 1


print('The following are the possible odometer readings:')
check_all()
print()

練習9:

最近我看忘了媽媽,然後我們發現我的年齡反過來正好是她的年齡。例如,假如他是73歲,我就是37歲了。我們好奇這種情況發生多少次,但中間叉開了話題,沒有想出來這個問題的答案。

我回家之後,我發現到目前位置我們的年齡互為逆序已經是六次了,我還發現如果我們幸運的話過幾年又會有一次,如果我們特別幸運,就還會再有一次這樣情況。換句話說,就是總共能有八次。那麼問題來了:我現在多大了?

寫一個 Python 程式,搜尋一下這個謎語的解。提示一下:你可能發現字串的 zfill 方法很有用哦。

mycode:

#Python zfill() 方法返回指定長度的字串,原字串右對齊,前面填充0。
def str_fill(i,n):
    return str(i).zfill(n)
def is_euqal(i,j):
    return str_fill(i, 2) == str_fill(j, 2)[::-1]

def check():
    flag1=0
    mom=0
    me=0
    count=0
    for i in range(100):
        flag1=i
        for j in range(100):
            if is_euqal(flag1,j):
                count=count+1
                if count==6:
                    mom=flag1
                    me=j
            flag1=flag1+1
        if count==8:
            print('mom=',mom,'me=',me)
        mom=0
        me=0
        count=0

check()