【力扣hot100】刷题笔记Day6

前言

  • 今天是社畜开工第一天,刷题刷题刷题💪

53. 最大子数组和 - 力扣(LeetCode)

  • 贪心法

    • 连续子数组累加和小于零就重新累加,【代码随想录】刷题笔记Day34-CSDN博客
    • class Solution:
          def maxSubArray(self, nums: List[int]) -> int:
              count = 0
              res = float('-inf')  # 整数最小值
              for num in nums:
                  count += num
                  res = max(res, count)
                  if count < 0:  # 小于0就重新累加
                      count = 0
              return res
  •  动态规划法

    • dp[i]表示以i结尾的最大连续子数组和,【代码随想录】刷题笔记Day52-CSDN博客
    • class Solution:
          def maxSubArray(self, nums: List[int]) -> int:
              dp = [0] * len(nums)
              dp[0], res = nums[0], nums[0]
              for i in range(1, len(nums)):
                  dp[i] = max(dp[i-1]+nums[i], nums[i])
                  res = max(res, dp[i])
              return res

 56. 合并区间 - 力扣(LeetCode)

  • 排序 + 一次遍历

    • 思路见【代码随想录】刷题笔记Day38-CSDN博客
    • 直接sort按照第一个元素大小,放进第一个区间,判断res[-1]右和新加入的左更新
    • class Solution:
          def merge(self, intervals: List[List[int]]) -> List[List[int]]:
              intervals.sort()  # 默认第一个元素,从小到大
              # intervals.sort(key=lambda x: x[1], reverse=True)  # 第二元素,从大到小
              res = [intervals[0]]  # 先放进第一个区间
              # 遍历剩余区间,不重叠就加入结果,重叠则更新右区间
              for left, right in intervals[1:]:
                  if res[-1][1] < left:
                      res.append([left, right])
                  else:
                      res[-1][1] = max(res[-1][1], right)
              return res

 189. 轮转数组 - 力扣(LeetCode)

  • 额外数组

    • class Solution:
          def rotate(self, nums: List[int], k: int) -> None:
              # 方法 1
              # k = k % len(nums)
              # nums[:] = nums[-k:] + nums[:-k]
              # 方法 2
              n = len(nums)
              newArr = [0] * n
              for i in range(n):
                  newArr[(i + k) % n] = nums[i]
              nums[:] = newArr[:]    
  • 利用队列

    • class Solution:
          def rotate(self, nums: List[int], k: int) -> None:
              for i in range(k):
                  nums.insert(0, nums.pop())
  • 三次翻转

    • 思路类似【代码随想录】刷题笔记Day13-CSDN博客里的左旋转字符串

    • class Solution:
          def rotate(self, nums: List[int], k: int) -> None:
              # 方法1:利用Python数组复制翻转,O(n)
              n = len(nums)
              k %= n  # 取余使得k小于n
              nums[:] = nums[::-1]
              nums[:k] = nums[:k][::-1]
              nums[k:] = nums[k:][::-1] 
      
              # 方法2:定义一个函数用于[i,j]范围内的翻转,O(1)
              def reverse(i, j):
                  while i < j:
                      nums[i], nums[j] = nums[j], nums[i]
                      i += 1
                      j -= 1
              n = len(nums)
              k %= n  # 取余使得k小于n
              reverse(0, n - 1)  # 全部翻转
              reverse(0, k - 1)  # 前翻转
              reverse(k, n - 1)  # 后翻转
  • 环状替换

    • 先求k和n的最大公约数g,遍历前g个数,环状向后跳k格进行交换直到回到最初位置,详细数学证明见官方题解
    • class Solution:
          def rotate(self, nums: List[int], k: int) -> None:
              # gcd求最大公约数
              def gcd(x, y) -> int:
                  return x if y == 0 else gcd(y, x % y)
      
              n = len(nums)
              k %= n  # 优化,取余使得k小于n
              g = gcd(n, k)
      
              # 一共有公约数g个环,前g个元素循环后跳直到回到开始位置
              for start in range(g):
                  current = start     # 记录开始下标
                  prev = nums[start]  # 记录上一个数
                  while True:        
                      next_idx = (current + k) % n  # 计算跳到哪里
                      nums[next_idx], prev = prev, nums[next_idx]  # 交换
                      current = next_idx   # 更新当前坐标
                      if current == start:  # 回到原点就退出
                          break

238. 除自身以外数组的乘积 - 力扣(LeetCode)

  • 前缀积 × 后缀积

    • 遍历两次,第一次用res记录前缀积,第二次用tmp记录后缀积,更新res
    • class Solution:
          def productExceptSelf(self, nums: List[int]) -> List[int]:
              """
              原数组:       [1       2       3       4]
              左部分的乘积:   1       1      1*2    1*2*3
              右部分的乘积: 2*3*4    3*4      4      1
              结果:        1*2*3*4  1*3*4   1*2*4  1*2*3*1
              """
              res, temp = [1] * len(nums), 1
              for i in range(1, len(nums)):  # 1 → n-1
                  res[i] = res[i-1] * nums[i-1]  # 前缀积
              for i in range(len(nums)-2, -1, -1):  # n-2 → 0
                  temp *= nums[i+1]  # 后缀积
                  res[i] *= temp  # 乘得结果
              return res

41. 缺失的第一个正数 - 力扣(LeetCode)

  • 建立新哈希表(空间复杂度O(n))

    • 把数组放入哈希表set中,从1开始查有没有在数组里,没有就返回i
    • class Solution:
          def firstMissingPositive(self, nums: List[int]) -> int:
              num_set = set(nums)
              for i in range(1, len(nums) + 1):
                  if i not in num_set:
                      return i
              return len(nums) + 1
  •  排序查找(时间复杂度O(nlgn))

    • 先排序,依次递增查找(跳过非正整数和重复值),相等递增不相等break返回值
    • class Solution:
          def firstMissingPositive(self, nums: List[int]) -> int:
              nums.sort()  # 排序就是O(nlogn)
              n = len(nums)
              res = 1
              for i in range(n):
                  if nums[i] <= 0 or nums[i] == res - 1:
                      continue  # 跳过非正整数和重复值
                  else:
                      if nums[i] == res:
                          res += 1  # 相等就继续递增
                      else:
                          return res  # 不相等就返回缺失正数
              return res
  • 原地标记

    • 第一遍把小于等于0的数变成n+1,第二遍将绝对值<=n的数对应的n-1位置变成负数(打上标记),第三遍找正数(说明没在对应位置上)

    • class Solution:
          def firstMissingPositive(self, nums: List[int]) -> int:
              n = len(nums)
              # 把小于等于0的数变成n+1
              for i in range(n):
                  if nums[i] <= 0:
                      nums[i] = n + 1
              # 将绝对值<=n的数对应的n-1位置变成负数(打上标记)
              for i in range(n):
                  num = abs(nums[i])
                  if num <= n:
                      nums[num - 1] = -abs(nums[num - 1])
              # 遍历找正数(说明没在对应位置上)
              for i in range(n):
                  if nums[i] > 0:
                      return i + 1
              # 都是负数说明缺失n+1
              return n + 1
  • 原地哈希

    • 参考这个题解,从头遍历到尾不停交换,判断在下标范围内并且和数-1的位置不同,就交换使得将nums[i]放在下标为nums[i]-1的位置上,最后再扫一遍找出异常值即可
    • class Solution:
          def firstMissingPositive(self, nums: List[int]) -> int:
              size = len(nums)
              for i in range(size):
                  # 先判断这个数字是不是索引,然后判断这个数字是不是放在了正确的地方
                  while 1 <= nums[i] <= size and nums[i] != nums[nums[i] - 1]:
                      temp = nums[i] - 1  # 防止交换出错
                      nums[i], nums[temp] = nums[temp], nums[i] 
      
              for i in range(size):
                  if i + 1 != nums[i]:
                      return i + 1
      
              return size + 1

后言

  • 刷了一整天的题了,脑子要炸了,但是也很充实,休息休息,晚上接npy咯 

  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值