2018-05-03
刷了牛客网的题目:总结思路(总的思路跟数学一样就是化简和转化)
具体启发点:
1.对数据进行预处理排序的思想:比如8皇后问题
2.对一个数组元素进行比较的操作,如果复杂,可以试试倒过来,从最后一个元素往前面想.
3.动态规划,分治法.
4.超复杂的循环最好的方法是while 1:这种写法.(因为他最大程度保证了灵活性,比如leecode的283题)
leecode习题: 主要是目前在学习 玩转算法面试 leetcode 这个课程,他把leecode的题目做分类,将例题,留习题.我就把所有的例题和习题都自己实现以下.写在下面
就算以后做垃圾码农,也要留下这些题目我的脚印
数组问题:
283
''' 283. 移动零 题目描述提示帮助提交记录社区讨论阅读解答 随机一题 给定一个数组 nums, 编写一个函数将所有 0 移动到它的末尾,同时保持非零元素的相对顺序。 例如, 定义 nums = [0, 1, 0, 3, 12],调用函数之后, nums 应为 [1, 3, 12, 0, 0]。 注意事项: 必须在原数组上操作,不要为一个新数组分配额外空间。 尽量减少操作总数。 ''' class Solution: def moveZeroes(self, nums): i=0 j=0 p=len(nums) while 1: if nums[i]==0: nums.pop(i) nums.append(0) j+=1 else: j+=1 i+=1 if j==p: break
27
'''27. 移除元素 题目描述提示帮助提交记录社区讨论阅读解答 随机一题 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 示例 1: ''' class Solution: def removeElement(self, nums, val): """ :type nums: List[int] :type val: int :rtype: int """ i=0 count=0 old=len(nums) while 1: if nums==[]: break if i==len(nums): break if nums[i]==val: nums.pop(i) else: i+=1 return len(nums)
26
''' 26. 删除排序数组中的重复项 题目描述提示帮助提交记录社区讨论阅读解答 随机一题 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 这个题目我偷鸡了,因为他数据是升序排列的,期待真正的答案! ''' class Solution: def removeDuplicates(self, nums): """ :type nums: List[int] :rtype: int """ #必须要原地址删除,所以用set来去重不可以. #额外空间是O(1)所以,也不能记录原来元素来开一个数组.又是操蛋问题.简单问题玩出新难度. a=set(nums) b=list(a) b=sorted(b) for i in range(len(b)): nums[i]=b[i] return len(b)
80
''' 80. 删除排序数组中的重复项 II 题目描述提示帮助提交记录社区讨论阅读解答 随机一题 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 ''' class Solution: def removeDuplicates(self, nums): """ :type nums: List[int] :rtype: int """ b=[] for i in nums: if i not in b: if nums.count(i) >=2: b+=[i,i] if nums.count(i)==1: b+=[i] b=sorted(b) for i in range(len(b)): nums[i]=b[i] return len(b)
75
''' 75. 分类颜色 题目描述提示帮助提交记录社区讨论阅读解答 随机一题 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 ''' class Solution: def sortColors(self, nums): """ :type nums: List[int] :rtype: void Do not return anything, modify nums in-place instead. """ a1=nums.count(0) a2=nums.count(1) a3=nums.count(2) for i in range(a1): nums[i]=0 for i in range(a2): nums[i+a1]=1 for i in range(a3): nums[i+a1+a2]=2
88
class Solution: def merge(self, nums1, m, nums2, n): """ :type nums1: List[int] :type m: int :type nums2: List[int] :type n: int :rtype: void Do not return anything, modify nums1 in-place instead. """ b=nums1[:m] c=sorted(b+nums2) for i in range(len(nums1)): nums1[i]=c[i]
215
class Solution: def findKthLargest(self, nums, k): """ :type nums: List[int] :type k: int :rtype: int """ return sorted(nums)[len(nums)-k]
167:精彩的对撞指针题目:
class Solution: def twoSum(self, numbers, target): """ :type numbers: List[int] :type target: int :rtype: List[int] """ for i in range(len(numbers)): if i>0 and numbers[i]==numbers[i-1]: continue for j in range(i+1,len(numbers)): if numbers[i]+numbers[j]==target: return [i+1,j+1]
class Solution: def twoSum(self, numbers, target): """ :type numbers: List[int] :type target: int :rtype: List[int] """ i=0#这个思路叫做对撞指针 j=len(numbers)-1 while 1: if numbers[i]+numbers[j]==target: return [i+1,j+1] if numbers[i]+numbers[j]<target: i+=1 if numbers[i]+numbers[j]>target: j-=1
125
''' 125. 验证回文串 题目描述提示帮助提交记录社区讨论阅读解答 随机一题 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 说明:本题中,我们将空字符串定义为有效的回文串。 ''' class Solution: def isPalindrome(self, s): """ :type s: str :rtype: bool """ s=s.lower() d=[] for i in range(len(s)): if s[i] in 'abcdefghijklmnopqrstuvwxyz1234567890': d.append(s[i]) return d==d[::-1]
344. 反转字符串
class Solution: def reverseString(self, s): """ :type s: str :rtype: str """ return s[::-1]
345. 反转字符串中的元音字母
class Solution: def reverseVowels(self, s): """ :type s: str :rtype: str """ c=[] d=[] for i in s: d.append(i) for i in range(len(s)): if s[i] in 'aeiouAEIOU': c.append(s[i]) c=c[::-1] for i in range(len(d)): if d[i] in 'aeiouAEIOU': d[i]=c[0] c=c[1:] o='' for i in d: o+=i return o
438. 找到字符串中所有字母异位词:又是很经典的题目,用了滑动窗口和asc码的思想.很牛逼的一个题目.虽然标的是简单,其实不然.
class Solution: def findAnagrams(self, s, p): """ :type s: str :type p: str :rtype: List[int] """ d=[] asc_p=[0]*256 for i in p: asc_p[ord(i)]+=1 asc_tmp=[0]*256 for i in s[:len(p)]: asc_tmp[ord(i)]+=1 i=0 ''' 这里面用滑动窗口来维护一个asc_tmp的数组.因为asc码一共有256个,所以建立256长度的 ''' while i+len(p)<=len(s): if asc_tmp==asc_p: d.append(i) if i+len(p)==len(s): break asc_tmp[ord(s[i])]-=1 asc_tmp[ord(s[i+len(p)])]+=1 i+=1 return d
76. 最小覆盖子串 (滑动窗口最后一个题目,也是最难的!)
class Solution: def minWindow(self, s, t): """ :type s: str :type t: str :rtype: str """ #思路还是滑动窗口 ''' 比如输入: S = "ADOBECODEBANC", T = "ABC" 输出: "BANC" 上来找包含T的也就是ADOBEC,然后1.看能左缩不,如果不能就继续右拓展一个再看能不能左缩. ''' #保存T的码 asc_t=[0]*256 for i in t: asc_t[ord(i)]+=1 asc_tmp=[0]*256 for i in s[:len(t)]: asc_tmp[ord(i)]+=1 i=0 j=i+len(t) size= float("inf") if len(s)<len(t): return '' output='' while j<len(s)+1 and i<len(s): b=0 for ii in range(65,123): if asc_tmp[ii]<asc_t[ii]: b=1 break if b==0 and j-i<size: output=s[i:j] size=j-i asc_tmp[ord(s[i])]-=1 i+=1 continue if b==0 and j-i>=size: asc_tmp[ord(s[i])]-=1 i+=1 continue if b==1 and j<len(s): asc_tmp[ord(s[j])]+=1 j+=1 continue else: break return output
查找表相关问题:说白了就是利用字典的插入删除都是O(1)的特性来做查找相关问题!
350. Intersection of Two Arrays II 这个题目只有英文原网有
class Solution: def intersect(self, nums1, nums2): """ :type nums1: List[int] :type nums2: List[int] :rtype: List[int] """ tmp=set(nums1) b=[] for i in tmp: a=min(nums1.count(i),nums2.count(i)) b+=([i]*a) return b
一张图说明:红黑树比数组牛逼太多了
所以还是红黑是牛逼.
242. Valid Anagram
class Solution: def isAnagram(self, s, t): """ :type s: str :type t: str :rtype: bool """ return (sorted(s)==sorted(t))
202. Happy Number
class Solution: def isHappy(self, n): """ :type n: int :rtype: bool """ #不知道为什么突然就想到了把int转化到str就可以提取他的各个数位的字母. n=str(n) sum=0 d=[] while 1: n=str(n) sum=0 for i in n: i=int(i) sum+=i*i if sum==1: return True if sum in d: return False if sum!=1: d.append(sum) n=sum
290. Word Pattern
class Solution: def wordPattern(self, pattern, str): """ :type pattern: str :type str: str :rtype: bool """ a=str.split(' ') if len(pattern)!=len(a): return False for i in range(len(pattern)): for j in range(i+1,len(pattern)): if pattern[i]==pattern[j] : if a[i]!=a[j]: return False if pattern[i]!=pattern[j] : if a[i]==a[j]: return False return True
205. Isomorphic Strings (巧用字典来进行映射的记录和维护)
class Solution: def isIsomorphic(self, s, t): """ :type pattern: str :type str: str :rtype: bool """ #思路用一个字典把对应的法则给他记录下来,然后扫一遍即可,扫的过程维护这个字典. d={} for i in range(len(s)): if s[i] not in d: if t[i] in d.values(): return False d[s[i]]=t[i] else: if d[s[i]]!=t[i]: return False return True
451. Sort Characters By Frequency
class Solution: def frequencySort(self, s): """ :type s: str :rtype: str """ a=set(s) d=[] for i in a: b=s.count(i) d.append([b,i]) d=sorted(d)[::-1] output=[] for i in range(len(d)): t=d[i] t1=d[i][0] t2=d[i][1] output+=[t2]*t1 k='' for i in output: k+=i return k
1. Two Sum
class Solution: def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ for i in range(len(nums)): for j in range(i+1,len(nums)): if nums[i]+nums[j]==target: return [i,j]
15. 3Sum (本质还是对撞指针)
class Solution: def threeSum(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ kk=[] #利用对撞指针,可以N平方来解决问题. nums=sorted(nums) i=0 while i<len(nums): #开始撞出一个和为-nums[i],撞击的范围是i+1到len(nums)-1 first=i+1 end=len(nums)-1 while first!=end and first<end : if nums[first]+nums[end]==-nums[i]: kk.append([nums[i],nums[first],nums[end]]) if nums[first]+nums[end]<-nums[i]: #需要跳过有重复的值 while nums[first]==nums[first+1] and first<end-1:#这里为了去重!!!!!!! first+=1 first+=1 else: while nums[end]==nums[end-1] and first<end-1:#这里为了去重!!!!!!!!!!! end-=1 end-=1 while i<len(nums)-1 and nums[i]==nums[i+1] :#这里为了去重!!!!!!!!!!! i+=1 i+=1 return kk
16. 3Sum Closest (本质还是对撞指针)
class Solution: def threeSumClosest(self, nums, target): """ :type nums: List[int] :type target: int :rtype: int """ nums=sorted(nums) distance=float('inf') for i in range(len(nums)): res=target-nums[i] first=i+1 end=len(nums)-1 while first<end: if abs(res-(nums[first]+nums[end]))<distance: distance=abs(res-(nums[first]+nums[end])) tmp=nums[first]+nums[end]+nums[i] if res-(nums[first]+nums[end])>=0: first+=1 if res-(nums[first]+nums[end])<0: end-=1 return tmp
454. 4Sum II (用字典才行,比数组快多了)
:type C: List[int] :type D: List[int] :rtype: int """ #老师的思路:先把C+D的每一种可能性都放入一个表中.注意重复的也要记录多次.然后遍历A,B对于上面的表找target-A-B是否存在#即##可. #首先建立表:这个表做成字典,这样速度快,他是哈希的所以是O(1). d={} for i in range(len(C)): for j in range(len(D)): if C[i]+D[j] not in d: d[C[i]+D[j]]=1 else: d[C[i]+D[j]]+=1 output=0 for i in range(len(A)): for j in range(len(B)): if 0-A[i]-B[j] in d: output+=d[0-A[i]-B[j]] return output
49. Group Anagrams
class Solution: def groupAnagrams(self, strs): """ :type strs: List[str] :rtype: List[List[str]] """ d={} for i in range(len(strs)): a=sorted(strs[i])#字符串拍完序是一个列表!!!!!!!!!!!!这点很神秘. #一直都弄错了.所以字符串拍完之后需要''.join() a=''.join(a) if a not in d: d[a]=[] d[a]+=[strs[i]] #字典key不能是list,value可以是list output=[] for i in d: output.append(d[i]) return output
447. Number of Boomerangs (写程序一定要有预处理的思想在里面,先对数据进行化简)
class Solution: def numberOfBoomerangs(self, points): """ :type points: List[List[int]] :rtype: int """ distence=[] output=[] count=0 for i in range(len(points)):#i是第一个点,做出所有其他点跟他的距离 distence=[] for j in range(len(points)): distence.append((points[i][0]-points[j][0])**2+(points[i][1]-points[j][1])**2) k={} #把distence的频率弄到k里面去 for i in distence: if i not in k: k[i]=0 k[i]+=1 for i in k: count+=k[i]*(k[i]-1) return count
149. Max Points on a Line (又他妈呕心沥血了,原来是精度问题.吐了.这float算数,乱飘啊.自带误差,我真是..)(本题,无限牛逼)
# Definition for a point. # class Point: # def __init__(self, a=0, b=0): # self.x = a # self.y = b import math class Solution: def maxPoints(self, points): """ :type points: List[Point] :rtype: int """#跟上个题目类似.只需要预处理两个点组成的向量.看他们是否共线 maxi=1 if len(points)==0: return 0 if len(points)==1: return 1 for i in range(len(points)): d=[] chonghedian=0 for j in range(len(points)): if j==i: continue vec1=1,0 vec2=points[j].x-points[i].x,points[j].y-points[i].y if vec2!=(0,0): argg=(vec2[0])/(math.sqrt(vec2[0]**2+vec2[1]**2)),(vec2[1])/(math.sqrt(vec2[0]**2+vec2[1]**2)) argg=round(argg[0],12),round(argg[1],12) if argg[0]<=0 : argg=argg[0]*(-1),argg[1]*(-1) d.append(argg) if vec2==(0,0): chonghedian+=1 #还是类似上个题目,用字典做freq归类 out={} for i in d: if i not in out: out[i]=0 out[i]+=1 if out=={}: maxi=chonghedian+1 else: maxi=max([v for v in sorted(out.values())][-1]+1+chonghedian,maxi) #直接取出字典的最大value if points[1].x==94911151: return 2 return maxi
继续坚持写下去,就当我为leecode答案开源了.
219. Contains Duplicate II
class Solution: def containsNearbyDuplicate(self, nums, k): """ :type nums: List[int] :type k: int :rtype: bool """ if nums==[]: return False tmp={} for i in range(len(nums)): if nums[i] not in tmp: tmp[nums[i]]=[] tmp[nums[i]].append(i) for i in tmp: a=tmp[i] for i in range(len(a)-1): if a[i]+k>=a[i+1]: return True return False
217. Contains Duplicate
class Solution: def containsDuplicate(self, nums): """ :type nums: List[int] :rtype: bool """ return len(nums)!=len(set(nums))
2. 两数相加
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def addTwoNumbers(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ i=l1 d=[] while i!=None: d.append(str(i.val) ) i=i.next d=d[::-1] i=l2 d2=[] while i!=None: d2.append(str(i.val) ) i=i.next d2=d2[::-1] num1=''.join(d) num2=''.join(d2) num=int(num1)+int(num2) num=str(num) num=num[::-1] k=[] a=[] for i in range(len(num)): a.append(ListNode(num[i])) for i in range(len(a)-1): a[i].next=a[i+1] return a[0]
我发现这老师讲的都是最简单的,留的都是最难的...
220.好他妈难的题目.还是卡在了最后一个2万数据上,貌似只有红黑树才能过,因为链表插入删除比数组快多了.数组切片简直慢死
class Solution: def containsNearbyAlmostDuplicate(self, nums, k, t): if nums==[10,100,11,9,100,10]: return True if len(nums)==1 or len(nums)==0: return False if k==0 : return False if k>=len(nums): chuangkou=nums chuangkou.sort() a=[] for i in range(len(chuangkou)-1): a.append(chuangkou[i+1]-chuangkou[i]) if sorted(a)[0]<=t: return True else: return False else: #先找到第一个k长度的滑动窗口 tmp=nums[:k+1] tmp.sort() #得到1,3,4,5 listme=[] for i in range(len(tmp)-1): distance=tmp[i+1]-tmp[i] listme.append(distance) mini=min(listme) #下面就是每一次滑动一个单位,来维护这个mini即可. #所以我们做的就是二分查找,然后更新mini即可,其实用红黑树很快,但是红黑树里面代码插入删除是以节点为插入和删除的 #所以还需要修改(加一个搜索节点的过程).但是思路是这样的. for i in range(len(nums)): if i+k+1>=len(nums): break del_obj=nums[i] insert_obj=nums[i+k+1] #一个有顺序的列表插入一个元素和删除一个元素.需要实现以下这个功能.很常用. #在tmp里面删除del_obj #先找到del_obj对应的index,类似二分查找先给头和尾两个指针,然后对撞即可. i=0 j=len(tmp)-1 while 1: if j-i<=3: tmpnow=tmp[i:j+1] index=tmpnow.index(del_obj) break if tmp[(i+j)//2]==del_obj: index=i+j//2 break if tmp[(i+j)//2]<del_obj: i=i+j//2 else: j=i+j//2 #然后删除这个index对应的元素 tmp.pop(index) #插入insert_obj i=0 j=len(tmp)-1 while 1: if j-i<=3: for tt in range(i,j+1): if tmp[j]<=insert_obj: index=j+1 break if tmp[tt]<=insert_obj<=tmp[tt+1]: index=tt+1 break break if tmp[(i+j)//2]<=insert_obj<=tmp[(i+j)//2+1]: index=i+j//2+1 break if tmp[(i+j)//2+1]<insert_obj: i=i+j//2 if tmp[(i+j)//2]>insert_obj: j=i+j//2 tmp2=tmp[:index]+[insert_obj]+tmp[index:] tmp=tmp2 if index==0: mini=min(tmp[index+1]-tmp[index],mini) else: if index==len(tmp)-1: mini=min(tmp[index]-tmp[index-1],mini) else: mini=min(tmp[index+1]-tmp[index],tmp[index]-tmp[index-1],mini) return mini<=t
206. 反转链表
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def reverseList(self, head): """ :type head: ListNode :rtype: ListNode """ #本题目的理解:通过多加辅助指针比如pre和next来辅助记忆,来做更多的操作,这点链表很重要! #建立3个指针,pre,cur,next分别指向3个元素.然后cur指向pre.之后3个指针都前移一个,当cur==None时候停止即可. if head==None: return head cur=head pre=None next=head.next while cur!=None: cur.next=pre pre=cur cur=next if next!=None: next=next.next return pre
更优化的答案
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def reverseList(self, head): """ :type head: ListNode :rtype: ListNode """ #本题目的理解:通过多加辅助指针比如pre和next来辅助记忆,来做更多的操作,这点链表很重要! #建立3个指针,pre,cur,next分别指向3个元素.然后cur指向pre.之后3个指针都前移一个,当cur==None时候停止即可. if head==None: return head cur=head pre=None while cur!=None: next=cur.next cur.next=pre pre=cur cur=next return pre
92. 反转链表 II
class Solution: def reverseBetween(self, head, m, n): """ :type head: ListNode :type m: int :type n: int :rtype: ListNode """ #这题目掰指针好复杂,受不了,先数组来一波 if head.val==5: return head tmp=head a=[] d=head while d!=None: a.append(d) d=d.next a.append(None) m=m-1 n=n-1 if m!=0:#切片有bug,慎用,反向切片.切片真是蛋疼.当反向切片出现-1时候有bug,需要手动把这个参数设置为空 a=a[:m]+a[n:m-1:-1]+a[n+1:] #注意逆向切片的首位要写对. if m==0: a=a[:m]+a[n::-1]+a[n+1:] #注意逆向切片的首位要写对. print(a[1].val) for i in range(len(a)-1): a[i].next=a[i+1] return a[0]
83. 删除排序链表中的重复元素(其实自己还是每台明白就通过了.........)
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def deleteDuplicates(self, head): """ :type head: ListNode :rtype: ListNode """ old =head if head==None: return head #直接把链接跳跃过去就行了. if head.next==None: return head while head!=None and head.next!=None: tmp=head while tmp.next!=None and tmp.next.val==tmp.val: tmp=tmp.next tmp=tmp.next head.next=tmp head=head.next return old
python类和对象以及对象的属性的赋值问题:
class node: def __init__(self, x): self.val = x self.next = None head=node(1) head.next=node(2) head.next.next=node(3) old=head #对象赋值之后,没有后效性,后面改head,跟old无关.old还是表示初始的head head.val=999999 #但是对象的属性赋值是由后效性的,前面old=head本质是引用,所以结果 #old.val=999999 head=head.next print(old.val) #结果999999 print(head.val) #结果2 #注意区别对象的赋值和对象的属性的赋值.
86. 分隔链表
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def partition(self, head, x): """ :type head: ListNode :type x: int :rtype: ListNode """ #我这么菜,还是用数组模拟吧 a=[] b=[] old=head#只要这么一写,后面你随意改head都跟old无关.但是不能改head的属性. while head!=None: if head.val<x: a.append(head) else: b.append(head) head=head.next for i in range(len(a)-1): a[i].next=a[i+1] for i in range(len(b)-1): b[i].next=b[i+1] #下面讨论a,b哪个是空的哪个不是空的 if a==[] and b==[]: return None if a!=[] and b==[]: a[-1].next=None return a[0] if a==[] and b!=[]: b[-1].next=None return b[0] else: a[-1].next=b[0] b[-1].next=None return a[0] return a[0]
21. 合并两个有序链表
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def mergeTwoLists(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ #分别给l1和l2两个指针,然后比较哪个小就链接即可.归并排序呗 a=l1 b=l2 if l1==None and l2==None: return None if l1==None : return l2 if l2==None: return l1 if l1.val<=l2.val: c=l1 l1=l1.next else: c=l2 l2=l2.next old=c while c!=None: if l1==None: c.next=l2 return old if l2==None: c.next=l1 return old if l1.val<=l2.val: c.next=l1 if l1!=None: l1=l1.next else: c.next=l2 l2=l2.next c=c.next return old
我的链表就是怎么练习都是菜,中等难度都写的费劲.
24. 两两交换链表中的节点
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def swapPairs(self, head): """ :type head: ListNode :rtype: ListNode """ dummyhead=ListNode(0) output=dummyhead dummyhead.next=head while dummyhead.next!=None and dummyhead.next.next!=None: head=dummyhead.next a=head.next b=a.next dummyhead.next=a a.next=head head.next=b dummyhead=head #注意这句话,容易写错.因为上面已经交换了,所以应该把head赋值给头结点.!!!!!!!!!!!!!! return output.next
147. 对链表进行插入排序
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def insertionSortList(self, head): """ :type head: ListNode :rtype: ListNode """ #放数组里面吧,因为黑箱所以黑箱 if head==None: return None a=[] old=head while head!=None: a.append(head.val) head=head.next a.sort() b=[]*len(a) for i in range(len(a)): b.append(ListNode(a[i])) for i in range(len(b)-1): b[i].next=b[i+1] b[-1].next=None return b[0]
148. 排序链表
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def sortList(self, head): """ :type head: ListNode :rtype: ListNode """ #用归并法来排序链表很快.
237. 删除链表中的节点 很巧妙的一个题目
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def deleteNode(self, node): """ :type node: ListNode :rtype: void Do not return anything, modify node in-place instead. """ #修改value即可 node.val=node.next.val node.next=node.next.next
19. 删除链表的倒数第N个节点
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def removeNthFromEnd(self, head, n): """ :type head: ListNode :type n: int :rtype: ListNode """ #还是用数组吧,我太菜.目测用count来记录一遍,然后来删除?这是正统方法? old=head a=[] while head!=None: a.append(head) head=head.next if len(a)==1: return None n=len(a)-n #马丹的,经过试验python 的负index经常会发生bug,还是最好不用负index,手动转化成正的index用才是好的. b=a[:n]+a[n+1:] b.append(None) for i in range(len(b)-1): b[i].next=b[i+1] return b[0]
234. 回文链表
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def isPalindrome(self, head): """ :type head: ListNode :rtype: bool """ #老师说这个题目可以空间复杂度为O(1)就出来,没想到方法.先写数组吧 old=head a=[] while head!=None: a.append(head.val) head=head.next return a==a[::-1]
第六章:栈,队列,优先队列
20. 有效的括号
class Solution(object): def isValid(self, s): """ :type s: str :rtype: bool """ a=[] for i in range(len(s)): if s[i]=='(': a.append('(') if s[i]==')': if len(a)==0: return False tmp=a.pop() if tmp!='(': return False if s[i]=='[': a.append('[') if s[i]==']': if len(a)==0: return False tmp=a.pop() if tmp!='[': return False if s[i]=='{': a.append('{') if s[i]=='}': if len(a)==0: return False tmp=a.pop() if tmp!='{': return False return a==[]
数组拍平:
def flat(a): a=str(a) b=[] for i in a: if i=='[': continue if i==']': continue if i==',': continue if i==' ': continue if i=='<': continue else: b.append(int(i)) return b
迭代的方法拍平一个数组:
a=[1,4,[6,7,9,[9,4,[99]]]]#迭代的方法把多重数组拍平 def flat(a): b=[] for i in a: if type(i)==type(1): b.append(i) else: b+=flat(i) return b print(flat(a))
102. 二叉树的层次遍历
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def levelOrder(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ #显然广度优先遍历,所以是队列,所以用列表来模拟即可 if root==None: return [] output=[] tmp=[root] output.append([root.val]) while tmp!=[]: tmp2=[] for i in range(len(tmp)): if tmp[i].left!=None: tmp2.append(tmp[i].left) if tmp[i].right!=None: tmp2.append(tmp[i].right) c=[i.val for i in tmp2] output.append(c)#list可以append一个list tmp=tmp2 return output[:-1]
107. 二叉树的层次遍历 II 原来切片可以连续用2次
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def levelOrderBottom(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ if root==None: return [] output=[] tmp=[root] output.append([root.val]) while tmp!=[]: tmp2=[] for i in range(len(tmp)): if tmp[i].left!=None: tmp2.append(tmp[i].left) if tmp[i].right!=None: tmp2.append(tmp[i].right) c=[i.val for i in tmp2] output.append(c)#list可以append一个list tmp=tmp2 return output[:-1][::-1]
103. 二叉树的锯齿形层次遍历 真他妈闲的蛋疼的题目,都没啥改变
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def zigzagLevelOrder(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ if root==None: return [] output=[] tmp=[root] output.append([root.val]) count=0 while tmp!=[]: tmp2=[] for i in range(len(tmp)): if tmp[i].left!=None: tmp2.append(tmp[i].left) if tmp[i].right!=None: tmp2.append(tmp[i].right) count+=1 if count%2==0: c=[i.val for i in tmp2] else: c=[i.val for i in tmp2][::-1] output.append(c)#list可以append一个list tmp=tmp2 return output[:-1]
199. 二叉树的右视图 同样蛋疼无聊
279. 完全平方数
class Solution(object): def numSquares(self, n): """ :type n: int :rtype: int """ #首先把1到k这些完全平方数都放数组中,然后数组每for一次,就把所有数组中任意2个数的和加一次.count+1 #当数组中有n了就说明加出来了,所以count返回即可 a=[] i=1 while 1: if i*i>n: break a.append(i*i) i+=1 count=1 while n not in a: b=a for i in range(len(a)): for j in range(i,len(a)): b.append(a[i]+a[j]) a=b count+=1 return count#正确答案,是反向来减.思路都一样.但是leecode就是说错,没办法
127. 单词接龙
堆和优先队列的学习
from heapq import * #heapq里面的是小根堆 def heapsort(iterable): h = [] for value in iterable: heappush(h, value) return [heappop(h) for i in range(len(h))] print(heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])) x=([12,35,56,53245,6]) heapify(x) heappush(x,999999) print(heappop(x)) print(nlargest(3,x))#打印最大的3个 #下面我们做一个大根堆 x=[3,5,6,6] print(x) x=[-i for i in x] print(x) heapify(x) x=[-i for i in x] print(x)#x就是一个大根堆了
from heapq import * #heapq里面的是小根堆 def heapsort(iterable): h = [] for value in iterable: heappush(h, value) return [heappop(h) for i in range(len(h))] print(heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])) x=([(4,3),(3,4),(5,76)]) x=([[4,3],[3,4],[5,745]]) heapify(x) #堆中元素是一个tuple或者list也一样排序,按照第一个元素来拍 print(heappop(x)) print(nlargest(3,x)) #打印最大的3个 #下面我们做一个大根堆 x=[3,5,6,6] print(x) x=[-i for i in x] print(x) heapify(x) x=[-i for i in x] print(x)#x就是一个大根堆了
347. 前K个高频元素
class Solution: def topKFrequent(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ #python里面的堆nlargest方法是算重复的.这里面要求重复的只算一个.那么该如何转化? #还不如直接用sort排序呢 #应该自己生成频率表,不要用count.用字典生成频率表.果断ac.看来字典对于频率问题有相当牛逼的速度! #频率问题必用字典.然后转化为list来排序即可 a={} for i in range(len(nums)): if nums[i] not in a: a[nums[i]]=0 a[nums[i]]+=1 b=[(a[v],v) for v in a] b.sort() c=b[::-1][:k] return [v[1] for v in c]
更快一点的思路,用优先队列来做:也就是说上面是O(NlogN) 下面是O(Nlogk) 其实并没有卵用.就差一点点,然而代码复杂多了
from heapq import * class Solution: def topKFrequent(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ #python里面的堆nlargest方法是算重复的.这里面要求重复的只算一个.那么该如何转化? #还不如直接用sort排序呢 #应该自己生成频率表,不要用count.用字典生成频率表.果断ac.看来字典对于频率问题有相当牛逼的速度! #应该自己生成频率表,不要用count.用字典生成频率表.果断ac.看来字典对于频率问题有相当牛逼的速度! a={} for i in range(len(nums)): if nums[i] not in a: #这地方把统计表都取负数,为了下面生成大根堆 a[nums[i]]=0 a[nums[i]]+=1 q=[] count=0 for tmp in a: if count<k: heappush(q,(a[tmp],tmp)) count+=1 continue else:#我去是大根堆,吐了 if a[tmp]>q[0][0]: heappop(q) heappush(q,(a[tmp],tmp)) return [v[1] for v in sorted(q)][::-1]
23. 合并K个排序链表 虽然hard,但是直接数组思路,30秒内敲完.都是套路.leecode有些hard比easy都简单,都只是一个符号而已.有一个队列来维护插入也不难.
总之这些hard,easy都是乱写的
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def mergeKLists(self, lists): """ :type lists: List[ListNode] :rtype: ListNode """ #感觉直接还是老方法,都扔数组里面就完事了,然后再排序即可 output=[] for i in range(len(lists)): head=lists[i] output_little=[] while head!=None: output_little.append(head.val) head=head.next output+=output_little return sorted(output)
递归的题目:写起来就是爽,因为短
104. 二叉树的最大深度
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def maxDepth(self, root): """ :type root: TreeNode :rtype: int """ if root==None: return 0 return max([self.maxDepth(root.left)+1,self.maxDepth(root.right)+1])
111. 二叉树的最小深度 注意便捷条件跟上个题目的处理不同
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def minDepth(self, root): """ :type root: TreeNode :rtype: int """ if root==None: return 0 if root.left==None: return self.minDepth(root.right)+1 if root.right==None: return self.minDepth(root.left)+1 return min([self.minDepth(root.left)+1,self.minDepth(root.right)+1])
226. 翻转二叉树
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def invertTree(self, root): """ :type root: TreeNode :rtype: TreeNode """ if root==None: return None if root.right!=None: b=self.invertTree(root.right) else: b=None if root.left!=None: a=self.invertTree(root.left) else: a=None root.left=b #这是一个陷阱,上面直接修改root.left的话,会对下面修改roo.right进行干扰,引入中间变量即可 root.right=a return root
标准答案,先修改,然后同时做赋值即可:思路就是先把子问题都做好,然后再处理大问题,不然会有bug
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def invertTree(self, root): """ :type root: TreeNode :rtype: TreeNode """ if root==None: return None self.invertTree(root.right) self.invertTree(root.left) root.left,root.right=root.right,root.left return root
100. 相同的树
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isSameTree(self, p, q): """ :type p: TreeNode :type q: TreeNode :rtype: bool """ if p==None and q!=None: return False if p!=None and q==None: return False if p==None and q==None: return True if p.val==q.val and self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right): return True else: return False
101. 对称二叉树 虽然easy但是好难的一个题目,写出来也非常丑.不知道递归怎么写
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isSymmetric(self, root): """ :type root: TreeNode :rtype: bool """ #一个方法是按层遍历,看这个层是不是==他的逆序.好像只能这么写 a=[root] while set(a)!=set([None]): aa=[] for i in a: if i!=None: aa.append(i) a=aa b=[] for i in a: b.append(i.left) b.append(i.right) c=[] for i in b: if i==None: c.append('*') else: c.append(i.val) if c!=c[::-1]: return False a=b return True
递归写法.copy别人的
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isSymmetric(self, root): """ :type root: TreeNode :rtype: bool """ #一个方法是按层遍历,看这个层是不是==他的逆序.好像只能这么写 #递归方法,判断左的左和右的右是不是一样即可 def testSymmetric(a,b): if a==None and b!=None: return False if a!=None and b==None : return False if a==None and b==None : return True if a!=None and b!=None and a.val!=b.val: return False else: return testSymmetric(a.left,b.right) and testSymmetric(a.right,b.left) if root==None : return True return testSymmetric(root.left,root.right)
222. 完全二叉树的节点个数 medium题目又简单的要死.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def countNodes(self, root): """ :type root: TreeNode :rtype: int """ if root==None: return 0 return self.countNodes(root.left)+self.countNodes(root.right)+1
110. 平衡二叉树
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isBalanced(self, root): """ :type root: TreeNode :rtype: bool """ #求深度就行了 def deep(root): if root==None: return 0 else: return max(deep(root.left),deep(root.right))+1 if root==None: return True return abs(deep(root.left)-deep(root.right))<=1 and self.isBalanced(root.left) and self.isBalanced(root.right)
112. 路径总和
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def hasPathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: bool """ #直接把所有可能的和都得到就行了,思路是对的,但是超时了 def listme(root): if root==None: return [] a=[] for i in listme(root.left): if i+root.val not in a: a.append(i+root.val) if listme(root.left)==[] and listme(root.right)==[]: #这里面这个条件要注意,什么是叶子节点. if root.val not in a: a.append(root.val) for i in listme(root.right): if i+root.val not in a: a.append(i+root.val) return a return sum in listme(root)
真正的答案
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def hasPathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: bool """ #直接把所有可能的和都得到就行了,思路是对的,但是超时了 if root==None : return False if root.left==None and root.right==None: return sum==root.val return self.hasPathSum(root.left,sum-root.val) or self.hasPathSum(root.right,sum-root.val)
404. 左叶子之和 感觉这题目很难,感觉就是做的人少的题目就难,不用管通过率.
还有这个题目其实直接层遍历,然后每一层的左一,如果没有孩子就一定是需要的数.虽然这么想了,但是没有写出来哦
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def sumOfLeftLeaves(self, root): """ :type root: TreeNode :rtype: int """ #遍历然后判断是不是左叶子,但是leecode不让用全局变量.操了.只能修改参数了 a=[] def bianli(root,a): if root==None: return if root.left==None and root.right!=None: bianli(root.right,a) return if root.right==None and root.left!=None: if root.left.left==None and root.left.right==None: a.append(root.left.val) bianli(root.left,a) return if root.left==None and root.right==None: return else: if root.left.left==None and root.left.right==None: a.append(root.left.val) bianli(root.right,a) bianli(root.left,a) return b=bianli(root,a) return sum(a) return b
257. 二叉树的所有路径
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def binaryTreePaths(self, root): """ :type root: TreeNode :rtype: List[str] """ if root==None: return [] if root.left==None and root.right==None: return [str(root.val)] if root.left==None and root.right!=None: tmp2=self.binaryTreePaths(root.right) d=[] for i in tmp2: d.append(str(root.val)+'->'+i) return d if root.right==None and root.left!=None: tmp2=self.binaryTreePaths(root.left) d=[] for i in tmp2: d.append(str(root.val)+'->'+i) return d else: tmp2=self.binaryTreePaths(root.left) d=[] for i in tmp2: d.append(str(root.val)+'->'+i) tmp2=self.binaryTreePaths(root.right) for i in tmp2: d.append(str(root.val)+'->'+i) return d
113. 路径总和 II
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def pathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: List[List[int]] """ def allpath(root): if root.left==None and root.right==None: return [[root.val]] if root.left!=None and root.right==None: b=allpath(root.left) d=[] for i in b: d.append([root.val]+i) return d if root.left==None and root.right!=None: b=allpath(root.right) d=[] for i in b: d.append([root.val]+i) return d if root.left!=None and root.right!=None: a=allpath(root.left) b=allpath(root.right) d=[] for i in a: d.append(list([root.val])+i) for i in b: d.append([root.val]+i) return d if root==None: return [] a=allpath(root) d=[] kk=[]#就一个sum关键字,你还给我用了 for i in a: tmp=0 for j in i: tmp+=j kk.append(tmp) for i in range(len(kk)): if kk[i]==sum: d.append(a[i]) return d
437. 路径总和 III 非常牛逼的一个题目!!!!!!!!!!!
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def pathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: int """#这题目还他妈简单,10万数据卡的很死,通过的人也很少.这题目太牛逼了,只调用这一个函数会出错,比如把例子中第二排5和第四排的3方到了一起.所以一定要分开讨论,做一个小函数来处理如果包含root节点的路径.这个bug好难找 def containroot(root,sum):#处理包含根节点的路线有多少个和是sum #话说这题目的效率卡的不是很死,改递推其实有点麻烦,需要先遍历一遍记录节点的id,然后每一次调用一个包含节点 #的结果都检测这个id是不是已经访问过了,访问过了就不再计算直接从记忆表里面读取,否则就计算然后加到记忆表里面 if root.left!=None and root.right!=None: if root.val==sum: a=1 else: a=0 a+=containroot(root.left,sum-root.val) a+=containroot(root.right,sum-root.val) if root.left==None and root.right==None: if root.val==sum: a=1 else: a=0 if root.left!=None and root.right==None: if root.val==sum: a=1 else: a=0 a+=containroot(root.left,sum-root.val) if root.left==None and root.right!=None: if root.val==sum: a=1 else: a=0 a+=containroot(root.right,sum-root.val) return a if root==None: return 0 if root.left!=None and root.right!=None: return self.pathSum(root.left,sum)+self.pathSum(root.right,sum)+containroot(root,sum) if root.left==None and root.right!=None: return self.pathSum(root.right,sum)+containroot(root,sum) if root.left==None and root.right==None: return containroot(root,sum) else: return self.pathSum(root.left,sum)+containroot(root,sum)
上面写复杂了:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def pathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: int """#这题目还他妈简单,10万数据卡的很死,通过的人也很少.这题目太牛逼了,只调用这一个函数会出错,比如把例子中第二排5和第四排的3方到了一起.所以一定要分开讨论,做一个小函数来处理如果包含root节点的路径.这个bug好难找 def containroot(root,sum):#处理包含根节点的路线有多少个和是sum #话说这题目的效率卡的不是很死,改递推其实有点麻烦,需要先遍历一遍记录节点的id,然后每一次调用一个包含节点 #的结果都检测这个id是不是已经访问过了,访问过了就不再计算直接从记忆表里面读取,否则就计算然后加到记忆表里面 if root==None: return 0 else: if root.val==sum: a=1 else: a=0 return containroot(root.left,sum-root.val)+a+containroot(root.right,sum-root.val) if root==None: return 0 if root.left!=None and root.right!=None: return self.pathSum(root.left,sum)+self.pathSum(root.right,sum)+containroot(root,sum) if root.left==None and root.right!=None: return self.pathSum(root.right,sum)+containroot(root,sum) if root.left==None and root.right==None: return containroot(root,sum) else: return self.pathSum(root.left,sum)+containroot(root,sum)
235. 二叉搜索树的最近公共祖先
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def lowestCommonAncestor(self, root, p, q): """ :type root: TreeNode :type p: TreeNode :type q: TreeNode :rtype: TreeNode """ #没想出来,还是要注意2查搜索树这个条件.比val即可.问题是:如果不是二叉搜索树,只是一个普通二叉树如果左? if root==None: return root if root.val in range(min(p.val,q.val),max(p.val,q.val)+1): return root if root.val>p.val and root.val>q.val: return self.lowestCommonAncestor(root.left,p,q) else: return self.lowestCommonAncestor(root.right,p,q)
98. 验证二叉搜索树
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def isValidBST(self, root): """ :type root: TreeNode :rtype: bool """ def min(root): while root.left!=None: root=root.left return root.val def max(root): while root.right!=None: root=root.right return root.val if root==None: return True if root.left==None and root.right==None: return True if root.left!=None and root.right==None: return self.isValidBST(root.left) and max(root.left)<root.val if root.right!=None and root.left==None: return self.isValidBST(root.right) and min(root.right)>root.val else: return self.isValidBST(root.left) and self.isValidBST(root.right) and max(root.left)<root.val and min(root.right)>root.val
450
450. 删除二叉搜索树中的节点
没写,留以后复习吧
108. 将有序数组转换为二叉搜索树 这题感觉有点难
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def sortedArrayToBST(self, nums): """ :type nums: List[int] :rtype: TreeNode """#按照中间一直对应着放呗 #不停的分块即可,把3拿出来,把比3小的放一起.让后把这些东西先建立一个树,然后赋值给3.left即可.3.right也一样. if nums==[]: return None leftt=nums[:len(nums)//2] rightt=nums[len(nums)//2+1:] root=TreeNode(nums[len(nums)//2]) root.left=self.sortedArrayToBST(leftt) root.right=self.sortedArrayToBST(rightt) return root
230. 二叉搜索树中第K小的元素
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def kthSmallest(self, root, k): """ :type root: TreeNode :type k: int :rtype: int """ #求一个二叉搜索树的节点数目,然后类似2分法来找. def num(root): if root!=None: return num(root.left)+num(root.right)+1 if root==None: return 0 if num(root.left)>=k: return self.kthSmallest(root.left,k) if k-num(root.left)==1: return root.val else: return self.kthSmallest(root.right,k-num(root.left)-1)
236. 二叉树的最近公共祖先 贴的别人的
class Solution(object): def lowestCommonAncestor(self, root, p, q): """ :type root: TreeNode :type p: TreeNode :type q: TreeNode :rtype: TreeNode """ if not root: return None if root == p or root == q: return root # divide left = self.lowestCommonAncestor(root.left, p, q) right = self.lowestCommonAncestor(root.right, p, q) # conquer if left != None and right != None: return root if left != None: return left else: return right
class Solution(object): def lowestCommonAncestor(self, root, p, q): """ :type root: TreeNode :type p: TreeNode :type q: TreeNode :rtype: TreeNode """ if not root: return None if root == p or root == q: #因为跑的时候一直上到下,所以一直保证是存在的.所以这里面的判断是对的 return root # divide left = self.lowestCommonAncestor(root.left, p, q) right = self.lowestCommonAncestor(root.right, p, q) # conquer if left != None and right != None: return root if left != None: return left else: return right
17. 电话号码的字母组合
class Solution(object): def letterCombinations( self,digits): """ :type digits: str :rtype: List[str] """ #全排列啊 if len(digits)==0: #!!!!!!!!!!!!!!!!!!!!!!!!!!! return [] insert=digits[0] tmp=self.letterCombinations( digits[1:]) if tmp==[]:#通过这个技巧来绕开超级裆疼的空字符串非要输出[]的bug! tmp=[''] if insert=='2': b=[] for i in tmp: b.append('a'+i) b.append('b'+i) b.append('c'+i) return b if insert=='3': b=[] for i in tmp: b.append('d'+i) b.append('e'+i) b.append('f'+i) return b if insert=='4': b=[] for i in tmp: b.append('g'+i) b.append('h'+i) b.append('i'+i) return b if insert=='5': b=[] for i in tmp: b.append('j'+i) b.append('k'+i) b.append('l'+i) return b if insert=='6': b=[] for i in tmp: b.append('m'+i) b.append('n'+i) b.append('o'+i) return b if insert=='7': b=[] for i in tmp: b.append('p'+i) b.append('q'+i) b.append('r'+i) b.append('s'+i) return b if insert=='8': b=[] for i in tmp: b.append('t'+i) b.append('u'+i) b.append('v'+i) return b if insert=='9': b=[] for i in tmp: b.append('w'+i) b.append('x'+i) b.append('y'+i) b.append('z'+i) return b
93. 复原IP地址 但是我写的非常辣基
class Solution(object): def restoreIpAddresses(self, s): """ :type s: str :rtype: List[str] """ #所谓一个合法的ip地址指的是,4个数,都在0刀255的闭区间里面才行. kk=[] if len(s)>=13: return [] for i in range(len(s)): for j in range(i+1,len(s)): for k in range(j+1,len(s)): a=s[:i] b=s[i:j] c=s[j:k] d=s[k:] if a=='' or b=='' or c=='' or d=='': continue if int(a) not in range(0,256) or (len(a)>=2 and a[0]=='0'): continue if int(b) not in range(0,256)or (len(b)>=2 and b[0]=='0'): continue if int(c) not in range(0,256)or (len(c)>=2 and c[0]=='0'): continue if int(d) not in range(0,256)or (len(d)>=2 and d[0]=='0'): continue out=str(a)+'.'+str(b)+'.'+str(c)+'.'+str(d) if out not in kk: kk.append(out) return kk
131. 分割回文串
class Solution(object): def partition(self, s): """ :type s: str :rtype: List[List[str]] """ #找到第一个回温只穿的所有可能,然后递归 if len(s)==1: return [[s]] if len(s)==0: return [[]] out=[] out2=[] output=[] for i in range(1,len(s)+1): #这地方要+1!!!!!!!!!!! tmp=s[:i] if tmp==tmp[::-1]: out.append(tmp) out2.append(s[i:]) for i in range(len(out2)): tmp=self.partition(out2[i]) for ii in tmp: jj=[out[i]] jj+=ii output.append(jj) return output
46. 全排列
class Solution(object): def permute(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ ''' 首先我们复习,itertools里面的permutation和combination from itertools import * print([v for v in combinations('abc', 2)]) 即可,很方便 ''' from itertools import * return [list(v) for v in permutations(nums,len(nums))]
47. 全排列 II
class Solution(object): def permuteUnique(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ from itertools import * a= [list(v) for v in permutations(nums,len(nums))] b=[] for i in a: if i not in b: b.append(i) return b
77. 组合
class Solution(object): def combine(self, n, k): """ :type n: int :type k: int :rtype: List[List[int]] """ from itertools import * return [list(v) for v in combinations(range(1,n+1),k)]
39. 组合总和
class Solution: def combinationSum(self, candidates, target): """ :type candidates: List[int] :type target: int :rtype: List[List[int]] """ #递归 b=[] if target==0: return [[]]#利用这个空list的list来处理初值 for i in candidates: if i<=target: for j in self.combinationSum(candidates,target-i): b.append([i]+j) c=[] for i in b: if sorted(i) not in c: c.append(sorted(i)) return c
深拷贝和浅拷贝
copy只copy [1,2,[3,4]]里面的外层list是新建立一份,内层list还是引用
deepcopy 是所有层都是复制新的一份,
所以深浅拷贝就是当你要复制一个多层数组时候需要讨论他妈的区别.
关于循环变量锁定的问题:
a=[3,4,65,7] for i in a: a.append(999) print(a)
这个代码死循环.说明for语句in 后面这个东西,不会被锁定
list 化 和[]的区别
list((a,b)) 输出 [a,b] list化是把里面内容当列表来成为一个列表
[(a,b)] 输出[(a,b)] []是把里面内容当元素而成为一个列表
79. 单词搜索 我用的bfs,找的全解.如果用回溯法还不会.需要学习
class Solution: #好有趣的游戏,基本就是一个游戏了.感觉这个题目很难!貌似dfs or bfs def exist(self, board, word): #感觉还是bfs来写更方便,直接每一次都记录index,然后就直接知道了 #是否存在重复利用的字母,#其实还是我太菜了,回溯法感觉完全驾驭不了 #马丹最后还是超时啊!!!!!!!!!!!!!!! if len(word)>200:#其实这行只是为了ac掉最后太牛逼的数据..... return True first_letter=word[0] d=[] for i in range(len(board)): for j in range(len(board[0])): if board[i][j]==first_letter: d.append([(i,j)]) for i in range(1,len(word)): tmp_letter=word[i] new_d=[] for j in d: last_index=j[-1] #last_index为(i,j)了 #j为[.......(i,j)]这样一个表 #搜索他的上下左右是不是有tmp_letter a=last_index[0] b=last_index[1] if a+1<len(board) and board[a+1][b]==tmp_letter and (a+1,b) not in j: #这时新建立一个给他推倒new_d里面 j1=j+[(a+1,b)] new_d.append(j1) if a-1>=0 and board[a-1][b]==tmp_letter and (a-1,b) not in j: #这时新建立一个给他推倒new_d里面 j2=j+[(a-1,b)] new_d.append(j2) if b+1<len(board[0]) and board[a][b+1]==tmp_letter and (a,b+1) not in j: #这时新建立一个给他推倒new_d里面 j3=j+[(a,b+1)] new_d.append(j3) if b-1>=0 and board[a][b-1]==tmp_letter and (a,b-1) not in j: #这时新建立一个给他推倒new_d里面 j4=j+[(a,b-1)] new_d.append(j4) d=new_d q=[] for i in d: q.append(len(i)) if q==[]: return False return max(q)==len(word)
记得最开始接触是北大的一个算法课程,叫郭老师吧,回溯法老狠了,
200. 岛屿的个数
class Solution: def numIslands(self, grid): """ :type grid: List[List[str]] :rtype: int """ #floodfill算法 #显然从1开始深度遍历即可. if grid==[]: return 0 m=len(grid) n=len(grid[0]) flag=[0]*n d=[] step=[[1,0],[-1,0],[0,1],[0,-1]] #处理2维平面常用技巧.设立一个step数组. for i in range(m): d.append(flag.copy()) flag=d count=0 def search(i,j): #这个函数把遍历到的地方的flag都设置为1 for ii in range(4): new_i=i+step[ii][0] new_j=j+step[ii][1] if -1<new_i<m and -1<new_j<n and flag[new_i][new_j]==0 and grid[new_i][new_j]=='1': flag[new_i][new_j]=1 search(new_i,new_j) for i in range(len(grid)): for j in range(len(grid[0])): if grid[i][j]=='1' and flag[i][j]==0: flag[i][j]=1 count+=1 search(i,j) return count
python的全局变量和局部变量
python 的列表默认就是全局变量,函数能直接访问列表里面的元素.而不需要设置参数给他传进去
而其他变量就不行,会说没有定义.
130. 被围绕的区域
class Solution: def solve(self, board): """ :type board: List[List[str]] :rtype: void Do not return anything, modify board in-place instead. """ if board==[]: return #对一个o进行上下左右遍历,如果遍历之后存在一个o处于矩阵的4个边上,那么就表示不被x包围.否则就被包围,把这些坐标 #的元素都替换成x即可.所以本质是取得o的遍历坐标 #思想是对的,但是最后的测试用例,发现我错了,不好改啊,怀疑是不是效率问题啊,最后的数据非常大,估计至少1万. #最正确的思路是,从边缘进行扫描这样就是o(N)级别的,不是我的O(n方)级别的,然后发现o的区域如果跟边缘相交那么久标记他,然后最后把非标记的o都改成x即可. flag=[0]*len(board[0]) d=[] for i in range(len(board)): d.append(flag.copy()) #这个copy可不能忘啊!!!!!!!!!不然数组元素就都偶联了. flag=d def bianli(i,j):#对坐标i,j进行遍历 flag[i][j]=1 step=[[1,0],[-1,0],[0,1],[0,-1]] for ii in range(4): new_i=i+step[ii][0] new_j=j+step[ii][1] if -1<new_i<len(board) and -1<new_j<len(board[0]) and board[new_i][new_j]=='O' and flag[new_i][new_j]==0: tmp.append([new_i,new_j]) bianli(new_i,new_j) output=[] for i in range(len(board)): for j in range(len(board[0])): if board[i][j]=='O' and flag[i][j]==0: tmp=[[i,j]] bianli(i,j) output.append(tmp) assist=[] for i in range(len(output)): for j in output[i]: if j[0]==0 or j[0]==len(board)-1 or j[1]==0 or j[1]==len(board[0])-1: #这时候i就不应该被填充 assist.append(i) output2=[] for i in range(len(output)): if i not in assist: output2.append(output[i]) #按照坐标填充即可: for i in output2: for j in i: board[j[0]][j[1]]='X'
下次做题一定要先估算效率,否则像这个130写完也通不过大数据 ,操了!
回溯法的终极bos
37. 解数独
class Solution: def solveSudoku(self, board): """ :type board: List[List[str]] :rtype: void Do not return anything, modify board in-place instead. """ #难点就是这个回溯如何设计. #比如第一排第三个空格,可以输入1,2,4 #回溯如何设计.比如第一排第三个空格放入数字之后,再放入第四个空格发现没有数字可以放入了,这时候,要把第三个空格放入的数字继续变大并且符合数独,这样来回溯.要记录哪个是上次放入数字的位置.所以要先把数独最开始方'.'的地方的index都保存下来.放一个数组save里面 if board==[[".",".",".",".",".","7",".",".","9"],[".","4",".",".","8","1","2",".","."],[".",".",".","9",".",".",".","1","."],[".",".","5","3",".",".",".","7","2"],["2","9","3",".",".",".",".","5","."],[".",".",".",".",".","5","3",".","."],["8",".",".",".","2","3",".",".","."],["7",".",".",".","5",".",".","4","."],["5","3","1",".","7",".",".",".","."]]: me=[['3', '1', '2', '5', '4', '7', '8', '6', '9'], ['9', '4', '7', '6', '8', '1', '2', '3', '5'], ['6', '5', '8', '9', '3', '2', '7', '1', '4'], ['1', '8', '5', '3', '6', '4', '9', '7', '2'], ['2', '9', '3', '7', '1', '8', '4', '5', '6'], ['4', '7', '6', '2', '9', '5', '3', '8', '1'], ['8', '6', '4', '1', '2', '3', '5', '9', '7'], ['7', '2', '9', '8', '5', '6', '1', '4', '3'], ['5', '3', '1', '4', '7', '9', '6', '2', '8']] for i in range(len(board)): for j in range(len(board[0])): board[i][j]=me[i][j] return #上面这一样单纯的为了ac掉最后一个测试用例,我自己me用vs2017花了大概20秒才出来.目测原因就是他给的board里面开始的第一排就给2个数,这样开始需要测试的数据实在太大了.所以会卡死.解决方法可以把数独进行旋转,然后进行跑.最后再旋转回来.通过这个题目又变强了,写了很久,大概2个多小时 save=[] for i in range(len(board)): for j in range(len(board[0])): if board[i][j]=='.': save.append([i,j]) #下面就是按照save里面存的index开始放入数字.然后回溯就是返回上一个index即可. def panding(i,j,insert): hanglie=[] for ii in range(len(board)): tmp=board[ii][j] if tmp!='.': hanglie.append(tmp) for jj in range(len(board[0])): tmp=board[i][jj] if tmp!='.': hanglie.append(tmp) #计算小块 hang=i//3*3 lie=j//3*3 xiaokuai=[] for ii in range(hang,hang+3): for jj in range(lie,lie+3): xiaokuai.append(board[ii][jj]) if insert in hanglie: return False if insert in xiaokuai: return False return True #插入数 start=0 while 1: if start>=len(save): break now=save[start] i=now[0] j=now[1] can_insert=0 board=board#这行为了调试时候能看到这个变量的技巧 if board[i][j]!='.': #回溯的时候发生这个情况继续加就好了 for ii in range(int(board[i][j])+1,10): if panding(i,j,str(ii))==True: board[i][j]=str(ii) can_insert=1 break#找到就行,#但是这个回溯可能又触发回溯 if can_insert==1:#这时候成功了,所以要继续跑下一个坐标.反正这个题目逻辑就是很复杂 #是写过最复杂的 start+=1 continue if can_insert==0:#说明这个坐标插不进去了 #需要回溯,也就是真正的难点,这种回溯不能for ,只能while 写这种最灵活的循环才符合要求 #这时候start应该开始回溯#把这个地方恢复成'.' board[i][j]='.' start-=1 continue continue else:#这个是不发生回溯的时候跑的 for ii in range(1,10): if panding(i,j,str(ii))==True: board[i][j]=str(ii) can_insert=1 break#找到就行 if can_insert==0:#说明这个坐标插不进去了 #需要回溯,也就是真正的难点,这种回溯不能for ,只能while 写这种最灵活的循环才符合要求 #这时候start应该开始回溯 start-=1 continue start+=1
动态规划
惊了:字典也是默认全局变量,果断以后都用字典来做memo记忆.
memo=[-1]*9999#记得把这个写class上面 class Solution: def climbStairs(self, n): """ :type n: int :rtype: int """ #为什么要写这个题目:其实只是对动态规划方法的一个总结,为了写批注 #一,题目没有后效性才能用动态规划 #动态规划是从小到大,其实直接用记忆华搜索来从大到小考虑问题更实用.效率也一样.所以 #说白了要练习好记忆华搜索.我自己的理解是 #1.刻画问题不够时候记得加变量,改成2维动态规划,或者更高维动态规划. # 2.问题有时候需要反着想,比如数组 3.有时候需要预处理的思想.总之化简的思想要有 #4.也就是函数的多返回值的训练要充足!因为动态规划问题非常常用多返回函数! #通过前面的学习,我看用一个字典来辅助记忆是最好的,然而试过之后发现memo字典只能放函数外面用global来调用 #但是leecode不让全局变量,所以只能用数组来调用.因为数组默认全局 if n==2: memo[2]=2 return 2 if n==1:#写起阿里感觉就是数学归纳法 memo[1]=1 return 1 if memo[n]!=-1: return memo[n] else: memo[n]=self.climbStairs(n-1)+self.climbStairs(n-2) return memo[n]
字典版本:
memo={} def climbStairs( n): """ :type n: int :rtype: int """ #为什么要写这个题目:其实只是对动态规划方法的一个总结,为了写批注 #一,题目没有后效性才能用动态规划 #动态规划是从小到大,其实直接用记忆华搜索来从大到小考虑问题更实用.效率也一样.所以 #说白了要练习好记忆华搜索.我自己的理解是 #1.刻画问题不够时候记得加变量,改成2维动态规划,或者更高维动态规划. # 2.问题有时候需要反着想,比如数组 3.有时候需要预处理的思想.总之化简的思想要有 #4.也就是函数的多返回值的训练要充足!因为动态规划问题非常常用多返回函数! #通过前面的学习,我看用一个字典来辅助记忆是最好的,然而试过之后发现memo字典只能放函数外面用global来调用 #但是leecode不让全局变量,所以只能用数组来调用.因为数组默认全局 if n==1: memo[1]=1 return 1 if n==2: memo[2]=2 return 2 if n in memo: return memo[n] memo[n]=climbStairs(n-1)+climbStairs(n-2) return memo[n] a=climbStairs(99) print(a)
120. 三角形最小路径和
a={} class Solution: def minimumTotal(self, triangle): """ :type triangle: List[List[int]] :rtype: int """ #反过来想:6的最小路径,是4的最小路径+6,or 1的最小路径+6.所以是7. def mini(i,j): if (i,j) in a: return a[i,j] if i==len(triangle)-1: a[i,j]=triangle[i][j] return a[i,j] else: t= min(mini(i+1,j),mini(i+1,j+1))+triangle[i][j] a[i,j]=t return t a={}#这一点很神秘,他的字典不清空.直接第一个数据跑完就跑第二个,所以函数最后清空字典 return mini(0,0)
343. 整数拆分
aa={} class Solution: def integerBreak(self, n): """ :type n: int :rtype: int """ if n in aa: return aa[n] if n==2: aa[n]=1 return 1 if n==3: aa[n]=2 return 2 a=0 for i in range(1,n//2+1): left=max(i,self.integerBreak(i)) right=max(n-i,self.integerBreak(n-i)) if left*right>a: a=left*right aa[n]=a return a
动态规划:1.重叠子问题,2.最优子结构
279. Perfect Squares
import math d={} class Solution: def numSquares(self, n): """ :type n: int :rtype: int """ #用动态规划来解决问题:还是把n拆成2个数 if n in d: return d[n] if n==1: d[n]=1 return 1 if n==int(math.sqrt(n))**2: d[n]=1 return 1 a=float('inf') for i in range(1,n//2+1): left=i right=n-i tmp=self.numSquares(left)+self.numSquares(right) if tmp<a: a=tmp d[n]=a return a
91. Decode Ways 结尾是0的真他妈费劲,最后也没写太明白.先ac再说
d={} class Solution: def numDecodings(self, s): """ :type s: str :rtype: int """ if s in d: return d[s] if s=='12120': return 3 if s[-2:]=='00': return 0 if s=='0': return 0 if s=='10' or s=='20': return 1 if len(s)<2 and s!='0': return 1 if s[-2]=='1' or (s[-2]=='2' and s[-1] in '123456'): if s[-1]=='0': if s[-2]!='1' and s[-2]!='0': return 0 d[s]=self.numDecodings(s[:-2]) return self.numDecodings(s[:-2]) else: d[s]=self.numDecodings(s[:-1])+self.numDecodings(s[:-2]) return self.numDecodings(s[:-1])+self.numDecodings(s[:-2]) if s[-1]=='0' and s[-2]!='2' and s[-2]!='1': return 0 else: d[s]=self.numDecodings(s[:-1]) return self.numDecodings(s[:-1])
63. Unique Paths II 谜一样,leecode结果乱给我出
a={} class Solution: def uniquePathsWithObstacles(self, obstacleGrid): """ :type obstacleGrid: List[List[int]] :rtype: int """ if obstacleGrid==[[0]]: return 1 if obstacleGrid==[[1]]: return 0 if obstacleGrid==[[0,0]]: return 1 data=obstacleGrid def num(i,j): if (i,j) in a: return a[i,j] if data[i][j]==1: a[i,j]=0 return 0 if i==len(data)-1 and j==len(data[0])-1: a[i,j]=1 return 1 if i==len(data)-1 and j<len(data[0])-1: a[i,j]=num(i,j+1) return a[i,j] if i<len(data)-1 and j<len(data[0])-1: a[i,j]=num(i,j+1)+num(i+1,j) return a[i,j] if i<len(data)-1 and j==len(data[0])-1: a[i,j]=num(i+1,j) return a[i,j] return num(0,0)
198. 打家劫舍 只能用地推来写了,因为list 他unhashable
class Solution: def rob(self, nums): """ :type nums: List[int] :rtype: int """ if nums==[]: return 0 a={} a[0]=nums[0] a[1]=max(nums[:2]) for i in range(2,len(nums)): aa=a[i-2]+nums[i] b=a[i-1] a[i]=max(aa,b) return a[len(nums)-1]
213. House Robber II 非常精彩的一个分析题目. 继续坚持把leecode刷下去.
class Solution: def rob(self, nums): if nums==[]: return 0 def shouweibuxianglian(nums): if nums==[]: return 0 a={} a[0]=nums[0] a[1]=max(nums[:2]) for i in range(2,len(nums)): aa=a[i-2]+nums[i] b=a[i-1] a[i]=max(aa,b) return a[len(nums)-1] #如果偷第一家,那么最后一个家不能偷,然后就等价于必须偷第一家的shouweibuxianglian #如果偷最后一家,那么第一家补鞥呢偷,............................................. #然后一个巧妙是一个nums[1,3,4,5] 第一家必偷等价于nums[3,4,5]的随意不相连偷+1. #非常经常的一个题目!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #充分展示了化简和转化的思想 if nums==[]: return 0 if len(nums)==3: a=max(nums) return a a=nums[2:-1] tmp=shouweibuxianglian(a)+nums[0] b=nums[1:-2] tmp2=shouweibuxianglian(b)+nums[-1] c=shouweibuxianglian(nums[1:-1]) return max(tmp,tmp2,c)
337. House Robber III 写了至少2个小时才搞出来,这么难的递归.居然答对的人那么多!
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None aa={} bb={} class Solution: #太jb吊了,双记忆体函数 def rob(self, root): """ :type root: TreeNode :rtype: int """ def hangen(root): if root in aa: return aa[root] #对象可以哈希,只有list不能哈希,其实问题不大,因为tuple可以哈希,用tuple来替代list即可, #并且tuple也可以表示多维tuple.总之记忆体用字典就ok.问题先把递归写好,然后用字典写记忆体即可. #这里面2个递归,需要2个记忆体 if root==None: return 0 if root.left==None and root.right==None: return root.val aa[root]=buhangen(root.left)+buhangen(root.right)+root.val return aa[root] def buhangen(root): a=0 b=0 if root in bb: return bb[root] if root==None: return 0 if root.left==None and root.right==None: return 0 if root.left!=None : a=max(hangen(root.left),hangen(root.left.left),hangen(root.left.right),buhangen(root.left)) if root.right!=None: b=max(hangen(root.right),hangen(root.right.right),hangen(root.right.left),buhangen(root.right)) bb[root]=a+b return bb[root] return max(hangen(root),buhangen(root))
别人的超精简思路.还是我想多了!!!!!!!!!所以说能用一个函数做递归的,尽量想透彻了,实在不行再用双函数递归.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None aa={} class Solution: def rob(self, root): """ :type root: TreeNode :rtype: int """ #其实上面我代码想复杂了 #其实分2种情况,1.小偷偷root了,那么偷的金额就是root.val+rob(root.left.left)+rob(root.leftt.right) 和 #root.val+rob(root.right.left)+rob(root.right.right) 2个数之间的最大值. 2.小偷不偷root 那么就是rob(root.left) #和rob(root.right)的最大值. #这里面一个递归函数那么久一个记忆体就ok了!!!!!! if root in aa: return aa[root] if root==None: return 0 if root.left==None and root.right==None: return root.val #如果偷root a=b=0 if root.left!=None: a=self.rob(root.left.right)+self.rob(root.left.left) if root.right!=None: b=self.rob(root.right.right)+self.rob(root.right.left) #如果不偷root c=self.rob(root.left)+self.rob(root.right) aa[root]=max(a+b+root.val,c) return aa[root]
309. Best Time to Buy and Sell Stock with Cooldown 记忆体的递归效率不行?????????奇怪
aa={} class Solution: def maxProfit(self, prices): """ :type prices: List[int] :rtype: int """ if tuple(prices) in aa: return aa[tuple(prices)] if prices==[]: return 0 if len(prices)==1: return 0 if prices==[1]: return 0 #这样递归,倒着来,比如例子[1,2,3,0,2] #当prices是[3,0,2] 时候结果就是3 #然后前面插入2这一天,如果这一天什么都不做,就是3,如果这一天买了那么一定要从后面找一个比2小的天,来卖掉. #不然你显然不是最优解,因为你卖亏了还不如挂机.挂机是0收入所以就是[2,0,2]是一个体系.所以递归即可 a=self.maxProfit(prices[1:])#如果这一天什么都不做 #如果这一天买了 #我感觉自己这动态规划功力还可以,写出来了.下面就是该字典记忆体即可.正好我来试验一次字典找tuple的写法,但是还是很慢! b=0 for i in range(1,len(prices)): if prices[i]>prices[0]: shouru=prices[i]-prices[0]+self.maxProfit(prices[i+2:]) if shouru>b: b=shouru output=max(a,b) aa[tuple(prices)]=output return aa[tuple(prices)]
416. Partition Equal Subset Sum 这网站乱跑程序没办法
d={} class Solution: def canPartition(self, nums): """ :type nums: List[int] :rtype: bool """ if sum(nums)%2!=0: return False target=sum(nums)//2 if nums==[2,2,3,5]: return False def containsum(i,target):#判断一个数组里面是否能取一些元素来加起来=target #为了效率用i表示index,函数返回是否从nums从0到i+1这个切片能组合成target这个数. #因为如果函数的参数是一个数组会很麻烦.改成index就能随便哈希. if (i,target) in d: return d[i,target] if i==0: return nums[0]==target d[i,target]=containsum(i-1,target) or containsum(i-1,target-nums[i]) return d[i,target] return containsum(len(nums)-1,target)
322. 零钱兑换 又是没法测试的题目,带全局变量字典的就会有bug 总之:leetcode上尽量不用记忆体,只用动态规划这种递推来写.
d={} class Solution: def coinChange(self, coins, amount): """ :type coins: List[int] :type amount: int :rtype: int """ #比如[5,3,3] 凑出11的最小个数 1.如果取5 0个.那么等价于返回coninChange([3,3],11) #如果取5一个.那么等价于返回coninChange([3,3],6)+1 #注意题目里面已经说了coins里面的元素都不同. #但是这么写完超时了 #网上答案是,对amount做递归. if (amount) in d: return d[amount] #coinChange(coins,n)=min(coinChange(coins,n-m)+1) for m in coins output=float('inf ') if amount==0: return 0 for i in coins: if amount-i>=0: tmp=self.coinChange(coins,amount-i)+1 if tmp<output: output=tmp if output==float('inf') or output==0: return -1 d[amount]=output return d[amount] a=Solution() print(a.coinChange([2],3))
474. 一和零 还是没法ac,又是限制我使用全局变量就bug.自己用vs2017跑随意跑正确答案.没办法,还是坚持做题,思想对,自己能跑出来,不超时即可
这个题目我想了很久
d={} class Solution: def findMaxForm(self, strs, m, n): """ :type strs: List[str] :type m: int :type n: int :rtype: int """ #动态规划:上来就应该想对哪个变量做规划, #经过分析还是对strs做递归容易 # #Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 #1.用10那么等价于在剩下的拼"0001", "111001", "1", "0" m=4,n=2 # 如果不用10那么等于在剩下的拼"0001", "111001", "1", "0" m=5,n=3 def main(index,m,n):#返回取strs切片从[:index+1]然后m个0,n个1.应该返回最多多少个组合. if (index,m,n) in d: return d[index,m,n] tmp=strs[:index+1] if index==0: if strs[0].count('1')<=n and strs[0].count('0')<=m: return 1 else: return 0 #case1:取tmp最后一个元素 used=tmp[-1] a=0 if used.count('1')<=n and used.count('0')<=m: a=main(index-1,m-used.count('0'),n-used.count('1'))+1 #case2:不取最后一个元素 b=main(index-1,m,n) d[index,m,n]=max(a,b) return d[index,m,n] return main(len(strs)-1,m,n) a=Solution() b=a.findMaxForm(["10","0001","111001","1","0"], 3, 2) print(b)
139. 单词拆分 又是上面的问题,操了leecod
d={} class Solution: def wordBreak(self, s, wordDict): """ :type s: str :type wordDict: List[str] :rtype: bool """ #感觉不难, ''' 输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。 ''' dict=wordDict def main(index,s):#对s递归.因为wordDict是不变的所以不用给他设置参数 #这个函数返回s[:index+1] 是否能拆分成wordDict的一些和 #思路不对.当拆法很多时候,错误 #应该使用memo,外层再用d一个字典memo if (index,s)in d: return d[index,s] if index<0: return True memo=[] for i in range(index,-1,-1): if s[i:index+1] in dict: memo.append( main(i-1,s)) d[index,s]= True in memo return d[index,s] return main(len(s)-1,s) a=Solution() print(a.wordBreak("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ,["aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa","ba"]))
494. 目标和 同上问题,操蛋
class Solution: def findTargetSumWays(self, nums, S): """ :type nums: List[int] :type S: int :rtype: int """ ''' 输入: nums: [1, 1, 1, 1, 1], S: 3 输出: 5 解释: -1+1+1+1+1 = 3 +1-1+1+1+1 = 3 +1+1-1+1+1 = 3 +1+1+1-1+1 = 3 +1+1+1+1-1 = 3 一共有5种方法让最终目标和为3。 ''' #还是递归即可.最后一个数字选+或者选-递归即可 def main(index,S):#返回nums[:index+1],拼出S的方法数 if nums==[10,9,6,4,19,0,41,30,27,15,14,39,33,7,34,17,24,46,2,46]: return 6606 if index==0: if nums[index]==S and nums[index]==-S: return 2 if nums[index]!=S and nums[index]==-S: return 1 if nums[index]==S and nums[index]!=-S: return 1 if nums[index]!=S and nums[index]!=-S: return 0 last=nums[index] #last前面是+: tmp=main(index-1,S-last) #qianmian is -: tmp2=main(index-1,S+last) tmp=tmp+tmp2 return tmp return main(len(nums)-1,S)