学习python时记录本身或观察别人从错误到正确的思路远比只看正确答案效果好——傅查理python
看到求和想到前面用到的内置函数sum(t),可是sum只说了是求列表内全部值的和,不知道能不能求部分和,因此须要作一下测试app
t=[1,2,3] sum(t[:2])
返回值是3,表示能够用sum,而后得出以下代码:dom
def cumulative_sum(t): res=[] for i in range(len(t)-1): #刚开始想着后面有i+1,之前这里都是须要减一的,可是忽略了":(i+1)"是不包括右侧的i+1的,因此不用减一 res.append(sum(t[:(i+1)])) return res t=[1,2,3] cumulative_sum(t)
返回值是[1,3],因此把减一去掉就能够了函数
def cumulative_sum(t): res=[] for i in range(len(t)): res.append(sum(t[:(i+1)])) return res t=[1,2,3] cumulative_sum(t)
这里有两点须要注意下,res后用append,我刚开始写成了res[i]=sum(t[:(i+1)]),这把字典和列表方法弄混,另外就是忘记了t[:(i+1)]中的“:”,也形成报错,须要注意下这些细节地方,这些bug是能够直接显示出来的,可是刚才那个减一是显示正常可是不符合预期结果,由于咱们知道预期结果,因此才能检查出问题,若是不知道那就难了,写代码时仍是须要提早想清楚。学习
列表删除元素有三种方法,需注意三者区别和是否有返回值:测试
对象和值:rest
a='banana' b='banana' a is b
输出是Truecode
c=[1,2,3] d=[1,2,3] c is d
输出是False对象
前面a和b咱们会说他们是相同的,在这个例子里python只创建了一个自发货车对象,而a和b都引用了它。排序
然后面两个咱们能够说c和d是相等的,由于他们有相同的元素,但他们不是相同的。由于他们并非同一个对象。若是两个对象相同,则否则相等,若是相等,但不必定相同。注意区分相同和相等。
区分修改列表的操做和新建列表的操做十分重要。例如append是修改列表,“+”则是新建列表。
t1=[1,2] t2=t1.append(3) print(t1) print(t2)
[1, 2, 3] None #t2返回None说明t1.append(3)没有返回值
t3=t1+[4] print(t3)
[1, 2, 3, 4]
切片操做会新建一个列表
def tail(t): return t[1:] letters=['a','b','c'] rest=tail(letters) print(rest)
['b', 'c']
给的提示是两个单词,若是从新排列其中一个的字母能够获得另外一个则互为回文,这个提示我是看懂了,可是感受不太对,上网查了下也只查了些诗中有互为回文的,可是那个写的是前面说的互为倒序的,那么就奇怪了,互为回文和互为倒序有什么区别,暂时先按照提示来写吧
def is_anagram(word1,word2): if word1.sorted()==word2: return True return False is_anagram('ab','ba')
AttributeError Traceback (most recent call last) <ipython-input-72-85d6d5401dcc> in <module> 4 return True 5 return False ----> 6 is_anagram('ab','ba') <ipython-input-72-85d6d5401dcc> in is_anagram(word1, word2) 1 #练习:编写一个函数is_anagram,接收两个字符串,当它们互为回文时返回True 2 def is_anagram(word1,word2): ----> 3 if word1.sorted()==word2: 4 return True 5 return False AttributeError: 'str' object has no attribute 'sorted'
报错提示字符串不能使用sorted,多是记错了,那用下sort试一下
def is_anagram(word1,word2): if word1.sort()==word2: return True return False is_anagram('ab','ba')
结果仍是报一样的错误,而后才想起字符串是不能更改的,若是想排序看样子得先把字符串变成列表才行
def is_anagram(word1,word2): if "".join(list(word1).sort())==word2 or "".join(list(word2).sort())==word1: return True return False is_anagram('hello','ab')
个人想法是先把字符串变成列表,而后排序,后面在用“”.join把分开的字母从新拼在一块儿,结果报错以下:
<ipython-input-74-716276a7e28b> in is_anagram(word1, word2) 1 def is_anagram(word1,word2): ----> 2 if "".join(list(word1).sort())==word2 or "".join(list(word2).sort())==word1: 3 return True 4 return False 5 is_anagram('hello','ab') TypeError: can only join an iterable
有个怀疑是sort()没返回值,而后尝试了下确实没有,那用sorted(t)试了下有返回值,而后把代码改为下面这样:
def is_anagram(word1,word2): if "".join(sorted(list(word1)))==word2 or "".join(sorted(list(word2)))==word1: return True return False is_anagram('hello','ello')
此次就正常了,仍是如前面讲的,注意有没有返回值很重要。
编写一个函数has_duplicates接收一个列表,当其中任何一个元素出现多于一次时,返回True.它不该当修改原始列表
首先想到的就是对列表中每一个元素数一下个数,当任何一个超过1时返回True
def has_duplicates(t): for s in t: if t.count(s)>1: return True return False t=[1,3,2] has_duplicates(t)
固然若是是本身以前不知道count(我也是上网查了用法),能够用笨办法,首先排序,而后挨个判断相邻元素是否相同
def has_duplicates1(t): new_t=t[:] #生成新的列表 new_t.sort() #由于这个会修改列表,不会生成新的列表 for i in range(len(new_t)-1): if new_t[i]==new_t[i+1]: return True return False t=[1,3,3] has_duplicates1(t)
若是大家班有23个学生,那么其中有两人生日相同的概率有多大?可使用random模块中的randint生成随机整数
去查了下官方文档,知道了randint的用法,一次只能生成一个随机数,那么想生成23个就须要用到循环,下面还须要计算几率须要调用,因此生成一个函数
def random_birt(students): t=[] for i in range(students): t.append(random.randint(1,366)) return t # random_birt(23) def count_match(students,numbers): t=random_birt(students) #应该放到循环里,不然只生成一个随机列表,结果都是同样的 count=0 for i in range(numbers): if has_duplicates(t): count+=1 return count count_match(23,1000)
返回值时1000,一想就不对,发现随机列表没有放到循环里,放到循环里后以下
def random_birt(students): t=[] for i in range(students): t.append(random.randint(1,366)) #一年按365天算,因此生成随机数范围是1到365 return t # random_birt(23) def count_match(students,numbers): count=0 for i in range(numbers): t=random_birt(students) if has_duplicates(t): count+=1 return count count_match(23,1000)
返回值494,说明1000次中有494次出现两我的生日相同。几率接近50%
想直接用find方法,试了下发现list是不能用find的,而后经过循环一个个比对了
def bisect(t,target): for i in range(len(t)): if t[i]==target: return i return None t=[1,2,3,4,5,6] bisect(t,5)
上述方法是将列表中全部的元素拿出来与目标一一比对,可是这有个问题就是若是列表很长就会形成速度比较慢,所以咱们能够用二分查找(须要列表是有序的),bisect模块(可见官方文档)用于二分查找:
import bisect def find_lt(a,x): i=bisect.bisect_left(a,x) #bisect.bisect_left(a, x, lo=0, hi=len(a)),在a中找到x合适的插入点,使得x左侧都小于x,右侧大于等于x if i != len(a) and a[i]==x: return i return None t=read_words() find_lt(t,'hello')
二分查找大大下降了查找速度,若是单词列表有113809个,按照第一种方法就要查找相应次数,按照第二种大概17步就能够找到。
import time def read_words(): fin=open('words.txt') t=[] for line in fin: word=line.strip() t.append(word) return t start_time=time.time() t=read_words() elapsed_time=time.time()-start_time print(len(t)) print(t[:10]) print(elapsed_time)
互为倒序的意思是“ad"和”da“这样就是,因此刚开始想着从头开始循环,检查每一个单词的倒序单词是否在单词表中便可,而后代码以下:
def remove_dumplicates(t): #为了去重,不过在验证主程序是否可行前还没调用函数 new_t=[] for i in range(len(t)): if t[i] not in new_t: new_t.append(t[i]) return new_t # t=[1,[1,2],[2,1]] # remove_dumplicates(t) def daoxu(): a=[] t=read_words() for s in t: if s[::-1] in t: a.append(sorted([s,s[::-1]])) return a daoxu()
一直用挨个查找的方法用习惯了,上来随手就写成这样,运行的时候发现忽略了运行时间了。十万个单词,每一个单词反向而后再查找一遍,具体时间就算不过来了,挺长的,因此须要用到二分查找,改为以下
import bisect def remove_dumplicates(t): #去重列表中重复的元素 new_t=[] for i in range(len(t)): if t[i] not in new_t: new_t.append(t[i]) return new_t def find_lt(a,x): #二分查找 i=bisect.bisect_left(a,x) if i != len(a) and a[i]==x: return True return None def daoxu(): a=[] t=read_words() #用到上面生成字母表的列表 for s in t: if find_lt(t,s[::-1])==True and s!=s[::-1]: a.append(sorted([s,s[::-1]])) return remove_dumplicates(a) daoxu()
得出的反向对须要两两不能相同,因此s!=s[::-1],而后再去重,最后就得出所要的结果了。
互锁:两个单词,从每一个单词中交错去除一个字母能够组成一个新的单词,咱们称之为互锁,例如shoe和code能够互锁为schooled
个人思路是将单词表中的每一个单词根据下标的奇偶分别拆分红两个单词,而后查找这两个单词是否都在单词表中,若是在就是互锁,不在就不是,可是在将一个单词拆分时遇到了问题:
for i in range(len('hello')): s1=[] s2=[] if i%2!=0: s1.append(['hello'[i]]) elif i%2==0: s2.append('hello'[i]) print(s1,s2)
返回不符合预期,后面发现是s1和s2放到循环中了,应该放在外面。
s1=[] s2=[] for i in range(len('hello')): if i%2!=0: s1.append('hello'[i]) elif i%2==0: s2.append('hello'[i]) print(s1,s2)
这样就分红了两个列表了,而后经过join将列表拼接成单词
def husuo(): # a=[] t=read_words() #获取单词表 for s in t: s1=[] s2=[] for i in range(len(s)): if i%2!=0: #奇数下标 s1.append(s[i]) #将全部奇数下标组成一个列表 elif i%2==0: #偶数下标 s2.append(s[i]) #将全部偶数下标组成一个列表 word1=''.join(s1) #将列表拼接成字符串 word2=''.join(s2) if find_lt(t,word1) and find_lt(t,word2): #查找两个单词同时在单词表中的状况 print(word1+' '+word2 +' '+s) # return a husuo()
这个问题我想的是两两组成词再查找运算量太大,并且麻烦,反向思考将单词拆分,而后查找就好一些。另外就是大问题要学会拆解成小问题,如前面两步就是看能不能本身把一个单词拆分红奇偶列表。
三互锁单词按照上面的逻辑稍微改一下就好了:
def husuo(): # a=[] t=read_words() for s in t: s1=[] s2=[] s3=[] for i in range(len(s)): if i%3==0: s1.append(s[i]) elif i%3==1: s2.append(s[i]) else: s3.append(s[i]) word1=''.join(s1) word2=''.join(s2) word3=''.join(s3) if find_lt(t,word1) and find_lt(t,word2) and find_lt(t,word3): print(word1+' '+word2 +' '+word3+' '+s) # return a husuo()
下面是答案代码:
from inlist import * def interlock(word_list, word): """Checks whether a word can be split into two interlocked words. word_list: list of strings word: string """ evens = word[::2] odds = word[1::2] return in_bisect(word_list, evens) and in_bisect(word_list, odds) def interlock_general(word_list, word, n=3): """Checks whether a word can be split into n interlocked words. word_list: list of strings word: string n: number of interleaved words """ for i in range(n): inter = word[i::n] if not in_bisect(word_list, inter): return False return True if __name__ == '__main__': word_list = make_word_list() for word in word_list: if interlock(word_list, word): print(word, word[::2], word[1::2]) # for word in word_list: # if interlock_general(word_list, word, 3): # print (word, word[0::3], word[1::3], word[2::3])
我发如今将一个一个单词拆分这块本身作得复杂了,用切片更简单一些,下次得注意下。