-
题目汇总
能完成:48/54/59/118/274/283/303/414/442/485/495/598/697/2656/2744
要优化:119/189/238/289
不会做:396/453
-
基础操作总结
插入元素:
1.list.append() #在列表末尾添加一个元素 2.list.extend() #在列表末尾添加至少一个元素 3.list.insert(idx,val) #在列表任意位置添加一个元素 4.切片 #通过替换的方式在列表任意位置添加至少一个元素
删除元素:
1.del list[i] del list[i:j] 2.list.pop(idx) #无指定位置时默认删除最后一个元素 3.list.remove(val) #删除和指定元素值相同的第一个元素 4.list.clear() #删除列表所有元素
复制列表:
1.直接赋值:list2 = list1 #浅拷贝 2.切片赋值:list2 = list1[:] #只对第一层实现深拷贝 3.list2 = list1.copy() #只对第一层实现深拷贝 list2 = copy.deepcopy(list1) #完全深拷贝 需要import copy #浅拷贝:list1和list2指向同一地址,同步改变 #深拷贝:list1和list2指向不同地址,互不影响
获取指定值的索引:list.index(val)
列表翻转:
1.list.reverse() 2.list = list[::-1]
转置实现:L = list(map(list, zip(*L)))
#以[[1, 2, 3],[4, 5, 6]]为例: # 1.拆解元素: list = *L = [1, 2, 3] [4, 5, 6] # 2.打包成元组: zip(*L) = [(1,4),(2,5),(3,6)] # 3.对指定序列的每个元素实施指定操作: map(list, zip(*L))) = [[1,4],[2,5],[3,6]
对列表的每个元素值进行相同操作:
#每个元素+1 1.for i in range(len(list)): list[i] = list[i] + 1 2.for i,val in enumerate(list): val = val + 1 3.map(lambda x:x+1, list) 4.[val + 1 for val in list]
实现两个列表的对应值相加:
1.[x + y for x, y in zip(list1, list2)] 2.for i in range(len(list1)): list1[i] = list1[i] + list2[i] 3.map(lambda x, y: x + y, list1, list2) #扩展lambda from functools import reduce reduce(lambda x, y: x + y, list) #列表求和 #reduce元素累积 sorted(list, key=lambda list: list[1], reverse=True) #根据列表元素的第二个元素进行降序排列 #sorted排序,key排序值,reverse是否降序排列 filter(lambda x: x % 3 == 0, list) #取出列表中3的倍数的元素并组成新列表 #filter过滤
补充:list操作对应的时间复杂度
list-列表常用操作和时间复杂度分析_void alistremovevalue(alist *list, const lelement -CSDN博客
-
基础数学知识
杨辉三角规律
①每个数等于它上方两数之和
②每一行的数据为组合数关系 Cnm = n!/m!(n-m)!
可推导出单行递推公式:Cnm=Cnm-1 * (n-m+1) / m
-
优化思路
119
给定一个非负索引
rowIndex
,返回「杨辉三角」的第rowIndex
行。思路一:在规律①的基础上输出整个杨辉三角,取出指定的第
rowIndex
行;优化点 :对 第i+1行 的计算仅用到 第i行的数据,可以使用 !!滚动数组!! ,只保留上一行数据来优化空间复杂度。
对 第i行第j个 的计算仅用到 第i-1行第j-1和j个 的数据,可以使用 !!倒叙计算!! 因为需要保证 list[j-1] 未被更新。
class Solution(object): def getRow(self, rowIndex): """ :type rowIndex: int :rtype: List[int] """ res = [1] * (rowIndex + 1) for i in range(2, rowIndex + 1): for j in range(i - 1, 0, -1): res[j] += res[j - 1] return res
思路二:在规律②的基础上推导出单行递推公式,直接输出第
rowIndex
行;class Solution(object): def getRow(self, rowIndex): res = [1] for i in range(1, rowIndex + 1): res.append(res[i - 1] * (rowIndex - i + 1) / i) return res
189
给定一个整数数组
nums
,将数组中的元素向右轮转k
个位置,其中k
是非负数。分析:轮转一共只有len(nums)种可能,先将k更新为对m取余的结果
思路一:通过切片再拼接得到输出结果
思路二:通过 for循环下的pop和insert得到输出结果
思路三(优化点):通过 !!三次翻转!! 得到输出结果
#以nums = [1,2,3,4,5,6,7], k = 3为例 #一次翻转:nums = [7,6,5,4,3,2,1] #二次翻转:nums = [5,6,7,4,3,2,1] #三次翻转:nums = [5,6,7,1,2,3,4] # 1.对整个数组实行翻转,保证后面后面元素移到列表前端 # 2.从k处分隔数组,左右两数组各自进行翻转,保证子数组内部的元素顺序 class Solution: def rotate(self, nums, k): """ :type nums: List[int] :type k: int :rtype: None Do not return anything, modify nums in-place instead. """ k %= len(nums) nums[:] = nums[::-1] nums[:k] = nums[:k][::-1] nums[k:] = nums[k:][::-1]
238
给你一个整数数组
nums
,返回 数组answer
,其中answer[i]
等于nums
中除nums[i]
之外其余各元素的乘积 。不能使用除法!!!思路一:双层for循环,将跳过
nums[i]
的乘积值放在answer[i]
思路二:一次遍历储存前后缀,前缀由前往后更新,后缀由后往前更新
优化点:一次遍历储存前缀,一次遍历用变量代替后缀,节省后缀的内存开销
class Solution(object): def productExceptSelf(self, nums): """ :type nums: List[int] :rtype: List[int] """ out = [1] right = 1 length = len(nums) for i in range(1, length): out.append(out[i-1]*nums[i-1]) for i in range(length-1,-1,-1): out[i] *= right right *= nums[i] return out
289
给定一个包含
m × n
个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1
即为 活细胞 (live),或0
即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
- 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
- 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
- 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
- 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你
m x n
网格面板board
的当前状态,返回下一个状态。分析:
m=1/n=1时,一头一尾格子内细胞全部死亡,剩余格子内活细胞要求周围两个格子均为活细胞才能保持状态,死细胞保持状态;
m>1/n>1时,四顶角格子k<=3(k=3:0-1/1-1;k=2:0-0/1-1;k<2:0-0/1-0)
四边格子除顶角k<=5 (k=3:0-1/1-1;k=2:0-0/1-1;k<2 or k>3:0-0/1-0)
剩余格子k<=8(k=3:0-1/1-1;k=2:0-0/1-1;k<2 or k>3:0-0/1-0)
由于出生死亡同时发生,则更新细胞状态中需要维持当前状态,故用额外空间保存更新状态
优化点: !!利用二进制定义复合状态!!(状态保持00=0,11=3,状态改变01=1 死亡,10=2 复活)
当前状态在低位下一状态在高位 是为了能统一在统计活细胞数量时改变的复合状态和初始状态的操作,比如邻域出现01(先活后死)和1(初始状态)时只要取低位就能获得细胞的当前状态;
思路:两层for循环遍历每个格子,统计每个格子周围的活细胞数量(&1 取低位),根据活细胞数量定义新状态(k<2ork>3 0-00/1-01,k=2 0-00/1-11,k=3 0-10/1-11);再次两层for循环遍历每个格子,将复合状态右移一位即得到下一个状态;
class Solution: def gameOfLife(self, board) """ Do not return anything, modify board in-place instead. """ if not board or not board[0]: return m, n = len(board), len(board[0]) for i in range(m): for j in range(n): cnt = self.count_alive(board, i, j) if cnt == 2 and board[i][j]: board[i][j] = 3 if cnt == 3: board[i][j] = 3 if board[i][j] else 2 for i in range(m): for j in range(n): board[i][j] >>= 1 def count_alive(self, board, i, j): #定义相对位置 m, n = len(board), len(board[0]) cnt = 0 directions = [(0, 1), (0, -1), (-1, 0), (1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)] for dx, dy in directions: x, y = i + dx, j + dy if x < 0 or y < 0 or x == m or y == n: #越界值不统计 continue cnt += board[x][y] & 1 return cnt
-
解题思路
396
给定一个长度为
n
的整数数组nums
。假设arrk
是数组nums
顺时针旋转k
个位置后的数组,我们定义nums
的旋转函数为:F(k) = 0*arrk[0]+ 1*arrk[1]+...+(n-1)*arrk[n -1]
返回
F(0), F(1), ..., F(n-1)
中的最大值 。分析:以 nums = [4,3,2,6] 为例
F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25
F(1) = (1 * 4) + (2 * 3) + (3 * 2) + (0 * 6) = 0 + 4 + 6 + 6 = 16
F(2) = (2 * 4) + (3 * 3) + (0 * 2) + (1 * 6) = 0 + 6 + 8 + 9 = 23
F(3) = (3 * 4) + (0 * 3) + (1 * 2) + (2 * 6) = 0 + 2 + 12 + 12 = 26
则F(1)-F(0) = 4+3+2-3*6,F(2)-F(1) = 4+3-3*2+6,F(3)-F(2) = 4-3*3+2+6
通过错位相减发现F(m)-F(m-1) = 4+3+2+6-4*nums[-m] = sum(nums)-len(nums)*nums[-m]
思路:一次遍历计算F(0),然后通过递推公式依次计算F(1)...F(n-1),只需要用到两个变量(一个保存当前F值,一个保存历史最大值)
class Solution(object): def maxRotateFunction(self, nums): """ :type nums: List[int] :rtype: int """ length = len(nums) summ = sum(nums) F = 0 for i in range(length): F += i * nums[i] maxx = F for i in range(1, length): F = F + summ - length * nums[-i] maxx = max(maxx, F) return maxx
453
给你一个长度为
n
的整数数组,每次操作将会使n - 1
个元素增加1
。返回让数组所有元素相等的最小操作次数。分析: !!
n - 1
个元素增加1
等价于 1个元素减少 1 !! 将问题转化成数组中每个数减少到最小值的操作数class Solution(object): def minMoves(self, nums): """ :type nums: List[int] :rtype: int """ time = 0 for val in nums: time += val - min(nums) return time