参考:https://labuladong.github.io/algo/2/20/26/
【中等】151. 反转字符串中的单词
https://leetcode.cn/problems/reverse-words-in-a-string/
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
思路:常规的思路是先strip去掉前后空格,再split分割成word数组,然后倒序," ".join()即可。另一种思路则是先反转整个字符串,然后反转每个word。
class Solution:
def reverseWords(self, s: str) -> str:
t = []
i = 0
while i < len(s):
# 非空格则直接加入
if s[i] != ' ':
t.append(s[i])
i += 1
else:
# 寻找空格的停止之处
while i < len(s) and s[i] == ' ':
i += 1
# 不要开头和结尾处的空格,只加入中间的空格
if len(t) != 0 and i < len(s):
t.append(' ')
length = len(t)
# 先反转整个字符串
self.reverse(t, 0, length - 1)
i = 0
while i < length:
j = i
while j < length:
# 找单词
if j + 1 == length or t[j + 1] == ' ' :
self.reverse(t, i, j)
i = j + 2
break
j += 1
return "".join(t)
def reverse(self, s:list, i:int, j:int):
while i < j:
s[i], s[j] = s[j], s[i]
i += 1
j -= 1
【中等】48. 旋转图像
https://leetcode.cn/problems/rotate-image
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
思路:先按对角线反转,将行变成列,然后左右反转。而左右反转实际是一维数组的反转。
如果是逆时针旋转90°,就是按另一条对角线反转(i→n-1-j ,j→n-1-i),再左右。
class Solution:
# 反转一维数组
def reverse(self, arr:List[int], i:int, j:int) -> None:
while i < j:
arr[i], arr[j] = arr[j], arr[i]
i += 1
j -= 1
def rotate(self, matrix: List[List[int]]) -> None:
m = len(matrix)
n = len(matrix[0])
for i in range(m):
# 注意这里是i开始
for j in range(i, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for i in range(m):
self.reverse(matrix[i], 0, n-1)
思路: (感觉这种更好记忆)每次都是[x,y]→[y][n-x]
[i, j] → [n-j, i]
[n-j, i] → [n-i, n-j]
[n-i, n-j] → [j, n-i]
[j, n-i] → [i, j]
size = len(matrix)
n = size - 1
for i in range(size // 2):
for j in range((size + 1) // 2):
matrix[i][j], matrix[n - j][i], matrix[n - i][n - j], matrix[j][n - i] \
= matrix[n-j][i], matrix[n - i][n - j], matrix[j][n - i], matrix[i][j]
return matrix
1886. 判断矩阵经轮转后是否一致
https://leetcode.cn/problems/determine-whether-matrix-can-be-obtained-by-rotation
给你两个大小为 n x n 的二进制矩阵 mat 和 target 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false 。
思路: 跟上一题完全一致,只不过可能旋转4次罢了。
class Solution:
def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
size = len(mat)
n = size - 1
for k in range(4):
for i in range(size // 2):
for j in range((size + 1) // 2):
mat[i][j], mat[n-j][i], mat[n-i][n-j], mat[j][n-i] \
= mat[n-j][i], mat[n-i][n-j], mat[j][n-i], mat[i][j]
if mat == target:
return True
return False
【中等】54. 螺旋矩阵
https://leetcode.cn/problems/spiral-matrix/
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
思路:直接模拟行进方向,按顺序。注意,每次遍历完要修改的边界,是当前块需要判断的条件。
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
ans = []
left = 0 # 左边界
right = len(matrix[0]) - 1 # 右边界
up = 0 # 上边界
down = len(matrix) - 1# 下边界
size = len(matrix) * len(matrix[0])
while len(ans) < size:
# 顶部从左往右
if up <= down:
for i in range(left, right + 1):
ans.append(matrix[up][i])
# 上边界要改
up += 1
# 右侧从上到下
if left <= right:
for i in range(up, down + 1):
ans.append(matrix[i][right])
right -= 1
# 底部从右往左
if up <= down:
for i in range(right, left-1, -1):
ans.append(matrix[down][i])
down -= 1
# 左侧从下往上
if left <= right:
for i in range(down, up-1, -1):
ans.append(matrix[i][left])
left += 1
return ans
【简单】剑指 Offer 29. 顺时针打印矩阵
https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/
与上一题完全一致,只是用例中含[],因此需要加一条判断:if len(matrix) == 0: return ans
【中等】59. 螺旋矩阵 II
https://leetcode.cn/problems/spiral-matrix-ii/
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
思路:与54.螺旋矩阵是一样的。需要改的只有引用每个ans[i][j]时。
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
left = 0 # 左边界
right = n - 1 # 右边界
up = 0 # 上边界
down = n - 1# 下边界
size = n * n
# 初始化全0数组
ans = [[0 for i in range(n)] for j in range(n)]
num = 1
while num <= size:
# 顶部从左往右
if up <= down:
for i in range(left, right + 1):
ans[up][i] = num
num += 1
# 上边界要改
up += 1
# 右侧从上到下
if left <= right:
for i in range(up, down + 1):
ans[i][right] = num
num += 1
right -= 1
# 底部从右往左
if up <= down:
for i in range(right, left-1, -1):
ans[down][i] = num
num += 1
down -= 1
# 左侧从下往上
if left <= right:
for i in range(down, up-1, -1):
ans[i][left] = num
num += 1
left += 1
return ans
1572. 矩阵对角线元素的和
https://leetcode.cn/problems/matrix-diagonal-sum/
思路:
双指针吧。如果是奇数边长,加一个中心值。
class Solution:
def diagonalSum(self, mat: List[List[int]]) -> int:
s = 0
left = 0
size = len(mat)
right = size - 1
r = 0
while left < right:
s += mat[r][left] + mat[r][right] + mat[size - 1 - r][left] + mat[size - 1 - r][right]
r += 1
left += 1
right -= 1
if left == right:
s += mat[size // 2][left]
return s
448. 找到所有数组中消失的数字
https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
示例 2:
输入:nums = [1,1]
输出:[2]
进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
思路:
可以通过符号确认某个位置是否访问过。需要注意的是,python中负数index有意义。
class Solution:
def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
for i in range(len(nums)):
if nums[i] > 0:
a = nums[i] - 1
else:
a = -1 * nums[i] - 1
if nums[a] > 0:
nums[a] *= -1
ans = []
for i in range(len(nums)):
if nums[i] > 0:
ans.append(i + 1)
return ans
类似的题目是:
442. 数组中重复的数据
https://leetcode.cn/problems/find-all-duplicates-in-an-array
给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[2,3]
思路: 这里只需要记录当前访问位置是负数时候的index。因为表示这个Index+1的值已经访问过了。
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
ans = []
for i in range(len(nums)):
if nums[i] > 0:
a = nums[i] - 1
else:
a = -1 * nums[i] - 1
if nums[a] < 0:
ans.append( a + 1)
nums[a] *= -1
#print(nums)
return ans
896. 单调数列
https://leetcode.cn/problems/monotonic-array/
如果数组是单调递增或单调递减的,那么它是 单调 的。
如果对于所有 i <= j,nums[i] <= nums[j],那么数组 nums 是单调递增的。 如果对于所有 i <= j,nums[i]> = nums[j],那么数组 nums 是单调递减的。
当给定的数组 nums 是单调数组时返回 true,否则返回 false。
思路: 用两个bool记录递增或递减。如果两个bool都是False,那么就是不单调了。
class Solution:
def isMonotonic(self, nums: List[int]) -> bool:
inc = desc = True
for i in range(len(nums) - 1):
if nums[i] < nums[i+1]:
desc = False
elif nums[i] > nums[i+1]:
inc = False
return inc or desc
1539. 第 k 个缺失的正整数
https://leetcode.cn/problems/kth-missing-positive-number
给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。
请你找到这个数组里第 k 个缺失的正整数。
示例 1:
输入:arr = [2,3,4,7,11], k = 5
输出:9
解释:缺失的正整数包括 [1,5,6,8,9,10,12,13,…] 。第 5 个缺失的正整数为 9 。
思路: k+1表示当前的正整数存在,所以往后一位,推迟。
class Solution:
def findKthPositive(self, arr: List[int], k: int) -> int:
for i in arr:
if i <= k:
k += 1
return k
1608. 特殊数组的特征值
https://leetcode.cn/problems/special-array-with-x-elements-greater-than-or-equal-x
给你一个非负整数数组 nums 。如果存在一个数 x ,使得 nums 中恰好有 x 个元素 大于或者等于 x ,那么就称 nums 是一个 特殊数组 ,而 x 是该数组的 特征值 。
注意: x 不必 是 nums 的中的元素。
如果数组 nums 是一个 特殊数组 ,请返回它的特征值 x 。否则,返回 -1 。可以证明的是,如果 nums 是特殊数组,那么其特征值 x 是 唯一的 。
示例 1:
输入:nums = [3,5]
输出:2
解释:有 2 个元素(3 和 5)大于或等于 2 。
思路: 先降序排序,如果存在x,那么[0, x-1]一定都是大于等于x的,而或者x已在数组外,或者[x]一定是小于x的。
class Solution:
def specialArray(self, nums: List[int]) -> int:
nums.sort(reverse=True)
s = len(nums)
for i in range(1, s+1):
if nums[i - 1] >= i and (i == s or nums[i] < i):
return i
return -1