第 02 天题目
0066. 加一
- 标签:数组
- 难度:简单
题目大意
给定一个非负整数数组,数组每一位对应整数的一位数字。计算整数 +1 后的结果。
解题思路
这道题把整个数组看成了一个整数,然后个位数 +1。问题的实质是利用数组模拟加法运算。
如果个位数不为 9 的话,直接把个位数 +1 就好。如果个位数为 9 的话,还要考虑进位。
具体步骤:
- 数组前补 0 位。
- 将个位数字进行 +1 计算。
- 遍历数组
- 如果该位数字 大于等于 10,则向下一位进 1,继续下一位判断进位。
- 如果该位数字 小于 10,则跳出循环。
代码
def plusOne(self, digits: List[int]) -> List[int]:
digits = [0] + digits
digits[len(digits)-1] += 1
for i in range(len(digits)-1,0,-1):
if digits[i] != 10:
break
else:
digits[i] = 0
digits[i-1] += 1
if digits[0] == 0:
return digits[1:]
else:
return digits
0724. 寻找数组的中心下标
- 标签:数组
- 难度:简单
题目大意
给定一个数组 nums,找到「左侧元素和」与「右侧元素和相等」的位置,若找不到,则返回 -1。
解题思路
两次遍历,第一次遍历先求出数组全部元素和。第二次遍历找到左侧元素和恰好为全部元素和一半的位置。
代码
class Solution:
def pivotIndex(self, nums: List[int]) -> int:
sum = 0
for i in range(len(nums)):
sum += nums[i]
curr_sum = 0
for i in range(len(nums)):
if curr_sum * 2 + nums[i] == sum:
return i
curr_sum += nums[i]
return -1
0189. 旋转数组
- 标签:数组
- 难度:中等
题目大意
给定一个数组,将数组中的元素向右移动 k 个位置。
解题思路
很容易想到的是用一个新数组,先保存原数组的后 k 个元素,再保存原数组的前 n-k 个元素。但题目要求不使用额外的数组空间,那么就需要在原数组上做操作。
我们可以先把整个数组翻转一下,这样后半段元素就到了前边,前半段元素就到了后边,只不过元素顺序是反着的。我们再从 k 位置分隔开,将 [0, k-1] 的元素和 [k, n-1] 的元素再翻转一下,就得到了最终结果。
具体步骤:
- 将数组 [0, n-1] 位置上的元素全部翻转
- 将数组 [0, k-1] 位置上的元素进行翻转
- 将数组 [k+1, n-1] 位置上的元素进行翻转
代码
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
n = len(nums)
k = k % n
self.reverse(nums, 0, n-1)
self.reverse(nums, 0, k-1)
self.reverse(nums, k, n-1)
def reverse(self, nums: List[int], left: int, right: int) -> None:
while left < right :
tmp = nums[left]
nums[left] = nums[right]
nums[right] = tmp
left += 1
right -= 1
第 03 天题目
0048. 旋转图像
- 标签:数组
- 难度:中等
题目大意
给定一个 n*n 的二维矩阵(代表图像)。将二维矩阵顺时针旋转 90°,要求不能使用额外的数组空间。
解题思路
如果使用额外数组空间的话,将对应元素存放到对应位置即可。如果不使用额外的数组空间,则需要观察每一个位置上的点最初位置和最终位置有什么规律。
对于矩阵中第 i 行的第 j 个元素,在旋转后,它出现在倒数第 i 列的第 j 个位置。即
matrixnew[col][n−row−1] = matrix[row][col]
而 matrixnew[col][n-row-1]
的点经过旋转移动到了 matrix[n−row−1][n−col−1]
的位置。
matrix[n−row−1][n−col−1]
位置上的点经过旋转移动到了 matrix[n−col−1][row]
的位置。
matrix[n−col−1][row]
位置上的点经过旋转移动到了最初的 matrix[row][col]
的位置。
这样就形成了一个循环,我们只需要通过一个临时变量 tmp 就可以将循环中的点逐一进行交换。
另一种思路是利用翻转代替旋转。
原矩阵可以通过一次水平翻转+主对角线翻转得到旋转后的二维矩阵。具体可以参考代码。
代码
def rotate(self, matrix: List[List[int]]) -> None:
n = len(matrix)
for i in range(n//2):
for j in range(n):
matrix[i][j], matrix[n-i-1][j] = matrix[n-i-1][j], matrix[i][j]
for i in range(n):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
0054. 螺旋矩阵
- 标签:数组
- 难度:中等
题目大意
给定一个 m * n 大小的二维矩阵 matrix。要求按照顺时针旋转的顺序,返回矩阵中的所有元素。
解题思路
按照题意进行模拟。可以实现定义一下上、下、左、右的边界,然后按照逆时针的顺序从边界上依次访问元素。
当访问完当前边界之后,要更新一下边界位置,缩小范围,方便下一轮进行访问。
代码
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
up, down, left, right = 0, len(matrix)-1, 0, len(matrix[0])-1
ans = []
while True:
for i in range(left, right + 1):
ans.append(matrix[up][i])
up += 1
if up > down:
break
for i in range(up, down + 1):
ans.append(matrix[i][right])
right -= 1
if right < left:
break
for i in range(right, left - 1, -1):
ans.append(matrix[down][i])
down -= 1
if down < up:
break
for i in range(down, up - 1, -1):
ans.append(matrix[i][left])
left += 1
if left > right:
break
return ans
0498. 对角线遍历
- 标签:数组、矩阵、模拟
- 难度:中等
题目大意
给你一个大小为 m * n
的矩阵 mat
。
要求:以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。
解题思路
这道题的关键是「找规律」和「考虑边界问题」。
找规律:
- 当行号 + 列号为偶数时,遍历方向为从左下到右上。可以记为右上方向(-1, +1),即行号 -1,列号 +1。
- 当行号 + 列号为奇数时,遍历方向为从右上到左下。可以记为左下方向(+1, -1),即行号 +1,列号 -1。
边界情况:
- 向右上方向移动时:
- 如果在最后一列,则向下方移动,即
x += 1
。 - 如果在第一行,则向右方移动,即
y += 1
。 - 其余情况想右上方向移动,即
x -= 1
、y += 1
。
- 向左下方向移动时:
- 如果在最后一行,则向右方移动,即
y += 1
。 - 如果在第一列,则向下方移动,即
x += 1
。 - 其余情况向左下方向移动,即
x += 1
、y -= 1
。
代码
class Solution:
def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:
rows = len(mat)
cols = len(mat[0])
count = rows * cols
x, y = 0, 0
ans = []
for i in range(count):
ans.append(mat[x][y])
if (x + y) % 2 == 0:
# 最后一列
if y == cols - 1:
x += 1
# 第一行
elif x == 0:
y += 1
# 右上方向
else:
x -= 1
y += 1
else:
# 最后一行
if x == rows - 1:
y += 1
# 第一列
elif y == 0:
x += 1
# 左下方向
else:
x += 1
y -= 1
return ans
参考资料
- 【题解】「498. 对角线遍历」最简单易懂! - 对角线遍历 - 力扣(LeetCode)