【習題】算法
【1】漢諾塔的移動編程
【2】自定義strip方法app
【3】打印前n個斐波那契數列的值函數
【4】打印楊輝三角測試
【5】使用reduce和map從新定義函數float( )spa
【6】打印全部素數命令行
【7】將L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]排序設計
【8】設計一個decorator,使它能做用於任何函數,並打印出函數執行的時間3d
【9】將題【8】中的裝飾器做用於一個打印素數的函數,要求輸入素數的最大值調試
【10】將題目改形成class
【11】讓用戶輸入名字,再次運行程序後仍可對用戶表示歡迎(並肯定用戶是否爲上次運行該程序的用戶)
【課外練習】
【1】定義階乘函數
【2】記由1,2,3,4組成的三位數爲x,寫出全部無重複數字的x
【3】一個整數,它加上100後是一個徹底平方數,再加上168又是一個徹底平方數,請問該數是多少?
也就是,x爲整數,n1,n2也爲整數,,
【4】打印九九乘法表
【6】將一個正整數分解質因數
【7】輸入一個成績,符合{'A': >= 90 丨'B': 60 <= x < 90丨'C': < 60 },分別輸出等級
【8】一個數若是剛好等於它的因子之和則稱爲"完數"。例如6=1+2+3.編程找出1000之內的全部完數
【9】打印一個菱形圖案
【11】按逗號分隔列表,如L = [1,2,3,4,5],返回1,2,3,4,5
【零落的知識點】
① sum( list ) = reduce( lambda x,y : x+y , list )
② L[:1] = L[0]
③ num = 123;num = input( )、輸入123;這二者得到的123類型都爲str,而不是int
④ 習題中有一題是比較輸入的兩個值,Maximum = lambda x,y : (x>y)*x + (x<y)*y,式子中的(x>y)和(x<y)都是布爾表達式,當爲True時顯示爲1、爲False時顯示0;將0和1代入式子中,剛好能夠計算出最大值。(固然,存在x=y時的bug)
⑤ 自定義int( )函數:return reduce( fn , list(map(int , n)))
⑥ 高階函數可被簡化:
map(add_10 , [1,2,3]) --> [add_10(i) for i in [1,2,3]]
reduce(lambda x: x > 5 , [1,2,8,5,9]) --> [x for x in [1,2,8,5,9] if x > 5]
【答案】
【1】漢諾塔的移動
PS:從抽象層面上去理解
【2】自定義strip方法
PS:從這題中可看出,對遞歸和切片的運用還很不熟練
【3】打印前n個斐波那契數列的值
方法①:
PS:利用同行賦值式,你應該記得上面的a , a+b被組裝成一個排序
方法②:
PS:結合斐波那契數列的特性,先設立特殊狀況【即前兩個[1]】,再利用Python從後遍歷,使用append
方法③:(輸入x,若僅顯示第x個數,而不是顯示從1到x的整段數列)
PS:理解斐波那契數列的特性,先設立特殊起始值,經過遞歸,在抽象層面上解決問題
方法④:(與方法③類似,都是運用遞歸,但可顯示1到x的整段數列)
PS:輸入x,方法③只能顯示第x個數值,如此,利用map遍歷range(1,x+1)獲得整個Iterator。問題是它彷佛佔用很大內存,調用Fib【20】有時會長時間沒法計算出結果筆記{尾遞歸}中有問題的補充,緣由是其遞歸算法形成極大的冗餘調用,複雜度是指數級的
方法⑤:(這是對方法④的改進,解決遞歸的低效率問題)
PS:二者的Fib函數沒有不一樣,但這裏的fib函數實際上是模仿方法①的同行賦值式a,b = b,a+b,設立特殊值(n = 1和n = 2),設立算法的最終輸出(n = 3時返回a+b,符合斐波那契數列的定義),經過遞減n控制次數,在次數限制下不斷對初始的a = 1 , b = 1進行邏輯運算,獲得結果
由代碼可看出,每到遞歸的步驟時僅對函數自身調用1次,因爲n是遞減的,因此這個函數的複雜度是線性的;因爲Python默認限制最大遞歸深度爲997,因此該代碼可計算Fib(900)無壓力
方法⑥:(非函數在模塊中被導入,而是直接運行.py文件)
PS:
這裏最重要的一點是最後的print( )函數,做爲函數的返回值返回後,在命令行窗口會直接輸出;但運行.py文件卻不會,即便返回一個list,也沒有標明對它的操做是什麼,所以這時藉助print( )函數輸出
此外,對高階函數的運用還不到位,map都丟到角落不會用了,傻傻地1行代碼寫成4行...
【4】打印楊輝三角
———————————————————————————————————————————————————
PS:思路有了,但對數值的把握火候不夠,n的初始值老是要進過調試才能肯定...不知道這是否正常
PS:漸漸開始熟悉了:
①假設列表L存在,因爲規則爲相鄰兩個數值相加,可經過range( len(L) -1 )來控制本次相加的次數
②經過max值來控制總的L的相加次數
【5】使用reduce和map從新定義函數float( )
———————————————————————————————————————————————————
涉及字典dict、lambda、index
【6】打印全部素數
① 定義全體天然數N,用n = N( )獲取Iterator
② 定義篩選函數not_division,注意這裏的雙變量使用(注:這裏的filter中的函數能夠接收參數)
③ n1 = next(n)獲取Iterator的第一個值,返回第一個值後,用filter進行篩選,n中但凡是能夠整除n1的都會被刪去,包括與n1等值的n的第一個值。
④ 不斷重複步驟③,不斷獲取第一個值
【7】將L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]排序
PS:因爲各個元素爲tuple,匿名函數旨在單獨取出各個tuple中的字符串或數字
【8】設計一個decorator,使它能做用於任何函數,並打印出函數執行的時間
PS:注意執行函數func需在定義start和end之間;以及最後記得返回wrapper
記得語法糖@的含義,以及使用它時的位置
【9】將題【8】中的裝飾器做用於一個打印素數的函數,要求輸入素數的最大值
PS:①原primes爲迭代器,要想被裝飾,修改成函數(經過提早設立max、將yield改成print)
②嚴格遵守了裝飾器(Docorator)的模板
③採用if __name__ == '__main__'的方式減小繁雜的程序測試
【10】將斐波那契數列題目/打印素數題目修改成class
PS:經過input、初始化self.max能夠達到設置退出循環條件的目的~
PS:這裏錦上添花,運用了\r和time模塊的sleep函數,效果不錯,可是被註釋掉的那行若是替代如今的print,(也就是我想輸出一長列的元素,但每一個稍有些間隔纔出現),會發現沒法退出循環【??】
【11】讓用戶輸入名字,再次運行程序後仍可對用戶表示歡迎(並肯定用戶是否爲上次運行該程序的用戶)
PS:多練習,這是通過重構的代碼
【課外練習答案】
【1】定義階乘函數
方法①:(使用高級函數)
方法②:(利用遞歸)
【2】記由1,2,3,4組成的三位數爲x,寫出全部無重複數字的x
PS:思惟侷限在要打印一個完整的數字,卻不知能夠將一個數字當作是多個數字字符串的並列組合
【3】一個整數,它加上100後是一個徹底平方數,再加上168又是一個徹底平方數,請問該數是多少?
即,,其中x爲整數,n1,n2也爲整數
PS:在草稿紙上列出數學關係式,即題目的第二行
①先找出n2的最大值:因爲n1、n2同爲徹底平方數,因此假設它們之間的間隔爲最小值1,又已知它們平方後的間隔爲168,因此經過while不斷接近n2的近似最大值;經過求出n2的近似最大值,能夠減小計算機的無效計算
②經過列表生成式將分別知足條件n1、n2的x篩選出來,設爲x1、x2,;因爲n2爲最大值,即n2 > n1,n1的範圍是n2的子集,因此所求的n2近似最大值能夠做用於n1
③求出x1、x2後,因爲x1、x2分別爲一半題目的解,這時題意就變爲求同時知足x1、x2的x的全部可能;經過set( )將list轉變爲無序且不重複的集合,再將set進行數學的集合運算,即求交集,獲得答案x
最後,上述列表生成式能夠用高階函數map和lambda取代:
【4】打印九九乘法表
PS:其中涉及print函數中的end用法,詳見參考筆記O(∩_∩)O
【5】求101到200之間的全部素數及個數
首先這是一個錯誤的範例:
調試結果代表,若是連續出現3個合數,如104,105,106,上述方法會將中間的105忽略!
緣由:Python中for循環是根據下標的,上述方法中,當remove(104)後,本來{104}所屬的索引位4被空缺,接由後面的{105}取代索引位4;break後,for循環依據下標,直接對索引位爲5的元素進行邏輯運算,就這樣,索引位爲4的{105}被錯過;事實上,當{102}被remove掉,後面的{103}也沒有被檢測,儘管{103}是素數,但這種篩選方法顯然是有漏洞的
正確範例:
修改後的代碼對L使用了切片複製獲得L_copy,在判斷時使用的是L中的元素,但刪除的倒是L_copy中的元素,這樣,for循環迭代L中元素時不會出現遺漏
方法②:(待刪)
PS:我以前就疑惑如何徹底刪除一個數列中全部的某個元素,直到複習時無心發現結合使用while和in能夠重複刪去,這才成功;而後就是定點刪除的問題,list沒有remove這個屬性,屬於檢測到x爲合數時,沒辦法直接刪去x,因此只能使用手動下標,將合數先轉變爲空格,再將list中的全部空格刪去
【6】將一個正整數分解質因數
PS:該題較爲簡單,複習時可嘗試使用range;有人先用生成器生成一個素數的無限數列,而後將參數n逐個除以素數,並輸出該素數和修改參數n
【7】輸入一個成績,符合{'A': >= 90 丨'B': 60 <= x < 90丨'C': < 60 },分別輸出等級
PS:這是一種暫時還沒學的方法,該方法在Python 3.x上運行是ok的,從代碼的內容和運行狀況能夠大體瞭解一下這種方法。
①格式爲print([...][...])
②前一個[...]中輸入若干個字符串,字符串按順序排列,擁有索引0、1、2等
③後一個[...]對輸入的參數進行判別且必須進行參數運算,單純地[score]會報ValueError,因此哪怕是無心義的[score//1]也必須敲上;對參數進行運算後(即上述的score//30),根據獲得的結果分別對應索引號輸出相應的字符串,若無對應的索引號,將會報IndexError
以上面代碼爲例,前一個[...]共有4個字符串等待輸出,則擁有4個索引號,即0、1、2、3;又由於後面的運算爲[score//30],要想參數score地板除30獲得相應的索引號,則score的範圍爲[0,120];又因爲Python支持倒數遍歷,因此索引號-1、-2、-3、-4都是容許的,因此參數score範圍實爲[-120,120],超出範圍即報IndexError。
在符合範圍的前提下,每運算出一個一個相應的索引號,就會print相應的字符串
【8】一個數若是剛好等於它的因子之和則稱爲"完數"。例如6=1+2+3.編程找出1000之內的全部完數。
PS:不難,待刪
【9】打印一個菱形圖案
效果圖:
PS1:我本來的思路是根據max獲得L = ' '*max,算出max中間那個數middle,定義逐漸遞增的num,使範圍在(middle - num , middle + num)中的全部空格替換成星號'*';問題是字符串在Python中是不可修改的,修改的方法
①replace,這個方法中如替代L[0]爲L[0].upper( ),全部爲L[0]的字符都會被替換,而不僅是L[0]處的字符
②join,彷佛可行,但還沒學 【因此之後學了試試?】
③切片,字符串也是序列,可使用序列下標的方式,即L[:3]+'*'*num+L[-3:]
驚覺方法③有可能成功,而後立刻試驗:
PS2:這裏有幾點說明下:
①改善了原問題,使規定打印星號{*}的菱形變爲打印輸入的某個字符,即用string替代 '*'
②num -= 4的緣由在圖中有說明
③實際上,L[:l_num] + string*num + L[r_num:]中的數據沒有通過準確推敲,而是憑感受敲上去的
④若輸入的string爲中文漢字,因爲漢字所佔的字節數爲2,而空格爲1,因此不能造成規則菱形
⑤這裏的類型檢查彷佛不行,if not ( isinstance ( string , str ) ) or ( isinstance ( max , int )) 已解決,應爲if not ( isinstance ( string , str ) ) and ( isinstance ( max , int )),and和or使用錯誤
PS3:我是認定每一行長度皆爲max,在這個基礎上敲代碼;另外一種思路是隻看每行星號前的空格數、星號數,星號後面的就由它去吧。上面的代碼就是一個例子
【標準答案涉及stdout】
【10】利用遞歸,將輸入的一個字符串倒序輸出
PS:遞歸時注意len(n)這個數就比n最後一個字符的索引大1,因此即便切片[x:y]不取y,也要減去1
【打印出的每一個字符都間隔一個空格,嘗試將空格刪除?】
【11】按逗號分隔列表,如L = [1,2,3,4,5],返回1,2,3,4,5
PS:這題旨在剝除list的外殼,將裏面的元素逐個返回,關鍵點在於打印逗號,可用[1:-1]去除首端的空格和末尾的逗號
PS:一樣可經過print來實現,注意if和else的位置,且之間無需其餘分隔符
【此外,有的答案還涉及join、repr】