leetcode python刷题_leetcode面试刷题笔记--python

1.两数之和:

做题要点:字典

利用map性质,当target-nums[i]在map中时,直接返回,如果不在则将nums[i]加入到map中即可。

1 classSolution:2 def twoSum(self, nums: List[int], target: int) ->List[int]:3 dic ={}4 for i inrange(len(nums)):5 if target - nums[i] indic.keys():6 return([i, dic.get(target -nums[i])])7 dic[nums[i]] = i

时间空间复杂度O(n)

3.无重复字符的最长子串:

做题要点:滑动窗口,字典,双指针

利用滑动窗口方法,记指针i=0,j=0.同时建立字典。循环遍历数组元素,当数组元素不包含于字典时,i++,同时将该元素添加到字典中。如果字典中包含该元素,则将字典中s[j]删除,并且将j++。最后返回字典长度最大值即可。

1 classSolution:2 def lengthOfLongestSubstring(self, s: str) ->int:3 i = 0 #左指针

4 j = 0 #右指针

5 dic ={}6 maxv =07 while i

11 else:12 dic.pop(s[j])13 j += 1

14 if maxv

View Code

4.两数相加:

做题要点:数学

1.暴力还原整数再加再转换成链表:先将两个链表转换成两个整数,两整数相加,将结果转换为链表

1 classSolution:2 def addTwoNumbers(self, l1: ListNode, l2: ListNode) ->ListNode:3 num1 = ""

4 num2 = ""

5 while l1 is notNone:6 num1 +=str(l1.val)7 l1 =l1.next8 while l2 is notNone:9 num2 +=str(l2.val)10 l2 =l2.next11 ans = str(int(num1[::-1]) + int(num2[::-1]))12 length =len(ans)13 result =ListNode(int(ans[0]))14 for i in range(1, length):15 result =ListNode(int(ans[i]), result)16 return result

View Code

2.合理利用进位

用s来存储每位相加的结果,同时保存进位结果。遍历链表,当l1不为空或者l2不为空或者s不为0时,执行两链表按位相加的操作,将结果保存在s,用s的个位建立新节点,同时再将s除十取floor即可(保存进位)。

1 def addTwoNumbers(self, l1: ListNode, l2: ListNode) ->ListNode:2 head = p =ListNode(0)3 s =04 while l1 or l2 or s !=0:5 s += (l1.val if l1 else 0) + (l2.val if l2 else0)6 p.next = ListNode(s % 10)7 p =p.next8 s //= 10 #进位

9 l1 = l1.next if l1 elseNone10 l2 = l2.next if l2 elseNone11 return head.next

15.三数之和:

做题要点:双指针

本题目与第一题有一定的联系,我们首先将整个数组进行排序遍历nums数组中的元素nums[i]。同时令L为i+1,R为len(nums)-1。当nums[i]=nums[i-1]时,跳过该次循环,因为此时会造成重复解。当L小于R时,我们进行循环判断nums[L]+nums[R]+nums[i]是否为0,如果为0,将其加入答案并跳过L,R相邻重复元素。如果>0则说明nums[R]过大,故将R--。如果<0则说明nums[L]过小,将L++。

1 classSolution:2 def threeSum(self, nums: List[int]) ->List[List[int]]:3 if len(nums)<3:4 return[]5 nums.sort()6 ans =[]7 for i inrange(len(nums)):8 if nums[i]>0:9 returnans10 if(i>0 and nums[i]==nums[i-1]):11 continue

12 L = i+1

13 R = len(nums)-1

14 while L <15 if nums ans.append>

18 while(L

20 while(L

22 L=L+1

23 R=R-1

24 elif nums[i] + nums[L] + nums[R] >0:25 R-=1

26 elif nums[i] + nums[L] + nums[R] <0:27 L+=1

28 return ans

View Code

时间复杂度O(n2),空间复杂度O(1)

15.K个一组翻转链表:

结合翻转链表的解法,加入count对已经反转的节点进行计数。当k=1或头节点为空或链表长度为1时表示不需要翻转,直接返回头节点。每翻转一次,将count自增一,当count%k为0时,将pre赋值为cur节点,同时,将cur节点向后挪动一个节点。并且将count自增。

1 classSolution:2 def reverseKGroup(self, head: ListNode, k: int) ->ListNode:3 if head is None or head.next is None or k == 1:4 returnhead5 count = 1

6 leng =07 node =head8 whilenode:9 leng+=1

10 node =node.next11 pre =ListNode(0)12 ans =ListNode(0)13 pre.next =head14 ans.next =head15 cur =head16 while leng - count > leng % k andcur.next:17 next_n =cur.next18 cur.next =next_n.next19 next_n.next =pre.next20 count += 1

21 pre.next =next_n22 if count ==k:23 ans.next =next_n24 if count % k ==0:25 pre =cur26 cur =cur.next27 count += 1

28 return ans.next

View Code

时间复杂度O(n),空间复杂度O(1)

11. 盛最多水的容器:

使用双指针法,从两侧向内收缩。注意指针变动的规律:将hi和hj中值较小的下标向内收缩!因为如果值较大的下标收缩面积必定减小!

1 def maxArea(self, height: List[int]) ->int:2 i =03 j = len(height)-1

4 max_v =05 while i <6 max_v="max((j-i)*min(height[i],height[j]),max_v)7" if height>min(height[i],height[j]):8 i+=16>

9 elif height[j-1] >min(height[i],height[j]):10 j-=1

11 else:12 i+=2

13 j-=2

14 return max_v

View Code

33. 搜索旋转排序数组:

本题目可以结合之前做过的一个题目:找寻旋转数组的最小值。我们可以先找到旋转数组的最小值,以此最小值为分界点,对左右两个排序数组进行二分查找。

1 classSolution:2 def search(self, nums: List[int], target: int) ->int:3 index =04 left =05 right = len(nums)-1

6 while left !=right:7 mid = int((right - left)/2) +left8 if nums[mid] > nums[right]: left = mid +1

9 elif nums[mid] < nums[right]: right =mid10 else: right-=1

11 index =right12 #对左右两侧分别进行二分查找

13 left1 =014 right1 = index-1

15 while left1 <16 mid="int((right1" left1 if nums target: returnmid18 elif> target: right1 =mid19 else: left1 = mid+116>

20 if nums[left1] == target: returnleft121 left2 =index22 right2 = len(nums)-1

23 while left2 <24 mid="int((right2" left2 if nums target: returnmid26 elif> target: right2 =mid27 else: left2 = mid+124>

28 if nums[left2] == target: returnleft229 return -1

View Code

时间复杂度O(nlogn),空间复杂度O(1)

23. 合并k个升序链表:

由本题可以联想到合并两个升序链表,结合分治算法,两两归并即可。

1 classSolution:2 def mergeTwoLists(self, l1: ListNode, l2: ListNode) ->ListNode:3 node = head =ListNode(0)4 while l1 andl2:5 if l1.val >l2.val:6 node.next =l27 l2 =l2.next8 node =node.next9 else:10 node.next =l111 l1 =l1.next12 node =node.next13 whilel1:14 node.next =l115 l1 =l1.next16 node =node.next17 whilel2:18 node.next =l219 l2 =l2.next20 node =node.next21 returnhead.next22

23 defmerge(self,left,right,lists):24 if left == right - 1:25 #可以两两合并

26 returnself.mergeTwoLists(lists[left],lists[right])27 if left ==right:28 #不需要合并

29 returnlists[left]30 mid = int((right - left)/2) +left31 l =self.merge(left,mid,lists)32 r = self.merge(mid+1,right,lists)33 returnself.mergeTwoLists(l,r)34

35 def mergeKLists(self, lists: List[ListNode]) ->ListNode:36 if len(lists) ==0:37 returnNone38 return self.merge(0,len(lists)-1,lists)

时间复杂度O(nlogk),k是链表个数,n是元素总数。空间复杂度为O(1)

56. 合并区间:

先将整个列表按第一个元素进行排序,再新建列表ans,将其初始化为intervals[0]。遍历intervals[1:],将元组记为x,y。判断ans[-1][1]和x的大小,如果x>ans[-1][1],说明区间没有重叠,直接将[x,y]加入ans。如果x<=ans[-1][1]。说明区间有重叠。故将ans[-1][1]赋值为y和ans[-1][1]的较大值即可。

1 deftakeFirst(ele):2 returnele[0]3

4 classSolution:5 def merge(self, intervals: List[List[int]]) ->List[List[int]]:6 if len(intervals) ==0:7 return[]8 intervals.sort(key=takeFirst)9 ans =[]10 ans.append(intervals[0])11 for x,y in intervals[1:]:12 if x > ans[-1][1]:13 #说明没有区间重叠,故直接append

14 ans.append([x,y])15 else:16 #说明有区间重叠,此时将ans[-1][1]赋值为y和ans[-1][1]的较大值

17 ans[-1][1] = max(y,ans[-1][1])18 return ans

View Code

时间复杂度O(nlogn),空间复杂度O(1)

46. 全排列:

使用回溯算法,遍历所有可能即可!递归要熟练。

1 classSolution:2 def permute(self, nums: List[int]) ->List[List[int]]:3 ans =[]4 used = [0 for i inrange(len(nums))]5 defbacktrack(nums,path):6 if notnums:7 #此时已经满足条件

8 ans.append(path)9 return

10 for i inrange(len(nums)):11 #遍历每一个可能的元素进行下一层递归!

12 backtrack(nums[:i] + nums[i+1:],path+[nums[i]])13 return

14 backtrack(nums,[])15 returnans16

17

View Code

时间复杂度O(n!)

39. 组合总和:

使用回溯算法,遍历所有可能即可。要对递归熟练。同时要合理利用约束条件降低时间复杂度!!!

1 classSolution:2 def combinationSum(self, candidates: List[int], target: int) ->List[List[int]]:3 res =[]4 defbacktrack(candidates,path):5 if sum(path) ==target:6 temp =sorted(path)7 if temp not inres:8 res.append(temp)9 return

10 if sum(path) > target: #说明此时已经不可能找到了

11 return

12 for i inrange(len(candidates)):13 #不可被重复选取

14 #backtrack(candidates[:i]+candidates[i+1:],path+[candidates[i]])

15 #可被无限制重复选取

16 backtrack(candidates,path+[candidates[i]])17 return

18 backtrack(candidates,[])19 return res

View Code

39. 滑动窗口的最大值:

使用双端队列,维护一个元素从队首到队尾一次变小的双端队列,每次取最大值即为队首值!注意新加入元素的位置以及队首元素是否还在窗口中即可。

1 classSolution:2 def maxSlidingWindow(self, nums: List[int], k: int) ->List[int]:3 if notnums:4 return[]5 ans =[]6 L =07 R =08 deque =[]9 #初始化滑动窗口

10 for i inrange(0,k):11 while deque and nums[deque[-1]]

15 #注意窗口L-R闭区间

16 ans.append(nums[deque[0]])17 #窗口开始滑动

18 while R

20 while deque and nums[deque[-1]]

24 while deque and (deque[0] <= L or deque[0] >R):25 deque.pop(0)26 deque.append(R)27 ans.append(nums[deque[0]])28 L+=1

29 R+=1

30 return ans

View Code

时间复杂度:O(n),每个元素最多进一次队列出一次队列最多操作2n次,空间复杂度O(n)。

38. 字符串的排列:

仍然是使用回溯法,注意如何去重:对字符串排好序之后,在遍历元素递归之前,如果当前元素和前一个元素相等,则说明前面已经对该字母进行过递归!故跳过此循环。

1 classSolution:2 def permutation(self, s: str) ->List[str]:3 res =[]4 #排序后方便进行去重

5 s =list(sorted(s))6 defbacktrack(now,path):7 if notnow:8 res.append(path)9 return

10 #说明此排列已经完成

11 for i inrange(len(now)):12 #如果当前元素和前一个元素相同,则重复!

13 if i > 0 and now[i] == now[i-1]:14 continue

15 backtrack(now[:i]+now[i+1:],path+now[i])16 backtrack(s,"")17 return res

View Code

时间复杂度O(n!)

31. 下一个排列:

针对本题目,可以设计如下算法:

1.遍历数组找到满足nums[k]

2.遍历数组找到满足nums[l]>nums[k]的最大的l,将nums[k]和nums[l]交换,再将nums[k+1:]逆序即可!

原理:找第一个的过程从后往前找nums[k] < nums[k+1], 意味着k+1之后是不上升的 nums[j]>=nums[j+1], j>k, 因此,后面的是逆序的,即最大字典序,找到的值是比nums[k]大的最小值,设为nums[t],意味着nums[t]>nums[k]>nums[t+1], 交换nums[k]与nums[t]后最大字典序不变,逆序之后即最小字典序。

1 classSolution:2 def nextPermutation(self, nums: List[int]) ->None:3 """

4 Do not return anything, modify nums in-place instead.5 """

6 index1 =07 flag =08 index2 =09 for i inrange(len(nums)):10 if i+1>=len(nums):11 if flag ==0:12 index1 = -1

13 break

14 if nums[i]

16 index1 =i17 if index1 == -1:18 nums.reverse()19 return

20 for i inrange(len(nums)):21 if nums[i]>nums[index1]:22 index2 =i23 nums[index1],nums[index2] =nums[index2],nums[index1]24 #翻转nums[index1+1:]

25 nums[index1+1:] = list(reversed(nums[index1+1:]))26

View Code

时间复杂度:O(n)

199. 二叉树的右视图:

对于本题目,本人采用层序遍历的方法,从左到右遍历每一层时将最后一个节点加入到ans中即可。

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.left = None

6 #self.right = None

7

8 classSolution:9 def rightSideView(self, root: TreeNode) ->List[int]:10 #按层进行BFS,每次添加到list中的都是queue的最后一个元素即可。

11 if notroot:12 return[]13 ans =[]14 queue =[]15 queue.append(root)16 ans.append(root.val)17 whilequeue:18 temp =[]19 #将下一层的节点从左向右全部加入temp中

20 for node inqueue:21 ifnode.left:22 temp.append(node.left)23 ifnode.right:24 temp.append(node.right)25 #将最靠右的节点加入ans中即为该层的右视图

26 iftemp:27 ans.append(temp[-1].val)28 queue =temp29 return ans

View Code

时间复杂度:O(n)

215. 数组中的第k个最大元素:

老题重做,对于本题而言,利用快速排序的partition函数进行递归即可。注意左右边界的传入!

1 classSolution:2 defpartition(self,nums,left,right,target):3 #随机化

4 random_index =random.randint(left, right)5 nums[random_index],nums[right] =nums[right],nums[random_index]6 main =nums[right]7 i = left-1

8 j =left9 while j<10 if nums>main:11 nums[i+1],nums[j] = nums[j],nums[i+1]12 i+=110>

13 j+=1

14 nums[i+1],nums[right] = nums[right],nums[i+1]15 #数组下标从0计数,故加一

16 now = i+1+1-left17 if now ==target:18 return nums[now-1+left]19 elif now <20>

21 return self.partition(nums,left + now,right,target-now)22 elif now >target:23 #说明当前元素比target对应元素小,故应从左半部分递归

24 return self.partition(nums,left,left-1 + now-1,target)25

26

27 def findKthLargest(self, nums: List[int], k: int) ->int:28 return self.partition(nums,0,len(nums)-1,k)

View Code

时间复杂度O(n)

9. 回文数:

可以用栈将数字进行倒序,可以转换为字符串进行判断。也可以按如下方式:

1 classSolution:2 def isPalindrome(self, x: int) ->bool:3 if x <0:4 returnFalse5 else:6 num =x7 ans =08 while num >0:9 ans += num%10

10 num//=10

11 if num >0:12 ans *= 10

13 return ans == x

View Code

时间复杂度O(n),空间复杂度O(1)

88. 合并两个有序数组:

归并排序的merge操作即可,注意此处要将nums2合并到nums1中,因此我们需要倒序遍历。

1 classSolution:2 def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) ->None:3 """

4 Do not return anything, modify nums1 in-place instead.5 """

6 i = m-1

7 j = n-1

8 k = len(nums1)-1

9 while i >= 0 and j >=0:10 if nums1[i] >nums2[j]:11 nums1[k] =nums1[i]12 k-=1

13 i-=1

14 else:15 nums1[k] =nums2[j]16 k-=1

17 j-=1

18 while i >=0:19 nums1[k] =nums1[i]20 k-=1

21 i-=1

22 while j >=0:23 nums1[k] =nums2[j]24 k-=1

25 j-=1

View Code

时间复杂度O(n),空间复杂度O(1)

14. 最长公共前缀

遍历即可。

1 classSolution:2 def longestCommonPrefix(self, strs: List[str]) ->str:3 if len(strs) ==0:4 return ""

5 min_len = 10086

6 ans = ""

7 for s instrs:8 if len(s)<9 min_len="len(s)10" for i inrange j in range if strs returnans14 ans return>

View Code

时间复杂度O(s),s为所有字符串长度和,空间复杂度O(1)

141. 环形链表

快慢指针即可解决。快指针每次走两个节点,慢指针每次走一个节点,如果存在环则快慢指针必然相遇。

1 #Definition for singly-linked list.

2 #class ListNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.next = None

6

7 classSolution:8 def hasCycle(self, head: ListNode) ->bool:9 slow =head10 fast =head11 while fast andfast.next:12 fast =fast.next.next13 slow =slow.next14 if fast ==slow:15 returnTrue16 return False

View Code

时间复杂度O(n),空间复杂度O(1)

112. 路径总和

对左右子树递归dfs即可。

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.left = None

6 #self.right = None

7

8 classSolution:9 def hasPathSum(self, root: TreeNode, sum: int) ->bool:10 if notroot:11 returnFalse12 left =False13 right =False14 ifroot.left:15 left = self.hasPathSum(root.left,sum-root.val)16 ifroot.right:17 right = self.hasPathSum(root.right,sum-root.val)18 if root.val == sum and not root.left and notroot.right :19 #说明此时root为叶子结点

20 returnTrue21 #说明此时不为叶子结点或者是不满足和为sum

22 return left orright23

View Code

时间复杂度O(n),空间复杂度O(n)

160. 相交链表

设置两个node,node1和node2,令其next分别为headA和headB。让node1和node2同时向后走一个节点。如果node走到了链表末尾也即为null,将其重置为另一个链表的head即可。当node1等于node2时,则为相交链表的第一个相交节点。

1 #Definition for singly-linked list.

2 #class ListNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.next = None

6

7 classSolution:8 def getIntersectionNode(self, headA: ListNode, headB: ListNode) ->ListNode:9 #双指针

10 node1 =ListNode(0)11 node2 =ListNode(0)12 node1.next =headA13 node2.next =headB14 whileTrue:15 ifnode1:16 node1 =node1.next17 elif notnode1:18 #此时将node1重置到headB

19 node1 =headB20 ifnode2:21 node2 =node2.next22 elif notnode2:23 #此时将node2重置到headA

24 node2 =headA25 if node2 ==node1:26 return node1

View Code

时间复杂度O(n),空间复杂度O(1)

176. 第二高的薪水

sql嵌套,先找最高薪水,再找小于最高薪水的最高薪水即可。

# Write your MySQL query statement below

selectmax(salary) SecondHighestSalary fromemployee wheresalary 

101. 对称二叉树

递归即可,注意对null情况进行完备地判断!

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.left = None

6 #self.right = None

7

8 classSolution:9 def isSymmetric(self, root: TreeNode) ->bool:10 defsymmetric(node1,node2):11 if not node1 and notnode2:12 #两节点都为null

13 returnTrue14 if node1 and not node2 or node2 and notnode1:15 #一个null一个有值false

16 returnFalse17 if node1.val!=node2.val:18 returnFalse19 if not node1.left and not node1.right and not node2.left and not node2.right and node1.val==node2.val:20 #叶子节点必对称

21 returnTrue22 return symmetric(node1.left,node2.right) andsymmetric(node1.right,node2.left)23 if not root or not root.right and notroot.left:24 returnTrue25 returnsymmetric(root.left,root.right)26

27

28

29

View Code

时间复杂度O(n),空间复杂度O(n)

175. 组合两个表

person左连接address即可保留address所有属性,注意平时的限制关键词where应该改成on!

# Write your MySQL query statement below

selectFirstName,LastName,City,State fromPerson leftjoinAddress onPerson.PersonId =Address.PersonId

543. 二叉树的直径:

对于此题目,对二叉树进行后序遍历即可:当前节点为null时,说明此时直径为0,如果当前节点不为null,求其左子树直径和右子树直径。如果左右子树直径之和大于当前保存的最大直径,则将最大值替换为左右子树直径之和。并将左右子树直径较大值+1返回上一层。

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.left = None

6 #self.right = None

7

8 classSolution:9 def diameterOfBinaryTree(self, root: TreeNode) ->int:10 path =[]11 #后序遍历即可

12 defdfs(node):13 if notnode:14 return015 left =dfs(node.left)16 right =dfs(node.right)17 #1代表当前节点!

18 path.append(left +right)19 return max(left+1,right+1)20 dfs(root)21 #print(path)

22 if notpath:23 return024 return max(path)

View Code

时间复杂度O(n),空间复杂度O(n)

103. 二叉树的锯齿形层次遍历:

对于此题目,在二叉树的层序遍历基础上新加一个层数判断即可。

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.left = None

6 #self.right = None

7

8 classSolution:9 def zigzagLevelOrder(self, root: TreeNode) ->List[List[int]]:10 if notroot:11 return[]12 ans =[]13 queue =[]14 queue.append(root)15 ans.append([root.val])16 count = 1

17 whilequeue:18 temp =[]19 for i inqueue:20 ifi.left:21 temp.append(i.left)22 ifi.right:23 temp.append(i.right)24 iftemp:25 if count %2 !=0:26 #说明此时需要逆序遍历

27 ans_t =[]28 for i in temp[::-1]:29 ans_t.append(i.val)30 ans.append(ans_t)31 else:32 ans_t =[]33 for i intemp:34 ans_t.append(i.val)35 ans.append(ans_t)36 count+=1

37 queue =temp38 return ans

View Code

时间复杂度O(n),空间复杂度O(n)

19. 删除链表的倒数第N个节点:

双指针法:定义node1和node2,两节点均初始化为头结点,先让node2走n+1个节点,同时如果node2为空同时还要继续前进时说明要删除头结点,此时直接返回第二个节点即可。待node2遍历完成后,让node1和node2同时前进,当node2为null时,说明node1.next为待删除节点,删除即可。

1 #Definition for singly-linked list.

2 #class ListNode:

3 #def __init__(self, val=0, next=None):

4 #self.val = val

5 #self.next = next

6 classSolution:7 def removeNthFromEnd(self, head: ListNode, n: int) ->ListNode:8 node1 =head9 node2 =head10 ans =head11 for i in range(n+1):12 #node2提前走n个节点

13 ifnode2:14 node2 =node2.next15 else:16 returnans.next17 whilenode2:18 node1 =node1.next19 node2 =node2.next20 node1.next =node1.next.next21 returnans22

23

View Code

时间复杂度O(n),空间复杂度O(n)

92. 反转链表II:

此题目在反转链表的基础上指定了要反转的链表范围,可以先记node1为pre,pre.next为head,让node1前进m个节点,则此时node1即为待反转部分起点的前一个节点。此时我们可以添加一个变量count记录已经反转的节点个数,每翻转一次count++,当count>=n-m时,停止反转操作。对于返回值进行特判:如果m=1说明从起点开始反转,此时返回pre1.next。如果m>1说明从中间开始反转,直接返回head即可。

1 #Definition for singly-linked list.

2 #class ListNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.next = None

6

7 classSolution:8 def reverseBetween(self, head: ListNode, m: int, n: int) ->ListNode:9 pre =ListNode(0)10 pre.next =head11 node1 =pre12 for i in range(m-1):13 node1 =node1.next14 #得到开始反转的节点的前一个节点为node1

15 count =016 pre =node117 pre_ret =node118 node =node1.next19 while count < n-m:20 n_next =node.next21 node.next =n_next.next22 n_next.next =pre.next23 pre.next =n_next24 count+=1

25 if m > 1:26 returnhead27 return pre_ret.next

View Code

时间复杂度O(n),空间复杂度O(1)

102. 二叉树的层序遍历:

用队列遍历即可

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, x):

4 #self.val = x

5 #self.left = None

6 #self.right = None

7

8 classSolution:9 def levelOrder(self, root: TreeNode) ->List[List[int]]:10 if notroot:11 return[]12 queue =[]13 queue.append(root)14 ans =[[root.val]]15 whilequeue:16 temp =[]17 ans_temp =[]18 for node inqueue:19 ifnode.left:20 ans_temp.append(node.left.val)21 temp.append(node.left)22 ifnode.right:23 ans_temp.append(node.right.val)24 temp.append(node.right)25 ifans_temp:26 ans.append(ans_temp)27 queue =temp28 return ans

View Code

时间复杂度O(n),空间复杂度O(n)

102. 两两交换链表中的节点:

对于本题而言,在反转链表的基础上添加了两两反转的限制。在每次反转之后,将pre设置为node,并将node赋为node.next即可。注意节点数为奇数时最后一个节点不反转!关键代码:

#两个一组对应操作

pre =node

node= node.next

1 #Definition for singly-linked list.

2 #class ListNode:

3 #def __init__(self, val=0, next=None):

4 #self.val = val

5 #self.next = next

6 classSolution:7 def swapPairs(self, head: ListNode) ->ListNode:8 if not head or nothead.next:9 returnhead10 pre =ListNode(0)11 pre.next =head12 node =head13 ans =head.next14 whilenode:15 if notnode.next:16 #对于余下一个节点的情况的处理

17 break

18 node_next =node.next19 node.next =node_next.next20 node_next.next =pre.next21 pre.next =node_next22 #两个一组对应操作

23 pre =node24 node =node.next25 returnans26

View Code

时间复杂度O(n),空间复杂度O(1)

22.括号生成

对于本题目而言,对于输入的数字n,先初始化n对括号的字符串,然后类似于全排列算法,求得括号组合的全排列,在递归的过程中进行剪枝(对于本体而言因为括号只有左右括号,因此当左右括号都被处理过之后可以跳过循环。)

1 classSolution:2 def generateParenthesis(self, n: int) ->List[str]:3 #遍历所有情况,再筛选所有有效的括号组合

4 ans =[]5 str_in = ""

6 for i inrange(n):7 str_in+="()" #initialize input

8 defjudge(brack_str):9 stack =[]10 for i inbrack_str:11 if i == "(":12 stack.append(i)13 elif i == ")" andstack:14 if stack.pop() != "(":15 returnFalse16 elif notstack:17 returnFalse18 returnTrue19 defbacktrack(str_input,path):20 flag_left =021 flag_right =022 if notstr_input:23 if judge(path) and path not inans:24 ans.append(path)25 path = ""

26 return

27 for i inrange(len(str_input)):28 if str_input[i] == "(" and flag_left == 1:29 continue

30 if str_input[i] == ")" and flag_right == 1:31 continue

32 if str_input[i] == "(" and flag_left ==0:33 flag_left = 1

34 if str_input[i] == ")" and flag_right ==0:35 flag_right = 1

36 backtrack(str_input[:i]+str_input[i+1:],path+str_input[i])37 backtrack(str_in,"")38 return ans

View Code

时间复杂度O(n!)

解法2:可以记左括号剩余数为left,右括号剩余数为right,用dfs即可。终止条件为left与right均为0.同时如果right

1 classSolution:2 def generateParenthesis(self, n: int) ->List[str]:3 #遍历所有情况,再筛选所有有效的括号组合

4 ans =[]5 str_in = ""

6 defbacktrack(left,right,path):7 if left == 0 and right ==0:8 ans.append(path)9 if right <10>

11 return

12 if left >0:13 backtrack(left-1,right,path+"(")14 if right >0:15 backtrack(left,right-1,path+")")16 backtrack(n,n,"")17 return ans

View Code

时间复杂度O(n!)

22.螺旋矩阵

对于此题目而言,边界条件的限定十分重要,记上下左右边界分别为:up,down,left,right,依次从边界行数或列数进行模拟遍历即可。

1 classSolution:2 def spiralOrder(self, matrix: List[List[int]]) ->List[int]:3 up =04 down = len(matrix)-1

5 left =06 right = len(matrix[0])-1

7 ans =[]8 whileTrue:9 i =left10 while i <=right:11 ans.append(matrix[up][i])12 i+=1

13 up+=1

14 if up >down:15 break

16

17 i =up18 while i <=down:19 ans.append(matrix[i][right])20 i+=1

21 right-=1

22 if left >right:23 break

24

25 i =right26 while i >=left:27 ans.append(matrix[down][i])28 i-=1

29 down-=1

30 if up >down:31 break

32

33 i =down34 while i >=up:35 ans.append(matrix[i][left])36 i-=1

37 left+=1

38 if left >right:39 break

40 return ans

View Code

时间复杂度O(m*n)

148.排序链表

对于此题目要求而言,其要求空间复杂度为O(1),时间复杂度为O(nlogn),想到归并排序,但是限于空间复杂度不能使用递归。因此采用自底向上的迭代计算。

主要函数有两个:

cut(node,step):将node链表的前step个节点截取下来,并返回cut完后的头节点

merge(l1,l2):将l1和l2两个链表进行合并,最后返回链表头节点。

先两两进行归并,再四四进行归并,依次类推。代码如下:

1 #Definition for singly-linked list.

2 #class ListNode:

3 #def __init__(self, val=0, next=None):

4 #self.val = val

5 #self.next = next

6 classSolution:7 def sortList(self, head: ListNode) ->ListNode:8 defcut(node,step):9 #切下node链表的前step个节点并返回切完后的头节点

10 #若节点不够,则能切几个是几个

11 for i in range(step-1):12 ifnode:13 node =node.next14 ifnode:15 ans =node.next16 node.next =None17 returnans18 else:19 returnNone20 defmerge(l1,l2):21 pre =ListNode(0)22 head =pre23 while l1 andl2:24 if l1.val>l2.val:25 pre.next =l226 pre =pre.next27 l2 =l2.next28 else:29 pre.next =l130 pre =pre.next31 l1 =l1.next32 whilel1:33 pre.next =l134 pre =pre.next35 l1 =l1.next36 whilel2:37 pre.next =l238 pre =pre.next39 l2 =l2.next40 returnhead.next41 if nothead:42 returnNone43 node =head44 length =045 pre =ListNode(0)46 pre.next =head47 current =pre.next48 tail =pre49 whilenode:50 node =node.next51 length+=1

52 for i in range(int(log(length,2))+1):#归并操作次数

53 #最后一次操作将整个链表的两半进行一次merge!

54 step = pow(2,i)55 current =pre.next56 tail =pre57 whilecurrent:58 left =current59 right =cut(current,step)60 current = cut(right,step)#下一次循环的left

61 tail.next = merge(left,right) #merge获取到合并的头节点,将已经合并的链表的尾部与该合并链表连接!

62 whiletail.next:63 tail =tail.next64 return pre.next

View Code

时间复杂度O(nlogn),空间复杂度为O(1)

94.二叉树的中序遍历

本题目要求非递归,故使用栈对递归过程进行模拟。

根节点入栈,进入循环

如果当前节点有左节点,此时将其左节点进栈。

如果不存在左节点但存在右节点,此时将根节点出栈,将根节点值加入list中,并将根节点的右节点进栈。

如果当前节点为叶子节点,则直接将当前节点出栈并将值加入list中,同时当前节点的根节点的左子节点设为空(防止重入造成死循环)。

执行如上循环即可。

1 #Definition for a binary tree node.

2 #class TreeNode:

3 #def __init__(self, val=0, left=None, right=None):

4 #self.val = val

5 #self.left = left

6 #self.right = right

7 classSolution:8 def inorderTraversal(self, root: TreeNode) ->List[int]:9 if notroot:10 return[]11 stack =[]12 ans =[]13 stack.append(root)14 whilestack:15 if stack[-1].left:16 #当前节点有左节点

17 stack.append(stack[-1].left)18 elif stack[-1].right:19 #当前节点无左节点,有右节点,此时应该pop出根节点

20 root_temp =stack.pop()21 ans.append(root_temp.val)22 stack.append(root_temp.right)23 else:24 #当前节点为叶子节点,pop出当前节点并且将当前节点值加入ans,同时将其设置为不可重入(设为null)

25 node =stack.pop()26 ans.append(node.val)27 if len(stack)>0:#最后一个节点pop出之后stack为空,故需要判断

28 stack[-1].left =None29 returnans30

31

View Code

时间复杂度O(n),空间复杂度O(1)

322.零钱兑换

对于此题目有两种解法:

dfs+剪枝:将coins数组逆序,然后对答案进行dfs搜索,当target值为零时说明搜索到一个可行解,此时将min(ans,count)赋值给ans即可。

同时注意剪枝!

1.coins[j]>target时说明硬币面值太大,此时跳过此重循环

2.(self.ans-count)*coins[j] < target

说明此时最大面值硬币都无法凑到target,因此不能得到比当前最优解更优的解,故直接break循环

1 classSolution:2 def coinChange(self, coins: List[int], amount: int) ->int:3 self.ans = pow(2,31) - 1

4 coins.sort(reverse=True)5 defbacktrack(i,target,count):6 if target==0:7 self.ans =min(self.ans,count)8 return

9 for j inrange(i,len(coins)):10 if coins[j] >target:11 #说明硬币面值太大,需要跳过此次循环

12 continue

13 if (self.ans-count)*coins[j] <14>

15 break

16 backtrack(j,target-coins[j],count+1)17 for i inrange(len(coins)):18 backtrack(i,amount,0)19 return self.ans if self.ans!=pow(2,31) - 1 else -1

View Code

时间复杂度O(N*amount)

动态规划:

记dp[i]为总金额i所需要的最少硬币数,则dp[i] = min(dp[i],dp[i-coin[j]]+1),遍历即可

1 classSolution:2 def coinChange(self, coins: List[int], amount: int) ->int:3 #dp[i] 金额为i所需要的最少coin个数

4 num = amount+1

5 dp = [num for i in range(amount+1)]6 dp[0] =07 for i in range(1,amount+1):8 for j inrange(len(coins)):9 if i >= coins[j] and dp[i-coins[j]] !=num:10 dp[i] = min(dp[i],dp[i-coins[j]]+1)11 return dp[-1] if dp[-1] != amount+1 else -1

View Code

时间复杂度O(N*amount)

93.复原ip地址

对于本题目而言,使用回溯法+剪枝进行求解

终止条件:

当前字符串为空,说明已经全部加入,此时将路径加入结果并返回

剪枝条件:

当前字符串大于count*3或者小于count,此时不可能构成有效的ip地址,直接返回(结合题目要求得到这个条件)

去除前导0:

判断待加入的字符串第一位是否为0并且其长度是否大于1,如果均满足说明有前导0,直接退出循环即可。

代码如下:

1 classSolution:2 def restoreIpAddresses(self, s: str) ->List[str]:3 ans =[]4 defbacktrack(num_str,path,count):5 if len(num_str) < count or len(num_str)>count*3:6 return

7 if notnum_str:8 #去掉最后一个点

9 ans.append(path[:len(path)-1])10 for i inrange(len(num_str)):11 p,q = num_str[:i+1],num_str[i+1:]12 if int(p[0]) == 0 and len(p) > 1:13 #过滤前导零

14 break

15 if 0 <= int(p) and int(p)<=255:16 backtrack(q,path+p+".",count-1)17 backtrack(s,"",4)18 returnans19

View Code

200.岛屿数量

对于本题本人采用bfs的方式,添加一个visit数组记录该元素是否被访问过,循环遍历每个元素,当当前元素没有被访问过同时还是陆地时,利用队列进行宽度优先搜索,当完全搜索不到时说明该片陆地已经被完全遍历。此时count+1即可。注意边界条件的处理!

代码如下:

1 classSolution:2 def numIslands(self, grid: List[List[str]]) ->int:3 visit = [[False for i in range(len(grid[0]))] for i inrange(len(grid))]4 #bfs遍历图

5 queue =[]6 line =len(grid)7 if line ==0:8 return09 col =len(grid[0])10 if col ==0:11 return012 count = 0 #岛屿数量

13 for i inrange(line):14 for j inrange(col):15 if grid[i][j] == "1" and not visit[i][j]: #尚未访问过此节点

16 visit[i][j] =True17 queue.append([i,j])18 #进行bfs

19 whilequeue:20 i1,j1 =queue.pop()21 #将该点上下左右的所有没有被visit过的岛屿加入

22 if i10 and not visit[i1-1][j1] and grid[i1-1][j1] == "1":26 queue.append([i1-1,j1])27 visit[i1-1][j1] =True28 if j10 and not visit[i1][j1-1] and grid[i1][j1-1] == "1":32 queue.append([i1,j1-1])33 visit[i1][j1-1] =True34 count+=1

35 returncount36

View Code

时间复杂度不便于分析。

79.单词搜索

本题采用dfs进行搜索,注意递归前后visit数组的状态赋值为true和false,同时当找到一个可行解的时候记得要直接返回!否则会超时。

1 classSolution:2 def exist(self, board: List[List[str]], word: str) ->bool:3 #dfs求解

4 line =len(board)5 col =len(board[0])6 ans =[]7 visit = [[False for i in range(col)] for i inrange(line)]8 defdfs(rem,i,j):9 if not rem:#说明此时已经没有剩余字符

10 ans.append(True)11 return

12 if i>0 and board[i-1][j] == str(rem[0]) and not visit[i-1][j]:13 visit[i-1][j] =True14 dfs(rem[1:],i-1,j)15 if len(ans) >0:16 return

17 visit[i-1][j] =False18 if i0:22 return

23 visit[i+1][j] =False24 if j>0 and board[i][j-1] == str(rem[0]) and not visit[i][j-1]:25 visit[i][j-1] =True26 dfs(rem[1:],i,j-1)27 if len(ans) >0:28 return

29 visit[i][j-1] =False30 if j0:34 return

35 visit[i][j+1] =False36 for i inrange(line):37 for j inrange(col):38 if board[i][j] == str(word[0]) and notvisit[i][j]:39 visit[i][j] =True40 dfs(word[1:],i,j)41 visit[i][j] =False42 if len(ans)>0:43 returnTrue44 return False

View Code

14>10>9>20>15>

你可能感兴趣的:(leetcode,python刷题)