一给 发表于 2024-6-19 22:17:29

【leetcode10-21】子串、普通数组、矩阵

子串

560.和为K的子数组【没理解】

https://img-blog.csdnimg.cn/direct/beabf5e888ce4a25914444ed46d1cbde.png
   什么是前缀和:前缀和指一个数组的某下标之前的所有数组元素的和(包含其自身)
通常,会在前缀和首位放一个0。比如数组
前缀和通常可以帮助我们快速计算某个区间内的和。比如我们要算i,ji,ji,j之间的和,那么就是nums+nums+⋯+numsnums


[*]nums + \cdots +numsnums+nums+⋯+nums。他可以看作是nums+nums+⋯+nums+nums+⋯+numsnums
[*]nums + \cdots + nums + nums + \cdots +numsnums+nums+⋯+nums+nums+⋯+nums减去nums+nums+⋯+numsnums
[*]nums + \cdots + numsnums+nums+⋯+nums。这个式子也是preSum−preSumpreSum


[*]preSumpreSum−preSum。
class Solution:
    def subarraySum(self, nums: List, k: int) -> int:
      # 要求的连续子数组
      count = 0
      n = len(nums)
      preSum =

      # 求前缀和数组,第i位置代表nums前面i个相加,共有len(nums)+1长
      tmp = 0
      for i in range(n):
            tmp += nums
            preSum.append(tmp)
      
      # 求和为k的连续子数组,求i到j之间的和
      for i in range(1, n+1):
            for j in range(i, n+1):
                if preSum - preSum == k:# preSum - preSum代表着在nums数组中,前j个数之和减去前i-1个数之和
                  count += 1
      
      return count
class Solution:
    def subarraySum(self, nums: List, k: int) -> int:
      # 要求的连续子数组
      count = 0
      n = len(nums)
      preSums = collections.defaultdict(int)   #其键是前缀和,值是该前缀和出现的次数。
      preSums = 1

      presum = 0
      for i in range(n):
            presum += nums   
            # if preSums != 0:
            count += preSums   # 利用defaultdict的特性,当presum-k不存在时,返回的是0。这样避免了判断
            preSums += 1# 给前缀和为presum的个数加1
      return count
【暴力解法】
class Solution:
    def subarraySum(self, nums: List, k: int) -> int:
      # 要求的连续子数组
      count = 0
      n = len(nums)
      
      for i in range(n):
            sum = 0
            for j in range(i, n):
                sum += nums
                if sum == k:
                  count += 1
      return count
239.滑动窗口最大值【大顶堆】

https://img-blog.csdnimg.cn/direct/df254fcd650b4910b0218cec7372cc4f.png
代码随机录写过这道题:使用大顶堆
from collections import deque


class MyQueue: #单调队列(从大到小
    def __init__(self):
      self.queue = deque() #这里需要使用deque实现单调队列,直接使用list会超时
   
    #每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
    #同时pop之前判断队列当前是否为空。
    def pop(self, value):
      if self.queue and value == self.queue:
            self.queue.popleft()#list.pop()时间复杂度为O(n),这里需要使用collections.deque()
            
    #如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
    #这样就保持了队列里的数值是单调从大到小的了。
    def push(self, value):
      while self.queue and value > self.queue[-1]:
            self.queue.pop()
      self.queue.append(value)
      
    #查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
    def front(self):
      return self.queue
   
class Solution:
    def maxSlidingWindow(self, nums: List, k: int) -> List:
      que = MyQueue()
      result = []
      for i in range(k): #先将前k的元素放进队列
            que.push(nums)
      result.append(que.front()) #result 记录前k的元素的最大值
      for i in range(k, len(nums)):
            que.pop(nums) #滑动窗口移除最前面元素
            que.push(nums) #滑动窗口前加入最后面的元素
            result.append(que.front()) #记录对应的最大值
      return result

76.最小覆盖子串【双指针|滑动窗口】【困难】

https://img-blog.csdnimg.cn/direct/f135c009a7fd4f08837f5653814a77e3.png
   
[*]用need字典维护,当前还需要的字符以及个数,need为负数,代表无需求,need代表需要
[*]滑动串口,先让right动起来,左指针指向队首,如果能cover字符T;就开始紧缩窗口,让left滑动,直至不能coverT
[*]在窗口滑动过程中,维护的need也要变,参加字符,就–,减去字符就+
如果实验访问一个在 defaultdict 中不存在的键,它会自动创建一个新键,并将其值设置为默认值(在这个例子中是 0)。但是{}不支持自动创建键
    def minWindow(self, s: str, t: str) -> str:
      need=collections.defaultdict(int)
      for c in t:
            need+=1
      needCnt=len(t)
      left=0
      res=(0,float('inf'))
      
      for index,c in enumerate(s):
            if need>0:#如果需要字母c
                needCnt-=1
            need-=1
            if needCnt==0:       #步骤一:滑动窗口包含了所有T元素
                while True:      #步骤二:增加left,排除多余元素
                  c=s
                  if need==0:
                        break
                  need+=1
                  left+=1
                if index-left<res-res:   #记录结果,当前窗口左指针left,右指针index
                  res=(left,index)
                need]+=1#步骤三:left增加一个位置,寻找新的满足条件滑动窗口
                needCnt+=1
                left+=1
      return '' if res>len(s) else s:res+1]    #如果res始终没被更新过,代表无满足条件的结果

普通数组

53.最大子数组和【动态规划】

https://img-blog.csdnimg.cn/direct/ba2f3c86a4914fcd9fb7a20c17eddc8e.png
   https://img-blog.csdnimg.cn/direct/816b14bc6aa245d4b9871fdf1ef41aed.png
由于dp只与dp和nums有关,因此直接在nums原地修改,空间复杂度O(1)
class Solution:
    def maxSubArray(self, nums: List) -> int:
      for i in range(1,len(nums)):
            nums = max(nums+nums,nums)
      return max(nums)
56.合并区间

https://img-blog.csdnimg.cn/direct/48d834e9d6f24c9a9e47f7f37f55fc8f.png
   
[*]先对左节点排序
[*]判断当前合并区间和候选区间,是否重叠
class Solution:
    def merge(self, intervals: List]) -> List]:
      ans = []
      intervals.sort()# 按照所有区间的左端点进行排序
      for interval in intervals:
            if not ans or ans[-1] < interval:   #当ans为空,或者 当前区间的右节点 在 候选区间的左边【无重叠】
                ans.append(interval)
            else: #当前并区间和候选区间有重叠
                ans[-1] = max(interval,ans[-1])   #取最大右区间
      return ans
189.轮转数组

https://img-blog.csdnimg.cn/direct/6e8ce50def3d4ed8a1b62145d29d6910.png
   直接用nums会报错??
修改nums[:]不会影响到nums,nums[;]是一个新列表,是nums的副本,她两指向差别内存地点
class Solution:
    def rotate(self, nums: List, k: int) -> None:
      """
      Do not return anything, modify nums in-place instead.
      """
      k = k % len(nums)
      nums[:] = nums + nums[:len(nums)-k]
      return nums
238.除自身以外数组的乘积

https://img-blog.csdnimg.cn/direct/875b13f4bdc74e4eb69918e3df41dbc5.png
   https://img-blog.csdnimg.cn/direct/cf1c79dab25340f092ce181d2cd00712.png

[*]先初始化ans,ans=1;辅助变量temp=1
[*]计算下三角,计算上三角乘积temp,并乘以上三角
索引容易搞错,可以看个图,根据图写索引
class Solution:
    def productExceptSelf(self, nums: List) -> List:
      ans = * len(nums)
      temp = 1
      for i in range(1,len(nums)):
            ans = ans * nums#下三角
      for j in range(len(nums)-2,-1,-1):
            temp *= nums   #上三角
            ans *= temp   #下三角 * 上三角
      return ans
41.缺失的第一个正数【困难】

https://img-blog.csdnimg.cn/direct/fcaeaef2eb3a4637a38ba1ba56c30169.png
   最后的结果肯定是在 内
修改 nums,使对应的下标 里 nums 第一个不是 i+1 的,i+1 就是答案
也就是,让 nums 里的数字,在 内的,都去他们对应的 位置上去的
class Solution:
    def firstMissingPositive(self, nums: List) -> int:
      n = len(nums)
      for i in range(n):
            while 1 <= nums <= n and nums - 1] != nums:
                # 这是错误的
                # nums, nums - 1] = nums - 1], nums
         #先计算右边的值,也就是nums和nums - 1]的值,然后将他们赋值给一个临时元祖;
#然后按顺序赋值给左边,也就是说会先修改nums的值,这样一来,nums - 1就不是原来想要修改的下标了。
                nums - 1], nums = nums, nums - 1]
      for i in range(n):
            if nums != i + 1:
                return i + 1
      return n + 1

矩阵

73.矩阵置0

https://img-blog.csdnimg.cn/direct/ac17cd5bd77242e7bd4d55e84e95243d.png
   两遍扫matrix,第一遍用集合记录哪些行,哪些列有0;第二遍置0
class Solution:
    def setZeroes(self, matrix: List]) -> None:
      """
      Do not return anything, modify matrix in-place instead.
      """
      row = len(matrix)
      col = len(matrix)
      row_zero = set()
      col_zero = set()
      for i in range(row):
            for j in range(col):
                if matrix == 0:
                  row_zero.add(i)
                  col_zero.add(j)
      for i in range(row):
            for j in range(col):
                if i in row_zero or j in col_zero:
                  matrix = 0
               
54.螺旋矩阵

https://img-blog.csdnimg.cn/direct/7cb2da980a2848a4844925ee6e28a498.png
   https://img-blog.csdnimg.cn/direct/b757d7b659534668b424fe417141bf66.png
class Solution:
    def spiralOrder(self, matrix: List]) -> List:
      if not matrix: return []

      left, right, top, bottom = 0, len(matrix) - 1, 0, len(matrix) - 1
      res = []
      while True:
            for i in range(left, right + 1):
                res.append(matrix) #从左上角 到 右上角
            top += 1
            if top > bottom:
                break

            for i in range(top, bottom + 1):
                res.append(matrix) # 从右上角 到 右下角
            right -= 1
            if left > right:
                break

            for i in range(right, left - 1, -1):
                res.append(matrix) # 从右下角 到左下角
            bottom -= 1
            if top > bottom:
                break

            for i in range(bottom, top - 1, -1):
                res.append(matrix) #从左下角 到 左上角
            left += 1
            if left > right:
                break
      return res


48.旋转图像

https://img-blog.csdnimg.cn/direct/3a5ab915934c491dade1d2750952a47e.png
   https://img-blog.csdnimg.cn/direct/74e061dfa5b244dea4bd1b0fa813d12f.png
方法一:借助一个辅助矩阵temp暂存原矩阵
方法二:原地修改。一轮可以完成矩阵 4 个元素的旋转。因而,只要分别以矩阵左上角 1/41/41/4 的各元素为起始点实行以上旋转操纵,即可完整实现矩阵旋转。【当矩阵大小n为偶数,就取n//2行,n//2列原始为起始点;矩阵大小n为奇数,取前n//2行,(n+1)//2列为起始点
https://img-blog.csdnimg.cn/direct/7052e35853014e0b9d4c0b20002ed11a.png
class Solution:
    def rotate(self, matrix: List]) -> None:
      """
      Do not return anything, modify matrix in-place instead.
      """
      n = len(matrix)
      temp = copy.deepcopy(matrix)   # 深拷贝 matrix -> tmp
      for i in range(n):
            for j in range(n):
                matrix = temp   # 根据元素旋转公式,遍历修改原矩阵 matrix 的各元素
class Solution:
    def rotate(self, matrix: List]) -> None:
      """
      Do not return anything, modify matrix in-place instead.
      """
      n = len(matrix)
      for i in range(n//2):
            for j in range((n+1)//2):
                temp = matrix
                matrix = matrix
                matrix = matrix
                matrix = matrix
                matrix = temp
240.搜刮二维矩阵||

   https://img-blog.csdnimg.cn/direct/270b19c19e274530a1d74b3776e21ee0.png
https://img-blog.csdnimg.cn/direct/5f705eabfa5441d9b589beade6ec7185.png
class Solution:
    def searchMatrix(self, matrix: List], target: int) -> bool:
      i, j = len(matrix)-1, 0
      while i>=0 and j < len(matrix):
            if matrix < target:
                j += 1
            elif matrix > target:
                i -= 1
            else:
                return True
      return False


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【leetcode10-21】子串、普通数组、矩阵