03 数组中重复的数字
题目描述:
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
方法一:暴力法
class Solution:
def findRepeatNumber(self, nums):
n = len(nums)
for i in range(0,n-1):
for j in range(i+1,n):
if nums[j] == nums[i]:
return nums[i]
运行超时
方法二:哈希表
class Solution:
def findRepeatNumber(self, nums):
hash_set = dict()
for item in nums:
if item in hash_set:
return item
else:
hash_set[item] = 1
04 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
方法一:暴力法
class Solution:
def findNumberIn2DArray(self, matrix,target):
if matrix == []:
return False
flag = False
row_len = len(matrix)
col_len = len(matrix[0])
for i in range(row_len):
for j in range(col_len):
if matrix[i][j] == target:
flag = True
return flag
竟然可以通过
方法二:从右上角出发,目标比数组数大则向左找,目标比数组数小则向下找。
class Solution:
def findNumberIn2DArray(self, matrix, target):
if matrix == []:
return False
flag = False
row_len = len(matrix)
col_len = len(matrix[0])
i = row_len - 1
j = 0
while i >= 0 and j <= col_len - 1:
if matrix[i][j] > target:
i = i - 1
elif matrix[i][j] < target:
j = j + 1
elif matrix[i][j] == target:
flag = True
break
return flag
05 替换空格
class Solution:
def replaceSpace(self, s):
return s.replace(" ","%20")
06 从尾到头打印列表
遍历链表后reverse即可
class Solution:
def reversePrint(self, head):
ret = []
p = head
while p != None:
ret.append(p.val)
p = p.next
ret.reverse()
return ret
07 重建二叉树
依据手动建树的方法模拟一次递归过程:
需要的信息有:从前序序列中找到根节点的值、中序序列中左子树的左边界、中序序列中右子树的左边界
思路如下:
从前序序列中找到根节点的值
根据根节点的值,找到根节点在中序序列中的位置(提前构造好{值:位置}的dict)
构建根节点(将根节点加入树中)
根据左右子树的边界信息,递归的对其左右子树进行上述操作
求解如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder, inorder):
# 在中序序列中,index可以根据值找到位置
index = {val:i for i,val in enumerate(inorder)}
# 递归函数建树:根节点在前序序列(preorder)中的下标,左、右子树在中序序列中的左右边界
def build(preRootId,inL,inR):
if inL > inR: # 递归出口 左边界大于右边界
return None
rootVal = preorder[preRootId] # 得到根节点的值
inRootId = index[rootVal] # 根据根节点的值 找到根节点在中序序列中的下标
# 求左子树的长度,目的是找到前序序列中右子树的根节点的起始地址
leftSize = inRootId - inL
# 构建根节点
root = TreeNode(rootVal)
# 构建左子树
root.left = build(preRootId+1, inL, inRootId-1)
# 构建右子树
root.right = build(preRootId+1+leftSize,inRootId+1,inR)
return root
return build(0,0,len(inorder)-1)
09 用两个栈实现队列
class CQueue:
def __init__(self):
self.Stack,self.Stack2 = [],[]
def appendTail(self, value):
self.Stack.append(value)
def deleteHead(self):
if self.Stack2:
return self.Stack2.pop()
if not self.Stack:
return -1
while self.Stack:
self.Stack2.append(self.Stack.pop())
return self.Stack2.pop()
还是要注意 Stack == [] 和 Stack is None是两个完全不同的概念。
10-1 斐波那契数列
class Solution:
def fib(self, n):
if n==0:
return 0
elif n==1:
return 1
else:
return self.fib(n - 1) + self.fib(n - 2)
递归时超出时间限制。
用一个一维数组存储前项结果。
class Solution:
def fib(self, n):
if n == 0:
return 0
if n == 1:
return 1
dp = [0] * (n+1)
dp[0] = 0
dp[1] = 1
for i in range(2,n+1):
dp[i] = dp[i-1]+dp[i-2]
return dp[n] % 1000000007
当然,也可以不用额外存储空间:
class Solution:
def fib(self,n):
if n == 0 :
return 0
a, b = 1, 1
for i in range(n - 1):
a, b = b, a + b
return a % 1000000007
10-2 青蛙跳台阶
class Solution:
def numWays(self, n):
if n == 0:
return 1
elif n == 1:
return 1
elif n == 2:
return 2
else:
return (self.numWays(n-1)+self.numWays(n-2)) % 1000000007
递归超出时间限制。
其解法与上述斐波那契数列一致。
class Solution:
def numWays(self, n):
if n == 0:
return 1
a,b = 1,2
for i in range(n - 1):
a, b = b, a + b
return a % 1000000007
11 旋转数组的最小数字
检测a[i+1]比a[i]小的元素即可
class Solution:
def minArray(self, numbers):
for i in range(0,len(numbers)-1):
if numbers[i+1]<numbers[i]:
return numbers[i+1]
return numbers[0]
12 矩阵中的路径
leetcode官方解法(DFS)
class Solution:
def exist(self,board,word):
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] # 四种前进方向
def check(i,j,k): #(i,j)是board中的坐标,k记录了已经比较到单词中的第k个字母
if board[i][j] != word[k]: # 终止条件:出现不相等
return False
if k == len(word) - 1: # 终止条件:比较完了整个单词
return True
visited.append((i,j)) # visited数组:记录已经走过的路径,避免兜圈子
result = False
for di,dj in directions:
newi,newj = i+di,j+dj # 出发
if 0 <= newi < len(board) and 0 <= newj < len(board[0]): # 当然只考虑board内的情况
if(newi, newj) not in visited: # 而且没访问过
if check(newi, newj, k+1): # 递归:只有k == len(word)-1时 才会将这些路径标记位True
result = True
break
visited.remove((i, j))
return result
h, w = len(board), len(board[0])
visited = []
for i in range(h):
for j in range(w):
if check(i, j, 0): # 初始值:k为0
return True
return False
13 机器人的运动范围
本题参考了leetcode官方解法(BFS)
from queue import Queue
def digitsum(n): # 求各位和函数
ans = 0
while n:
ans += n % 10
n //= 10
return ans
class Solution:
def movingCount(self, m, n, k):
q = Queue()
q.put((0, 0)) # 将(0,0)加入队列
s = set() # s是机器人活动范围集合 集合自带去重功能
while not q.empty():
x, y = q.get() # 每次出队一个坐标分析
if (x, y) not in s and 0 <= x < m and 0 <= y < n and digitsum(x) + digitsum(y) <= k: #符合题目所指条件
s.add((x, y))
for nx, ny in [(x + 1, y), (x, y + 1)]: # 将右侧、下册元素入队
q.put((nx, ny))
return len(s)
14 剪绳子
class Solution:
def cuttingRope(self, n):
dp = [0] * (n+1)
if n <= 2:
return 1
if n == 3:
return 2
# dp[x]定义为将绳子切成若干段的最大乘积
# 注意:当i≥4的时候 2、3段不切的乘积收益更高
dp[1] = 1
dp[2] = 2
dp[3] = 3
for i in range(4,n+1): # i 是绳子的长度
for j in range(1,i//2+1): # j 是刀的位置
dp[i] = max(dp[i],dp[j]*dp[i-j])
return dp[n]
15 二进制中1的个数
简单循环遍历
class Solution:
def hammingWeight(self, n):
n = bin(n)
cnt = 0
for i in str(n):
if i == '1':
cnt = cnt + 1
return cnt
位运算的巧妙推论:n & (n−1)的结果是将n二进制中最低位的1变为0
class Solution:
def hammingWeight(self, n):
ret = 0
while n:
n &= n - 1
ret += 1
return ret
16 数值的整数次方(重要)
常规思路:超时(0.00001 2147483647 )
class Solution:
def myPow(self, x, n):
if n < 0:
x = 1/x
n = abs(n)
if n == 0:
return 1.0
temp = x
while n-1:
x = x * temp
n = n - 1
return x
分治思路:
class Solution:
def myPow(self, x, n):
if n == 0:
return 1
def quickMul(n):
if n == 0:
return 1
y = quickMul(n // 2)
if n % 2 == 0:
return y*y
else:
return y*y*x
if n>0:
return quickMul(n)
elif n<0:
return 1/quickMul(-n)
17 打印从1到最大的n位数
class Solution:
def printNumbers(self, n):
limit = 1*pow(10,n)
lst = list()
for i in range(1,limit):
lst.append(i)
return lst
18 删除链表的节点(按值)
考虑到删除第一个元素的情况即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, head, val):
p = head
if head.val == val:
head = head.next
return head
while p.next.val != val:
p = p.next
p.next = p.next.next
return head
21.调整数组顺序使奇数位于偶数前面
class Solution:
def exchange(self, nums):
temp_1 = []
temp_2 = []
for i in nums:
if i%2 != 0:
temp_1.append(i)
else:
temp_2.append(i)
temp_1.extend(temp_2)
return temp_1
python合并两个列表用extend
22.链表中倒数第k个节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getKthFromEnd(self, head, k):
def linklist_length(head):
length = 0
while head:
length+=1
head = head.next
return length
length = linklist_length(head)
n = length - k
cnt = 0
while cnt<n:
head = head.next
cnt = cnt + 1
return head
24.反转链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head):
if head is None:
return None
cur = head
pre = None
# 四步走
while cur.next:
nex = cur.next # 存储cur的next
cur.next = pre
pre = cur
cur = nex
cur.next = pre
return cur
或
# 四步走
while cur:
nex = cur.next # 存储cur的next
cur.next = pre
pre = cur
cur = nex
return pre
25.合并两个排序的链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1, l2):
prehead = ListNode(-1)
prev = prehead
while l1 and l2:
if l1.val <= l2.val:
prev.next = l1
l1 = l1.next
else:
prev.next = l2
l2 = l2.next
prev = prev.next
prev.next = l1 if l1 is not None else l2
return prehead.next
26.树的子结构
递归思路
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# B是A的子结构:B从A的某个节点出发的遍历序列完全相同
# 递归的对A的每一个节点进行判定
def isSubStructure(self, A, B):
def Judge(A,B): # 依次对比(遍历)从该节点出发的A的某棵子树与B
if B is None: # 递归终止条件:B已经访问完
return True
if A is None:# 由于上一个判断 这里已经默认了B不为空 B不为空而A为空 证明B不是A的子结构
return False
if B.val != A.val:
return False
return Judge(A.left,B.left) and Judge(A.right,B.right)
if A is None or B is None:
return False
return Judge(A,B) or self.isSubStructure( A.left, B) or self.isSubStructure( A.right, B)
27.二叉树的镜像
递归是要找到最小问题 从最小问题开始解决
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def mirrorTree(self, root):
if root is None:
return;
left = self.mirrorTree(root.left)
right = self.mirrorTree(root.right)
root.left, root.right = right, left
return root
28.对称的二叉树
# 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):
def Judge(root1,root2):
if root1 is None and root2 is None:
return True
if root1 is None or root2 is None:
return False
return root1.val == root2.val and Judge(root1.left,root2.right) and Judge(root1.right,root2.left)
if root is None:
return True;
return Judge(root.left,root.right)
29.顺时针打印矩阵
换方向的条件:是模拟走后看是否有问题,而不是走之前判断四周;
class Solution:
def spiralOrder(self, matrix):
if not matrix:
return list()
rows = len(matrix)
columns = len(matrix[0])
directions = [[0,1],[1,0],[0,-1],[-1,0]]
index = 0
visited = [[False for col in range(columns)] for row in range(rows)]
ret = []
row = 0
column = 0
for i in range(0,columns*rows):
ret.append(matrix[row][column])
visited[row][column] = True
nextRow,nextCol = row + directions[index][0],column + directions[index][1]
# 换方向条件:这样走会有问题
if nextRow == rows or nextCol == columns or nextRow<0 or nextCol<0 or visited[nextRow][nextCol]:
index = (index+1)%4
row = row + directions[index][0]
column = column + directions[index][1]
return ret
30.包含min函数的栈
我们可以在每个元素 a
入栈时把当前栈的最小值 m
存储起来。在这之后无论何时,如果栈顶元素是 a
,我们就可以直接返回存储的最小值 m
。
class MinStack:
def __init__(self):
self.stack = []
self.mini_stack = [math.inf]
def push(self, x: int) -> None:
self.stack.append(x)
self.mini_stack.append(min(self.mini_stack[-1],x))
def pop(self) -> None:
self.stack.pop()
self.mini_stack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return self.mini_stack[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
31.栈的压入、弹出序列
class Solution:
def validateStackSequences(self, pushed, popped):
if pushed is None:
return False
stack = []
length = len(pushed)
i,j = 0,0
while j!= length and i!=length:
if pushed[i] != popped[j]:
stack.append(pushed[i])
i = i + 1
elif pushed[i] == popped[j]:
i = i + 1
j = j + 1
while j< length and stack and stack[-1] == popped[j] : # 这里的判断顺序不能变 否则会出现越界问题
j = j + 1
stack.pop()
return len(stack) == 0
可以简化为:
class Solution:
def validateStackSequences(self, pushed, popped) :
st, j = [], 0
for x in pushed:
st.append(x)
while st and st[-1] == popped[j]:
st.pop()
j += 1
return len(st) == 0
32.从上到下打印二叉树(重要)
层次遍历二叉树需要借助队列完成
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root):
if root is None:
return []
res, queue = [],collections.deque() # 队列
queue.append(root)
while queue:
node = queue.popleft()
res.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return res
但是在一些公司的面试考核中,是不允许使用python队列的库函数deque()的,可以用pop(0)代替popleft方法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root):
if root is None:
return []
ret = []
# 层次遍历(广度优先)
def bfs(root):
queue = [root]
while queue:
currentNode = queue.pop(0) # 等价于popleft
ret.append(currentNode.val)
if currentNode.left:
queue.append(currentNode.left)
if currentNode.right:
queue.append(currentNode.right)
bfs(root)
return ret
变式:以列表套列表的形式打印,思路是对于每一层的结果单独生成列表(tmp),用nxt存储下一层的结果,queue清零就是每层结束的标志。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root):
if root is None:
return []
ret = []
def bfs(root):
queue = [root]
while queue:
nxt = []
tmp = []
for node in queue:
tmp.append(node.val)
if node.left:
nxt.append(node.left)
if node.right:
nxt.append(node.right)
ret.append(tmp)
queue = nxt
bfs(root)
return ret
33.二叉搜索树的后序遍历序列
[1,3,2,6,5]
观察一个正确的序列,可以发现的关系是 [1,3,2] [6] [5]依次为比根小、比根大、根;
用两个指针分别指向位置0和len-1(根)处;
未完待续