数组和字符串-22
数组简介-3
寻找数组的中心索引,简单
搜索插入位置,简单
合并区间,中等
对区间列表根据左端点排序:
intervals.sort(key=lambda x: x[0])
intervals = sorted(intervals, key=lambda x:x[0])
对二维列表 lst 根据第 i 列进行排序:
lst.sort(key=lambda x: x[i])
lst = sorted(lst,key=lambda x:x[0])
注意:
lst.sort()
是在原列表上进行排序,不需要返回sorted(lst)
是返回排序后的列表,需要重新赋值二维数组简介-3
旋转矩阵,中等
两种方法:
方法一:将原矩阵四等分为四块,每块小矩阵均顺时针旋转90°并移动到下一块的位置。
将原地旋转的问题转化为四个小块分别移动且旋转的问题,只要有移动,就只需要常数个额外空间
注:Python中写交换不用引入临时变量
直接a , b = b , a
、a , b , c , d = b , c , d , a
即可
方法二:翻转法
顺时针旋转90° = 水平翻转一次 + 沿主对角线翻转一次 = 竖直翻转一次 + 沿副对角线翻转一次
可以直接将奇偶数情况合成一段代码
零矩阵,中等
对角线遍历,中等
遍历第一行和最后一列,作为每一次对角线遍历的起点
每次对角线遍历存入一个临时列表,根据对角线条数的奇偶性决定临时列表是否翻转
将翻转(不一定)处理过的列表extend到答案列表 lst 里,最后返回 lst
字符串简介-4
最长公共前缀,简单
逐位比较,有不同的直接返回
在字符串末尾增加某个字符用str = str + char
用列表作为输入的题都要先判断列表是否为空再继续写
Python中判断列表为空的语句:if not lst: return xxx
空列表的 bool 值为 False,非空列表为 True
取字符串子串的方法:str[a:b]
a 表示起点,可以空着,b表示终点之后,也可以空着
最长回文子串,中等
Python 给列表赋初值:resubstr = [[False for i in range(n)] for j in range(n)]
方法一:动归
初始值:单字符是回文串,两个相同字符是回文串
循环遍历:根据 子串长度从小到大遍历
最后的答案要返回一个最长回文子串,需要从0开始比较每次True的回文串是不是比答案长,不要遗漏一个字符和两个字符的情况
方法二:中心扩展
从方法一的边界条件,也就是单字符和双字符的情况开始,双向扩展,知道两边的新字符不同或到达字符串头尾停止
翻转字符串里的单词,中等
去除字符串收尾空格 [ 其他字符 ]:str.strip(['其他字符'])
将字符串按空格 [ 其他字符 ] 划分存入列表:lst = str.split([其他字符])
官解用了join方法,就一行:
join方法的语法: "单词间的间隔".join(被连接的字符(串)列表对象)
,有返回值
reversed方法:reversed(需要翻转的迭代器)
,有返回值
class Solution:
def reverseWords(self, s: str) -> str:
return " ".join(reversed(s.split()))
进阶:尝试使用 O(1) 额外空间复杂度的原地解法。
不会
实现 strStr(),简单
用Python的 str.find(substr)
可以直接秒杀
自己写:
暴力逐一比较,外层循环只需要执行 len1 - len2 + 1 次,复杂度O(mn)
需要考虑要查找的子串比主串更长的情况
双指针技巧-6
双向双指针
翻转字符串,简单
从两头开始依次交换
数组拆分I,简单
排序取奇数位置的数求和
两数之和 II - 输入有序数组,简单
暴力时间复杂度O(n²)
方法一:二分查找,时间复杂度O(nlongn)
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
n = len(numbers)
for i in range(n):
low, high = i + 1, n - 1
while low <= high:
mid = (low + high) // 2
if numbers[mid] == target - numbers[i]:
return [i + 1, mid + 1]
elif numbers[mid] > target - numbers[i]:
high = mid - 1
else:
low = mid + 1
方法二:双指针,时间复杂度O(n)
题目假设唯一解,则在数组有序的情况下,假设解为 ( x , y ) ,i , j 从两边开始遍历时,假如解 ( i , j ) 的值比 target 小了,则一定有 i < x ,应该继续加大 i ,如果加大 j ,则退回了之前遍历过的情况,一定不会得到 target 。同理假如 ( i , j ) 的值比 target 大了,则应该继续减小 j 。
结合:二分查找结合双指针,时间复杂度最好O(logn),最坏O(n)
单向双指针
移除元素,简单
根据题目描述直接对列表进行修改
最大连续1的个数,简单
长度最小的子数组,中等
这道题如果每次重新对子列表求和的话,复杂度至少为O(nlogn)
使用双指针维护一个唯一的字列表和,前指针增加新元素,后指针减少子列表头元素,复杂度降低为O(n)
小结部分-6
杨辉三角,简单
双层循环,处理好边界,复杂度O(N²)
杨辉三角 II,简单
单求第k层的各个元素,空间复杂度优化至 O(k) 的方法:
维护一个临时数组,杨辉三角的每一层等于两个错一位的上一层相加
比如 [ 1,3,3,1 ] ==> [ 0,1,3,3,1 ] + [ 1,3,3,1,0 ] = [ 1,4,6,4,1 ]
反转字符串中的单词 III,简单
res = s[::-1]
可以得到反转的字符串寻找旋转排序数组中的最小值,中等
class Solution:
def findMin(self, nums: List[int]) -> int:
n = len(nums)
left = 0
right = n-1
while right >= left:
mid = (left + right)//2
if nums[mid] >= nums[left]:
if nums[mid] <= nums[right]:
return nums[left]
else:
left = mid + 1
else:
right = mid
left += 1
直接根据右边端点和中点的大小关系讨论,可以减少为两种情况:
class Solution:
def findMin(self, nums: List[int]) -> int:
n = len(nums)
left = 0
right = n-1
while right > left:
mid = (left + right)//2
if nums[mid] < nums[right]:
right = mid
else:
left = mid + 1
return nums[left]
删除排序数组中的重复项,简单
简单的同向双指针,跟双指针那道“去除元素”做法一样
移动零,简单
用双指针
一开始的思路是每次给左边的指针赋值右边的非零值,右边指针遍历一遍后,左边指针再继续遍历数组,将剩余位置的零补全。这样最优情况需要遍历一遍,最差情况需要遍历两遍。
优化为:每次检测到非零数,左右两指针的值交换。这样无论最优还是最差都只需遍历一遍