week13
文章目录
- week13
- 知识点:
- 简单:
- 中等:
- [442. 数组中重复的数据](https://leetcode.cn/problems/find-all-duplicates-in-an-array/)
- [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/)
- [73. 矩阵置零](https://leetcode.cn/problems/set-matrix-zeroes/)
- [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
- [79. 单词搜索](https://leetcode.cn/problems/word-search/)
- [48. 旋转图像](https://leetcode.cn/problems/rotate-image/)
- 困难:
- 其他
知识点:
float('inf')
:
float('inf')
在 Python 中表示正无穷。它是一个特殊的值,比任何其他可能的数字都大。
原地算法:
原地算法是一种计算机算法,它只在输入数组上进行操作,而不是创建额外的存储空间。这可以节省内存和时间,尤其是在数组很大的情况下。
原地算法的一种常见用途是排序。例如,冒泡排序和插入排序都是原地算法。这些算法可以对数组中的元素进行排序,而无需创建额外的存储空间。
原地算法的另一种常见用途是搜索。例如,二分搜索是一种原地算法,它可以快速地在数组中查找指定的元素。
原地算法是计算机科学中重要的工具。它们可以用于解决各种各样的问题,包括排序、搜索和压缩。
zip() 函数:
在 Python 中,zip() 函数用于将两个或多个序列(列表、元组、字符串等)合并成一个元组列表。
例如,以下代码将两个列表合并成一个元组列表:
Python
list1 = [1, 2, 3]
list2 = [4, 5, 6]
result = list(zip(list1, list2))
print(result)
输出:
[(1, 4), (2, 5), (3, 6)]
zip() 函数的返回值是一个元组列表,其中每个元组包含来自两个原始序列的元素。在上面例子中,每个元组包含一个元素来自 list1 和一个元素来自 list2。
zip() 函数还可以用于将字符串合并成一个元组列表:
Python
str1 = "abc"
str2 = "def"
result = list(zip(str1, str2))
print(result)
输出:
[('a', 'd'), ('b', 'e'), ('c', 'f')]
zip() 函数是一个非常有用的函数,它可以用于将多个序列合并成一个元组列表。它可以用于解决各种各样的问题。
在 Python 中,zip() 函数用于将两个或多个序列(列表、元组、字符串等)合并成一个元组列表。
例如,以下代码将两个列表合并成一个元组列表:
Python
list1 = [1, 2, 3]
list2 = [4, 5, 6]
result = list(zip(list1, list2))
print(result)
输出:
[(1, 4), (2, 5), (3, 6)]
zip() 函数的返回值是一个元组列表,其中每个元组包含来自两个原始序列的元素。在上面例子中,每个元组包含一个元素来自 list1 和一个元素来自 list2。
zip() 函数还可以用于将字符串合并成一个元组列表:
Python
str1 = "abc"
str2 = "def"
result = list(zip(str1, str2))
print(result)
输出:
[('a', 'd'), ('b', 'e'), ('c', 'f')]
zip() 函数是一个非常有用的函数,它可以用于将多个序列合并成一个元组列表。它可以用于解决各种各样的问题。
简单:
448. 找到所有数组中消失的数字
题目描述
给你一个含 n
个整数的数组 nums
,其中 nums[i]
在区间 [1, n]
内。请你找出所有在 [1, n]
范围内但没有出现在 nums
中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
code:
class Solution:
def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
seen = [False] * (len(nums) + 1) # 记录出现的值
result = [] # 记录结果
for num in nums: # 标记已出现的数值
seen[num] = True
for i in range(1, len(nums) + 1): # [1, n]
if seen[i] is False: # 未出现的数值
result.append(i)
return result
class Solution:
def find_disappeared_numbers(self, nums: List[int]) -> List[int]:
"""
给定一个含 n 个整数的数组 nums ,找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
时间复杂度:O(n)
空间复杂度:O(1)
Args:
nums: 一个含 n 个整数的数组。
Returns:
一个包含所有没有出现过的数字的数组。
"""
# 记录出现的值
seen = [False] * (len(nums) + 1)
# 记录结果
result = []
# 标记已出现的数值
for num in nums:
seen[num] = True
# 遍历 [1, n],如果数值没有出现,则添加到结果数组中
for i in range(1, len(nums) + 1):
if seen[i] is False:
result.append(i)
return result
解题思路:
使用布尔数组 seen 来标记每个数字是否已经出现过。如果数字已经出现过,则将其标记为 True;如果数字没有出现过,则将其标记为 False。遍历完数组后,所有标记为 False 的数字就是所有没有出现过的数字。
seen
列表用于存储已经出现过的数字。result
列表用于存储所有没有出现过的数字。- 循环遍历数组,如果数字已经出现过,则将其标记为已经出现过。
- 遍历 [1, n],如果数值没有出现,则添加到
result
列表中。 - 最后,返回
result
列表。
121. 买卖股票的最佳时机
题目描述:
给定一个数组 prices
,它的第 i
个元素 prices[i]
表示一支给定股票第 i
天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0
。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
code:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
min_price = float('inf') # 初始最大价格保证最小的买入是在数组中
max_profit = 0
for price in prices:
min_price = min(price, min_price) # 得到数组最小买入
max_profit = max(max_profit, price - min_price) # 更新最大利润
return max_profit
解题思路:
贪心算法:因为只用一买一出,所以要计算最小的price和最大的price的价格,该算法的好处就像等于将 [ 1 , 2 , 3 , 2 , 6 , 7 ] ⟶ [ [ 1 , 3 ] , [ 2 , 7 ] ] ⟶ [ 2 , 5 ] [1,2,3,2,6,7]\longrightarrow[[1,3],[2,7]]\longrightarrow[2,5] [1,2,3,2,6,7]⟶[[1,3],[2,7]]⟶[2,5]我们要的结果就是5。
118. 杨辉三角
题目描述:
给定一个非负整数 *numRows
,*生成「杨辉三角」的前 numRows
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
code:
class Solution:
def generate(self, num_rows: int) -> List[List[int]]:
# 初始化结果列表。
result = []
for row in range(num_rows):
# 初始化当前行的列表。
row_list = []
for col in range(row + 1):
# 如果当前列为 0 或行数,则元素为 1。
if col == 0 or col == row:
row_list.append(1)
# 否则,元素为上两元素之和。
else:
row_list.append(result[row - 1][col - 1] + result[row - 1][col])
# 添加当前行的列表到结果列表。
result.append(row_list)
return result
解题思路:
简单的动态规划,处理每行的结果,在逐一添加答案。
中等:
442. 数组中重复的数据
题目描述:
给你一个长度为 n
的整数数组 nums
,其中 nums
的所有整数都在范围 [1, n]
内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n)
且仅使用常量额外空间的算法解决此问题。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[2,3]
code:
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
seen = [False] *(len(nums) + 1) # 构建hash表
result = [] # 结果记录
for num in nums:
if seen[num]: # 第二次出现
result.append(num)
else: # 第一次出现
seen[num] = True
return result
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
"""
给定一个长度为 n 的整数数组 nums ,找出所有出现 两次 的整数,并以数组形式返回。
时间复杂度:O(n)
空间复杂度:O(1)
Args:
nums: 一个长度为 n 的整数数组。
Returns:
一个包含所有出现 两次 的整数的数组。
"""
# 构建哈希表
seen = [False] * (len(nums) + 1)
# 结果记录
result = []
# 遍历数组
for num in nums:
# 如果数字已经出现过
if seen[num]:
# 将其添加到结果数组中
result.append(num)
# 否则
else:
# 将其标记为已经出现过
seen[num] = True
# 返回结果数组
return result
解题思路:
seen
列表用于存储已经出现过的数字。result
列表用于存储所有出现过两次的数字。- 循环遍历数组,如果数字已经出现过,则将其添加到
result
列表中,否则将其标记为已经出现过。 - 最后,返回
result
列表。
原地hsah表,因为条件限制所以,难度大大下降
n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
nums
中的每个元素出现 一次 或 两次
55. 跳跃游戏
题目描述:
给定一个非负整数数组 nums
,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
code:
class Solution:
def canJump(self, nums: List[int]) -> bool:
n = len(nums)
max_right = 0
for i in range(n):
# 如果当前位置可以达到
if i <= max_right:
# 更新可以达到的最大位置
max_right = max(max_right, i + nums[i])
# 如果可以达到数组的最后一个位置
if max_right >= n - 1:
return True
return False
解题思路:
贪心算法:在不超过最大界限的范围内,可以达到的最大位置,若超过最大的右边界,则可以跳跃到最后一个下标。
73. 矩阵置零
题目描述:
给定一个 *m* x *n*
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法**。**
示例 1:
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
code:
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
"""
`m` 和 `n` 分别是矩阵的行数和列数。
`row_has_zero` 是一个布尔列表,表示矩阵中的每一行是否包含 0 元素。
`col_has_zero` 是一个布尔列表,表示矩阵中的每一列是否包含 0 元素。
"""
m, n = len(matrix), len(matrix[0])
row_has_zero = [False] * m
col_has_zero = [False] * n
"""
遍历矩阵,并将所有包含 0 元素的行和列的元素置为 0。
"""
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
row_has_zero[i] = True
col_has_zero[j] = True
"""
遍历矩阵,并将所有被标记为 0 的行和列的元素置为 0。
"""
for i in range(m):
for j in range(n):
if row_has_zero[i] or col_has_zero[j]:
matrix[i][j] = 0
解题思路:
首先创建两个布尔数组,分别表示矩阵中的行和列是否包含 0 元素。然后,遍历矩阵,并将所有包含 0 元素的行和列的元素置为 0。最后,返回修改后的矩阵。
54. 螺旋矩阵
题目描述:
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
code:
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
# 初始位置和界限
row_start = 0
row_end = len(matrix) - 1
col_start = 0
col_end = len(matrix[0]) - 1
result = []
# 开始循环
while row_start <= row_end and col_start <= col_end:
# 正向行
for col in range(col_start, col_end + 1):
result.append(matrix[row_start][col])
# 到下一行
row_start += 1
# 正向列
for row in range(row_start, row_end + 1):
result.append(matrix[row][col_end])
# 到下一列
col_end -= 1
# 反向行
if row_start <= row_end:
for col in range(col_end, col_start - 1, -1):
result.append(matrix[row_end][col])
row_end -= 1
# 反向列
if col_start <= col_end:
for row in range(row_end, row_start - 1, -1):
result.append(matrix[row][col_start])
col_start += 1
return result
解题思路:
模拟算法,模拟数值的添加路线,要注意range的集合是一个左闭右开的区间。
79. 单词搜索
题目描述:
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
code:
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m, n = len(board), len(board[0])
for i in range(m):
for j in range(n):
if self.dfs(board, word, i, j, m, n):
return True
return False
def dfs(self, board, word, i, j, m, n):
if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != word[0]:
return False
if len(word) == 1:
return True
board[i][j] = '#'
for choice in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
if self.dfs(board, word[1:], i + choice[0], j + choice[1], m, n):
return True
board[i][j] = word[0]
return False
解题思路;
逐个字母地比较单词。如果两个字母匹配,则会向右或向下移动一个单元格,并继续比较下一个字母。如果两个字母不匹配,或者到达了网格的边界,则算法会返回 False。
小细节在 dfs
函数中,board[i][j] = '#'
语句将 #
标记符赋值给二维列表 board
的 i
行和 j
列中的元素。这是为了防止单词被多次找到。
48. 旋转图像
题目描述:
给定一个 n × n 的二维矩阵 matrix
表示一个图像。请你将图像顺时针旋转 90 度。
你必须在** 原地** 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
code:
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
n = len(matrix) # 矩阵的维度
for i in range(n // 2): # 遍历上半部分行
for j in range((n + 1) // 2): # 遍历上半部分列
# 进行四个元素的位置交换
matrix[i][j], matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1] = matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1], matrix[i][j]
解题思路:
可以观察到,旋转前后,原矩阵左上角的元素,会移动到右上角的位置,右上角的元素会移动到右下角的位置,右下角的元素会移动到左下角的位置,左下角的元素会移动到左上角的位置。因此,我们可以通过对矩阵中的四个元素进行位置交换来实现矩阵的旋转。
具体地,我们从外部的一圈元素开始,每次遍历对应一圈的四个边,对四个边的元素进行位置交换。遍历的终止条件是遍历完所有的圈。
需要注意的是,当矩阵的维度为奇数时,最中间的一行和一列只包含一个元素,不需要进行位置交换。
这样,就能够实现将矩阵顺时针旋转90度的操作。
困难:
41. 缺失的第一个正数
题目描述:
给你一个未排序的整数数组 nums
,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n)
并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
code:
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums) # 获取数组的长度
for i in range(n):
if nums[i] <= 0: # 处理非正整数
nums[i] = n + 1
for i in range(n):
num = abs(nums[i])
if num <= n: # 处理(1, N)的数
nums[num - 1] = -abs(nums[num - 1]) # 这里开始使用的是一个简单的负数值,没有考虑到重复的数
for i in range(n): # 开始扫描
if nums[i] > 0:
return i + 1
return n + 1(=
解题思路:
对于一个长度为N的数组,其中没有出现的的最小正整数只能在 [ 1 , N + 1 ] [1, N + 1] [1,N+1]。如果 [ 1 , N ] [1, N] [1,N]都出现了,那么答案就是 N + 1 N+1 N+1,否则就是 [ 1 , N ] [1, N] [1,N]中没有出现的最小正整数。
其他
ass Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums) # 获取数组的长度
for i in range(n):
if nums[i] <= 0: # 处理非正整数
nums[i] = n + 1
for i in range(n):
num = abs(nums[i])
if num <= n: # 处理(1, N)的数
nums[num - 1] = -abs(nums[num - 1]) # 这里开始使用的是一个简单的负数值,没有考虑到重复的数
for i in range(n): # 开始扫描
if nums[i] > 0:
return i + 1
return n + 1(=
#### 解题思路:
对于一个长度为N的数组,其中没有出现的的最小正整数只能在$[1, N + 1]$。如果$[1, N]$都出现了,那么答案就是$N+1$,否则就是$[1, N]$中没有出现的最小正整数。
## 其他