ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

剑指offer刷题合集

2021-10-05 16:04:18  阅读:114  来源: 互联网

标签:head return offer 中序 数组 合集 节点 def 刷题


参考大神https://blog.csdn.net/zjulyx1993/article/details/108327108

1.剑指 Offer 03. 数组中重复的数字(数组)

 1 """ 找出数组中重复的数字。
 2 
 3 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
 4 2 <= n <= 100000
 5 
 6 示例 1:
 7 
 8 输入:
 9 [2, 3, 1, 0, 2, 5, 3]
10 输出:2 或 3 
11 
12  """
13 
14 #集合法,依次将列表中的数放入集合,若已在集合中重复,则输出,时间复杂度O(n),空间复杂度O(n)
15 def findRepeatNumber1(nums):
16     d = set()
17     for i in nums:
18         if i not in d:
19             d.add(i)
20         else:
21             return i
22 
23 #注意数字范围在0~n-1之间, 这说明每个数都可以放到等同于其自身值的下标中,时间复杂度O(n),空间复杂度降到O(1)
24 def findRepeatNumber2(nums):
25     for i in range(len(nums)):
26         
27         # for循环中每遍历一次位置i,会一直交换至nums[i]==i
28         while i != nums[i]:
29             # 当前下标i和值nums[i]不相等, 进入/继续内层循环,如果相等则说明此位置符合要求
30             j = nums[i]
31             if nums[i] == nums[j]:
32                 # 前提条件: i!=j, 所以nums[i]和nums[j]是数组的两个数字, 它们值相等, 即为重复数字
33                 return nums[i]
34             # 交换两个值, 使得nums[j] == j, 这样可以继续循环判断i和新的nums[i]
35             nums[i], nums[j] = nums[j], nums[i]
36 
37     return -1   #如果给定的数组没有重复值的话,返回-1

2.剑指 Offer 04. 二维数组中的查找(数组)

 1 """ 在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
 2 
 3 示例:
 4 
 5 现有矩阵 matrix 如下:
 6 [
 7   [1,   4,  7, 11, 15],
 8   [2,   5,  8, 12, 19],
 9   [3,   6,  9, 16, 22],
10   [10, 13, 14, 17, 24],
11   [18, 21, 23, 26, 30]
12 ]
13 给定 target = 5,返回 true。 给定 target = 20,返回 false。
14 
15 限制:
16 0 <= n <= 1000
17 0 <= m <= 1000 
18 """
19 #初始化坐标为右上角, 然后判断当前点与 target 的关系, 大于的话列号减 1, 小于的话行号+1, 直到找到等于 target 的点, 或者超出矩阵范围
20 #时间复杂度O(R+C),空间复杂度O(1)
21 def findNumberIn2DArray(matrix, target):
22     if not matrix:
23             return False
24     row, col = len(matrix), len(matrix[0])
25     r, c = 0, col-1
26     while r<row and c>-1:
27         if target < matrix[r][c]:
28             c -= 1
29         elif target > matrix[r][c]:
30             r += 1
31         else:
32             return True
33     return False

3.剑指 Offer 05. 替换空格(字符串)

 1 """ 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
 2 
 3 示例 1:
 4 
 5 输入:s = "We are happy."
 6 输出:"We%20are%20happy."
 7  
 8 限制: 0 <= s 的长度 <= 10000 
 9 """
10 
11 def replaceSpace(s):
12     # return s.replace(' ', '%20')
13     return '%20'.join(s.split())

4.剑指 Offer 06. 从尾到头打印链表(链表)

 1 """ 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
 2 
 3 示例 1:
 4 
 5 输入:head = [1,3,2]
 6 输出:[2,3,1]
 7  
 8 限制:0 <= 链表长度 <= 10000 
 9 class Solution:
10     def reversePrint(self, head: ListNode) -> List[int]:
11 """
12 
13 # Definition for singly-linked list.
14 class ListNode:
15     def __init__(self, x):
16         self.val = x
17         self.next = None
18 
19 #先正向存储到数组,再翻转返回
20 def reversePrint1(head: ListNode):
21     lst = []
22     while head:
23         lst.append(head.val)
24         head = head.next
25     return lst[::-1]
26 
27 #使用递归
28 def reversePrint2(head: ListNode):
29     res = []
30     
31     def add(x: ListNode):
32         if not x:           #递归出口
33             return 
34         add(x.next)
35         res.append(x.val)
36     
37     add(head)
38     return res
39 
40 #不能翻转,不能使用递归,只能用栈迭代
41 def reversePrint3(head: ListNode):
42     stack = []
43     while head:
44         stack.append(head.val)     #正向压入栈中
45         head = head.next
46     
47     res = []
48     while stack:
49         res.append(stack.pop().val)    #再一个个弹出
50     return res

5.剑指 Offer 07. 重建二叉树(树)

 1 """ 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 2 
 3 例如,给出
 4 前序遍历 preorder = [3,9,20,15,7]
 5 中序遍历 inorder = [9,3,15,20,7]
 6 返回如下的二叉树:
 7 
 8     3
 9    / \
10   9  20
11     /  \
12    15   7
13 
14 class Solution:
15     def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
16  """
17 
18 # Definition for a binary tree node.
19 class TreeNode:
20     def __init__(self, x):
21         self.val = x
22         self.left = None
23         self.right = None
24 
25        
26 #递归法
27 def buildTree1(preorder, inorder):
28     if not preorder:
29         return None
30     
31     valueToInorderIndex = {}        #使用一个value=>inorder index的字典加速运算, 为了使得查找中序下标的操作变为O(1), 不需要扫描整个中序数组
32     n = len(preorder)
33 
34     for i in range(n):
35         valueToInorderIndex[inorder[i]] = i
36 
37     def build(pb, pe, ib, ie):      #(pb, pe)是当前前序遍历的起点和终点 (ib, ie)是当前中序遍历的起点和终点
38         if pb > pe:                 
39             return None             #递归出口
40         
41         root = TreeNode(preorder[pb])         #前序遍历的当前第一个元素即为当前的根节点
42         if pb == pe:
43             return root
44         
45         im = valueToInorderIndex[root.val]    #根节点对应的中序遍历的下标,以此作为分界点
46         pm = pb + im - ib                     #根节点对应的前序遍历的下标(对应部分的前序和中序长度应该相等, 即im-ib=pm-pb,由此得出)
47 
48         #前序[pb    ]pm[     pe]
49         #中序[ib  ]im[       ie]
50         root.left = build(pb + 1, pm, ib, im-1)         #左子树部分,前序(pb+1, pm),中序(ib, im-1)
51         root.right = build(pm + 1, pe, im + 1, ie)      #右子树部分,前序(pm+1, pe),后序(im+1, ie)
52 
53         return root
54     return build(0, n-1, 0, n-1)
55 
56 #迭代法
57 def buildTree2(preorder, inorder):
58     if not preorder:
59         return None
60 
61     root = TreeNode(preorder[0])
62     stack = [root]
63     
64     ii = 0                  #ii表示当前的中序下标
65  
66     for pi in range(1, len(preorder)):
67         prenode = stack[-1]        #记录上一个栈顶节点,一定不为空
68         curnode = TreeNode(preorder[pi])     #当前节点curnode位于上一节点的左子树或者右子树
69 
70         if prenode.val != inorder[ii]:    #上一个节点不是当前中序节点, 意味着现在还没到上一个节点的右边部分, 所以当前节点位于左子树,
71             prenode.left = curnode
72         else:                              #上一节点就是当前中序节点,意味着当前节点在右子树上
73             while stack and ii < len(inorder) and stack[-1].val == inorder[ii]:
74                 prenode = stack.pop()      #找最上层一个(也即倒置前序序列最后一个)与当前中序节点相同的节点
75                 ii += 1
76             prenode.right = curnode        #那个节点的右儿子就是当前节点
77             
78         stack.append(curnode)              #将当前节点加入stack中, 作为下次循环的上一个节点
79 
80     return root        

6.剑指 Offer 09. 用两个栈实现队列(栈/队列)

 1 """ 用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1
 2 
 3 示例 1:
 4 输入:
 5 ["CQueue","appendTail","deleteHead","deleteHead"]
 6 [[],[3],[],[]]
 7 输出:[null,null,3,-1]
 8 
 9 示例 2:
10 输入:
11 ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
12 [[],[],[5],[2],[],[]]
13 输出:[null,-1,null,null,5,2]
14 
15 提示:1 <= values <= 10000,最多会对 appendTail、deleteHead 进行 10000 次调用 
16 """
17 # 两个队列stack1和stack2,队列尾部插入数据,即数据压入stack1,队列头部删除整数,判断三种情况
18 # 1.第二个栈不为空,则从第二个栈中弹出数据   2.第一个栈不为空,则从第一个栈中把元素依次弹出并压入第二个栈中   3.第一个栈为空,即删除失败
19 class CQueue:
20     def __init__(self):
21         self.stack1 = []    
22         self.stack2 = []
23 
24     def appendTail(self, value: int):       #在队列尾部插入整数
25         self.stack1.append(value)
26 
27     def deleteHead(self):                   #在队列头部删除整数
28         if self.stack2:             #对应情况1
29             return self.stack2.pop()
30         if not self.stack1:         #对应情况3
31             return -1
32        
33         while self.stack1:          #对应情况2
34             x = self.stack1.pop()
35             self.stack2.append(x)
36         return self.stack2.pop()
37 
38 
39 # Your CQueue object will be instantiated and called as such:
40 # obj = CQueue()
41 # obj.appendTail(value)
42 # param_2 = obj.deleteHead()

7.剑指 Offer 10- I. 斐波那契数列(动态规划)

 1 """ 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
 2 F(0) = 0,   F(1) = 1
 3 F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
 4 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
 5 
 6 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
 7  """
 8 
 9 def fib(n):
10     if n < 2:
11         return n
12 
13     x, y, z = 0, 1, 1
14     while n-2:
15         x, y = y, z
16         z = x + y
17         n = n - 1
18     return z % 1000000007
19 
20 #用数组更清晰
21 def fib2(n):
22     if n < 2:
23         return n
24 
25     dp=[0]*(n+1)
26     dp[1]=1
27     for k in range(2, n+1):
28         dp[k] = dp[k-1] + dp[k-2]
29     return dp[-1]%1000000007

8.剑指 Offer 10- II. 青蛙跳台阶问题(动态规划)

本质和上一题一样

9.剑指 Offer 11. 旋转数组的最小数字(二分查找)

 1 """ 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
 2 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
 3 例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。  
 4 
 5 输入:[3,4,5,1,2]
 6 输出:1
 7 
 8 输入:[2,2,2,0,1]
 9 输出:0 
10 """
11 #题目的意思是数组有两段递增序列,找分段点,如果只有一段递增序列,那就是开头
12 #二分查找
13 def minArray(numbers):
14     n = len(numbers)
15     i, j = 0, n-1
16     while i < j:
17         mid = (i + j) // 2
18         if numbers[mid] < numbers[j]:    #如果中间值小于末尾, 那么一定说明该数字之后(后半段)有序.
19             j = mid
20         elif numbers[mid] > numbers[j]:  #如果中间值大于末尾, 那么毫无疑问后半段无序.
21             i = mid + 1
22         else:                          #如果中间值等于末尾, 那就不好判断是前半段无序还是后半段无序,退化为逐个遍历
23             j -= 1
24     return numbers[i]

类似的还有面试题

面试题 10.03. 搜索旋转数组

 1 """ 搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。
 2 请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个
 3 
 4 输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
 5 输出: 8(元素5在该数组中的索引) 
 6 """
 7 
 8 #理解一下:旋转一次和旋转多次没有任何区别, 最终还是只有一个旋转点, 以及不多于 2 个的有序区间
 9 def search(arr, target):
10     left, right = 0, len(arr) - 1
11     while left <= right:
12 
13         mid = (left + right) // 2
14         if arr[left] == target:
15             return left
16         elif arr[mid] == target:         #mid和right值等于target时,未必是索引值最小的,还要继续遍历
17             right = mid
18         elif arr[right] == target:
19             left = mid + 1
20         elif arr[mid] < arr[right]:             #后半段有序
21             if arr[mid] < target < arr[right]:    #target在后半段里
22                 left = mid + 1
23             else:                                 #target在前半段里
24                 right = mid - 1
25         elif arr[mid] > arr[right]:             #前半段有序
26             if arr[left] < target < arr[mid]:     #target在前半段里
27                 right = mid - 1
28             else:                                 #target在后半段里
29                 left = mid + 1
30         else:                           #前后段谁有序不清楚,逐一遍历
31             right -= 1
32     return -1 

 

标签:head,return,offer,中序,数组,合集,节点,def,刷题
来源: https://www.cnblogs.com/cxq1126/p/14488205.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有