【算法】剑指 Offer 专项突击版 Day4数组部分
题目地址:https://leetcode-cn.com/study-plan/lcof/?progress=wgzvtig
目标:要点总结,分享思路
注:在合理的条件下仅采用理解起来最简单,用起来实用的代码实现
文章目录
I 【中等】010. 和为 k 的子数组
难度:普通,要理解一下就好,笔者最开始对于题解给出的前缀和有点懵
要点:
- 思路:先按照暴力求解方法去理解题目,这道题可以构造前缀和数组presum[],这样presum[j]-presum[i]==k的双重循环就可以求解了,时间复杂度 O ( n 2 ) O(n^2) O(n2)
- 优化思路1:连续子数组,可不可以用滑动窗口解决,尝试后不行,因为有负数。这样在滑动窗口中无法确定到底是改滑动左指针还是右指针使其满足窗口之和
- 优化思路2:前缀和数组用哈希表存储,边构造边寻找
引用于刷穿剑指offer-Day07-数组III-010.和为k的子数组 前缀和的思路讲解)
- 个人解释(通俗解释,看懂上面的请跳过):在众多题解中这篇最简洁清晰,但个人还是不理解这里的哈希表是怎么存储到前缀和数组i和j的差值的。详细解释如下
class Solution:
def subarraySum(self, nums: List[int], target: int) -> int:
presum = 0 # 前缀和
dic = {0:1} # dic[key]:value,代表前缀和key出现的次数
ans = 0
for num in nums:
presum += num
# presum - target 表示以起始点到当前num为终点的前缀和比target多出的距离
# 如果在前面点中找到刚好等于这段距离的前缀,那么就找到了路径解
ans += dic.get(presum-target,0)
#
dic[presum] = dic.get(presum,0) + 1
return ans
II 【中等】011. 0 和 1 个数相同的子数组
难度:有上一题作为基础,该题转换思路后简单
要点:
- 思路:数组中仅有0和1,不做任何更改滑动窗口也无法使用,因为右指针右移多个0和左指针右移少个0的效果是相同的,无法确定指针移动方向即滑窗。那为什么不直接使用前缀和算法?(笔者当时自问自答的时候懵了) 同样若直接使用前缀和会出现该怎么确定前缀和等于多少时条件成立
- 重点:将0换成-1就可以使用前缀和了,这样只要前缀和为0就满足条件了,题目转换为前缀和为0的最长子数组。
- 那更改后能用滑动窗口了吗,不能,即使全部改为正数,满足滑窗滑动要求,但是滑窗内的数字之和为多少才能满足条件呢?
class Solution:
def findMaxLength(self, nums: List[int]) -> int:
ans = 0
dic = {0:-1} # 当前缀和等于0时,说明已经满足要求,直接i+1即可
presum = 0
for i,num in enumerate(nums):
if not num:num=-1 # 0转-1
presum += num
# 这里用else才对哈希表赋值可以保证仅更新最早的点,这样得到的长度最大
# 同时这道题如果变种为求子数组长度最小在这里调整无条件字典赋值即可
if presum in dic:
ans = max(ans,i-dic.get(presum))
else:
dic[presum] = i
return ans
II 【简单】012. 左右两边子数组的和相等
难度:简单,前缀和问题
要点:
- 思路:引自官方题解
class Solution:
def pivotIndex(self, nums: List[int]) -> int:
sums = sum(nums)
presum = 0
for i,num in enumerate(nums):
leftSum = presum
rightSum = sums-leftSum-num
if leftSum == rightSum:
return i
presum += num
return -1
II 【中等】013. 二维子矩阵的和
难度:
要点:
- 思路:引用于
图解前缀和,思路简明,注释全
- 因此本题就变成了如何求二维矩阵的前缀和矩阵(个人理解有点模板题的味儿)
# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)
class NumMatrix:
def __init__(self, matrix: List[List[int]]):
rows,cols = len(matrix),len(matrix[0]) if matrix else 0
sums = [[0] * (cols+1) for _ in range(rows+1)]
for i in range(rows): # y轴向下
for j in range(cols): # x轴向右
# 求二维矩阵的前缀和
sums[i+1][j+1] = sums[i][j+1] + sums[i+1][j] - sums[i][j] + matrix[i][j]
self.sums = sums
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
_sums = self.sums
return _sums[row2 + 1][col2 + 1] - _sums[row1][col2 + 1] - _sums[row2 + 1][col1] + _sums[row1][col1]