力扣刷题4.22

2024-04-23 02:20
文章标签 力扣 刷题 4.22

本文主要是介绍力扣刷题4.22,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

88. 合并两个有序数组

解题思路:
双指针加单指针
同时从后往前遍历原始的nums1和2,比较大小,大的往后站。

class Solution:def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:"""Do not return anything, modify nums1 in-place instead."""# 初始化双指针,还有全局指针index1, index2, index = m-1, n-1, m+n-1# 从后往前遍历while index1 >= 0 and index2 >= 0:# 如果nums1的元素大,就放在最后if nums1[index1] > nums2[index2]:nums1[index] = nums1[index1]index1 -= 1else:nums1[index] = nums2[index2]index2 -= 1index -= 1# nums2有剩余元素if index2 >= 0:nums1[:index2+1] = nums2[:index2+1]return(nums1)

当面对 “合并两个有序数组” 的任务时,特别是在给定 nums1 中有足够的空间来容纳 nums2 中的所有元素这一约束条件下,我们可以通过一个有效的原地(in-place)合并方法来实现。这里的 “原地” 指的是不使用额外的空间来存储大量的数据,仅利用输入数组的空间。我们从后向前填充 nums1,这样做可以避免在合并时覆盖 nums1 中尚未处理的元素。下面是详细的步骤说明:

算法步骤

  1. 初始化指针

    • index1 指向 nums1 中最后一个有效元素的位置,即 m-1
    • index2 指向 nums2 中最后一个元素的位置,即 n-1
    • index 指向 nums1 的最末尾位置,即 m + n - 1。这是合并后的数组的最后一个位置。
  2. 从后向前比较并合并

    • index1 >= 0index2 >= 0 时,比较 nums1[index1]nums2[index2]
      • 如果 nums1[index1] 大于等于 nums2[index2],则将 nums1[index1] 放在 nums1[index] 的位置上,然后 index1 减一。
      • 如果 nums1[index1] 小于 nums2[index2],则将 nums2[index2] 放在 nums1[index] 的位置上,然后 index2 减一。
    • 每次操作后,index 减一,以准备下一个位置的填充。
  3. 处理剩余元素

    • 如果 nums2 中还有未合并的元素(当 index2 >= 0 时),直接将这些剩余元素复制到 nums1 的前面部分,即从 nums1[0]nums1[index2](因为 index2 未被合并的部分恰好表示还需要合并多少元素)。
  4. 完成合并

    • 在上述步骤完成后,nums1 就包含了完全合并后的有序数组。

示例

假设 nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3

  • 初始状态:

    • nums1 = [1, 2, 3, 0, 0, 0]
    • nums2 = [2, 5, 6]
  • 处理过程:

    • 比较 36,将 6 放在最后,更新数组为 [1, 2, 3, 0, 0, 6]
    • 比较 35,将 5 放在倒数第二的位置,更新数组为 [1, 2, 3, 0, 5, 6]
    • 比较 32,将 3 放在倒数第三的位置,更新数组为 [1, 2, 3, 3, 5, 6]
    • 比较 22,将 2 放在倒数第四的位置,更新数组为 [1, 2, 2, 3, 5, 6]
    • 处理完成,没有剩余元素需要特殊处理。

169. 多数元素

解题思路1:哈希表计数,再找到最大的。

class Solution:def majorityElement(self, nums: List[int]) -> int:# 添加哈希表元素_dict = {}for i in nums:if i not in _dict:_dict[i] = 1else:_dict[i] += 1# 遍历哈希表,找到最大的max_num = 0max_can = 0for key,value in _dict.items():if value > max_num:max_num = valuemax_can = keyreturn max_can

解题思路2:
摩尔投票算法

class Solution:def majorityElement(self, nums: List[int]) -> int:# 将多数元素与非多数元素一起成对消除,最后留下的就是多数# 初始化计数和候选count = 0candicate = None# 遍历for num in nums:# 如果此前多数元素消除完了,就拿当前的作为多数if count == 0:candicate = num# 计数更新count += (1 if candicate == num else -1)return candicate

这段代码实现了一个寻找数组中多数元素的算法,使用的是摩尔投票算法(Boyer-Moore Voting Algorithm)。这个算法特别适用于找出一个数组中出现次数超过半数的元素。下面是算法的步骤解释:

算法步骤

  1. 初始化

    • 设置一个计数器 count,初始值为0。
    • 设置一个变量 max_n 用于存储可能的多数元素,初始值为 None
  2. 遍历数组

    • 对数组 nums 中的每个元素 num 进行迭代。
  3. 确定候选元素

    • 当计数器 count 为0时,将当前遍历到的元素 num 设为新的候选多数元素,并将 max_n 设置为这个元素。
    • 此步骤确保如果之前的候选元素不是真正的多数元素,可以被更有可能的候选者替换。
  4. 更新计数器

    • 如果当前元素 num 等于候选多数元素 max_n,计数器 count 加1。
    • 否则,计数器 count 减1。
    • 这一步的逻辑是:每遇到一个与 max_n 相同的元素,就增加它的权重;每遇到一个不同的元素,就减少它的权重。这样做的目的是抵消那些非多数元素的影响。
  5. 返回结果

    • 遍历完成后,max_n 中存储的就是数组的多数元素。这是基于问题描述中的假设,即一定存在一个多数元素。

代码功能

这个算法非常高效,只需要一次遍历(时间复杂度为 (O(n))),并且只使用了常数空间(空间复杂度为 (O(1)))。算法的核心在于通过计数器的增减来维护当前可能的多数元素,其基本假设是多数元素的数量比其他所有元素的数量总和还要多,因此最终 max_n 中存储的元素必然是真正的多数元素。

应用场景

这种算法适用于需要从一个大数据集中快速确定主要趋势或者占优势数量的元素的场景,如社交媒体数据分析、市场调研等领域中的统计分析。

136. 只出现一次的数字

要求常量空间内解决。所以思路1是不行的。
思路1:
新建一个list,遍历nums,有相同的就去掉原来的相同的,这样留下的就是所求。
也可以使用哈希表辅助。

class Solution:def singleNumber(self, nums: List[int]) -> int:# 假设第一个是res = []for i in nums:if i not in res:res.append(i)else:res.remove(i)return sum(res)

正确解法:

位运算。

class Solution:def singleNumber(self, nums: List[int]) -> int:# 结果假设res = 0# 遍历,形成连乘的异或运算for num in nums:res ^= numreturn res

位运算由于其独特的性质,在解决编程问题,特别是在竞赛和面试中经常被用来简化解决方案或提高运算效率。以下是一些重要的位运算性质,特别强调了异或运算(XOR),这些性质可以帮助你更好地理解和运用位运算解决实际问题:

通用性质

  1. 零的规律

    • 任何数与0进行按位与、按位或和按位异或操作的结果:
      • a & 0 = 0
      • a | 0 = a
      • a ^ 0 = a
  2. 自身规律

    • 任何数与自身进行按位与、按位或和按位异或操作的结果:
      • a & a = a
      • a | a = a
      • a ^ a = 0(异或的重要性质)
  3. 按位取反

    • ~a 等于 -a - 1(在二进制表示中,所有位数取反)

异或运算(XOR)的特殊性质 异或运算是位运算中极具特色的一种,它在算法问题中尤为常见,具有以下几个重要性质:

  1. 反身性

    • 任何数与自己异或的结果为0,即 a ^ a = 0
  2. 恒等性

    • 任何数与0异或仍然为自己,即 a ^ 0 = a
  3. 交换律和结合律

    • a ^ b = b ^ a
    • a ^ (b ^ c) = (a ^ b) ^ c
    • 这意味着多个数异或的结果与顺序无关。
  4. 自反性

    • 如果 a ^ b = c,那么 a ^ c = b 也成立,且 b ^ c = a。这意味着异或操作可以用来在不使用第三个变量的情况下交换两个数。

应用场景举例

  1. 找出唯一的单一数字

    • 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。可以通过对所有元素进行异或操作解决,因为成对的数字会通过
      a ^ a = 0 消除,剩下的就是唯一的单一数字。
  2. 交换两个变量

    • 不使用临时变量交换两个数:a ^= b; b ^= a; a ^= b; 这样就完成了 ab 的交换。
  3. 构建简单的加密和解密

    • 由于 a ^ b = c 可逆,c ^ b = a,可以使用异或来对数据进行简单的加密和解密。

56. 合并区间

解题思路:
合并区间排序,一定要以元素的左边界排序!
比如这样的情况 处理 [2, 3] 和 [1, 4],应该合并为[1,4],但是按右边界的话,就是[2,3],[1,4],就变成了[2,4],这是错误的。

步骤:
1.按照元素的左边界升序排列。lambda表达式
2.初始化结果列表,并将第一个元素添加进,作为基准元素
3.遍历剩余的元素,如果结果列表的最后一个元素(已经是当前最大了)的右边界小于当前遍历到的元素的左边界,说明重叠,此时的新元素的左边界是结果列表的最后一个元素的左边界,右边界由这两个元素的右边界决定,选择最大值。

class Solution:def merge(self, intervals: List[List[int]]) -> List[List[int]]:# 按照左边界升序排序intervals.sort(key=lambda x: x[0])# 初始化res列表res = [intervals[0]]for i in intervals[1:]:# 前一个元素的右边界小于当前元素的左边界,直接添加当前元素if res[-1][1] < i[0]:res.append(i)# 重叠,因为已经按左边界升序排列了,所以重叠时的合并区间的左边界就是res[-1]的# 至于右边界,就看是前一个元素还是当前遍历到的元素的右边界大了# 比如 [1,2],[2,3]else:res[-1][1] = max(res[-1][1], i[1])return res

179. 最大数

解题思路:
利用字典序,对数组排序。
步骤:
1.将数组元素转为str
2.设置自定义排序函数,不断比较两个元素不同位置拼接的结果大小,选择最大的拼接方式
3.排序,检查是否有前导0
4.输出为字符串

class Solution:def largestNumber(self, nums):# 将数字转换为字符串,便于拼接比较strs = [str(num) for num in nums]# 自定义排序函数,看这两个值的def compare(x,y):# 如果xy拼接>yx拼接,说明x应该放在y前面,因为用正序排列,返回-1if x + y > y + x:return -1elif x + y < y + x:return 1else:return 0# 排序,使用自定义函数strs.sort(key=cmp_to_key(compare))# 检查元素,如果第一个是0,说明是全0if strs[0] == '0':return '0'# 正常返回return ''.join(strs)

排序流程概述:
排序算法开始:排序算法(如快速排序)会选择一个元素作为基准,然后将其他元素与这个基准进行比较,这涉及到多次调用
compare 函数。 比较操作:每次比较都涉及两个元素。比如,可能先比较 3 和 30,基于 compare 函数的结果(比较 "330"与 “303”),确定它们在数组中的相对位置。任何两个元素都可能被比较,不仅限于紧邻的元素。
递归和迭代:排序算法递归地对基准点左侧和右侧的子数组进行相同的过程,不断比较和交换位置,直到整个数组有序。

704. 二分查找

解题思路:
左右指针,确定中点,不断更新中点和左右指针,缩小范围,找到目标数。

步骤:
1.初始化左右指针分别指向数组左右边界
2.使用while循环,条件是左指针小于等于右指针
3.每次循环都更新mid,这里要注意,因为不断更新左指针,但是数组还是那么长。所以mid不等于(right-left+1)//2,而是left+(right-left)//2
4.循环体中判断是否mid就是目标值索引。如果大于mid的值,那就说明在mid的后面,更新left=mid+1,因为判断中已经把mid包括了。小于同理
5.默认返回-1

class Solution:def search(self, nums: List[int], target: int) -> int:n = len(nums)# 左右边界指针初始化left, right = 0, n-1# 当还未遍历完数组while left <= right:# 中间位置,必须是以左界为起点,这样才能在第二轮及之后都找到正确的中点mid = left + (right-left)//2# 如果相等,就找到了,返回索引if target == nums[mid]:return mid# 如果小于中点的元素,就要更新右指针,因为mid处已经被考虑过了,所以减1elif target < nums[mid]:right = mid-1# 大于同理else:left = mid+1# 最后返回默认值return -1

34. 在排序数组中查找元素的第一个和最后一个位置

解题思路1:
时间复杂度O(n),纯粹遍历

class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:start, end = -1,-1for i in range(len(nums)):if start == -1 and nums[i] == target:start = iif start != -1 and nums[i] == target:end = ireturn [start, end]

正确的思路:

二分查找。
分阶段,第一阶段找首次出现的位置,第二阶段找第二次。
要注意的是每阶段都要检查前面或者后面是否有相同元素,以确保找到的就是所求。

class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:# 先找第一个元素def first(nums, target):left,right = 0, len(nums)-1while left <= right:mid = left+(right-left)//2# 大于中点,更新左边界if nums[mid] < target:left = mid+1elif nums[mid] > target:right = mid-1else:# 检查前面是否还有该元素,更新右边界,逐步往前if mid == 0 or nums[mid-1] != target:return midright = mid-1return -1# 再找最后一个元素def end(nums, target):left,right = 0, len(nums)-1while left <= right:mid = left+(right-left)//2if nums[mid] < target:left = mid+1elif nums[mid] > target:right = mid-1else:# 检查后面是否还有该元素,更新左边界,逐步往后if mid == len(nums)-1 or nums[mid+1] != target:return midleft = mid + 1return -1# 找第一个元素start = first(nums, target)# 没找到就返回-1if start == -1:return [-1,-1]# 找到了第一个元素,找第二个last = end(nums, target)return [start, last]

153. 寻找旋转排序数组中的最小值

解题思路:
使用二分查找,将右边界的值作为target。
多次旋转后,如果中点大于右边界,说明最小值在右边,向右缩小区间,更新left为mid+1
如果小于等于右边界,说明是mid或者在左边,更新right 为mid
继续循环。

class Solution:def findMin(self, nums: List[int]) -> int:left, right = 0, len(nums)-1# 二分查找while left < right:mid = left + (right-left)//2# 右端点的值大于中点,说明最小值是mid或者在mid的左边# 更新右边界if nums[mid] <= nums[right]:right = midelse:# 小于中点,说明在mid的右边left = mid + 1     return nums[left]

33. 搜索旋转排序数组

解题思路:
旋转之后就不能用原始的二分查找了。
步骤:
1.初始化左右界指针
2.开始二分查找的循环
3.循环体:
初始化中点,如果中点就是目标值,那么就返回中点索引。
首先判断左边是否有序,进一步判断目标值是在left——mid吗?如果是,就更新右指针;否则,更新左指针。
再判断右边是否有序,同理。
默认返回-1

class Solution:def search(self, nums: List[int], target: int) -> int:# 二分查找left, right = 0,len(nums)-1while left <= right:mid = left + (right-left)//2# 找到目标值,返回下标if nums[mid] == target:return mid# 因为是升序,所以说明左边是有序的if nums[mid] >= nums[left]:# 目标在左边,缩小右边的区间if nums[left] <= target <= nums[mid]:right = mid - 1# 否则,缩小左边的区间else:left = mid + 1# 右边是有序的,同理操作else:if nums[mid] <= target <= nums[right]:left = mid+1else:right = mid-1return -1

算法思路

这个问题可以使用二分查找的变体来解决,关键是如何在旋转的数组中应用二分查找。具体的方法是使用两个指针 leftright 分别指向数组的起始和结束位置,并在每一步中确定旋转点是否在左边或右边,以及目标值是否可能位于当前考虑的数组部分。

  1. 初始化指针left 指向数组的第一个元素,right 指向最后一个元素。
  2. 计算中点:在每次迭代中,计算中点 mid = (left + right) // 2
  3. 比较和移动
    • 如果 nums[mid] 等于 target,返回 mid
    • 确定有序区间:
      • 如果 nums[left] <= nums[mid],这说明左半部分是有序的。
        • 如果 targetnums[left]nums[mid] 之间,移动 rightmid - 1
        • 否则,移动 leftmid + 1
      • 否则,右半部分是有序的。
        • 如果 targetnums[mid]nums[right] 之间,移动 leftmid + 1
        • 否则,移动 rightmid - 1
  4. 循环结束:如果整个数组都搜索完毕仍没有找到 target,返回 -1

162. 寻找峰值

解题思路:
也是二分查找。
根据中点和左右相邻的大小关系来确定峰值在哪边,然后收敛峰值到left=right

class Solution:def findPeakElement(self, nums: List[int]) -> int:left, right = 0, len(nums)-1# 二分查找while left < right:mid = left + (right-left)//2# 峰值在右侧,中点右边相邻的比中点大if nums[mid] < nums[mid+1]:left = mid + 1# 峰值在左侧else:right = mid# 返回左指针return left

240. 搜索二维矩阵 II

解题思路:
矩阵可以理解为从西北到东南是逐步增加的。
具体来说,是每行是从左到右升序,每列是从上到下升序。
所以就根据这个性质逐步缩小范围:如果当前元素比目标值大,说明太右边了,可以排除掉这一列;比目标值小,说明太上面了,这一行可以排除。
这种方法通常被称为“步进”方法或“Z字形”搜索。
步骤:
1.初始化矩阵长宽m、n
2.设置初始坐标为右上角,使得最右边最大,最上面最小。以利用矩阵性质
3.判断是否符合条件
4.缩小范围:太大就往左移动,太小就往下移动。

class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:# 矩阵的长宽m,n = len(matrix), len(matrix[0])# 初始化矩阵的长宽边界i,j = 0,n-1# 在矩阵范围内搜索while i < m and j >= 0:# 如果当前元素等于目标值if matrix[i][j] == target:return True# 如果太大了,说明当前元素靠右了,往左移动if matrix[i][j] > target:j -= 1# 如果太小了,说明靠上了,往下移动else:i += 1return False

69. x 的平方根

没想到这题也能用二分查找。
平方根肯定是在0-x之间的某个数,所以可以将其看做一个长度为x的数组,这样就能进行二分查找。
我们的target就是平方根,得到公式target**target=x

步骤:
1.初始化左右指针
2.二分查找,判断条件是中点是否满足该公式
3.默认返回右指针,这是因为循环退出时正好指向小于等于平方根的最大整数

class Solution:def mySqrt(self, x: int) -> int:# 以该数作为数组,进行二分查找left, right = 0, xwhile left <= right:mid = left+(right-left)//2# 如果在从0到数字的区间内有中点正好是平方根,那么相乘就是该数if mid * mid == x:return mid# 更新左右指针elif mid * mid < x:left = mid + 1else:right = mid - 1# 默认返回右指针# 因为循环退出时right指向小于等于sqrt(x)的最大整数return right

283. 移动零

解题思路:左右双指针
左指针用于构造数组前端的非0,右指针用于遍历并检查非0元素

class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""# 左右指针,左指针用于构造数组前端left = 0# 右指针遍历数组for right in range(len(nums)):# 发现一个非0元素,并且两个指针不相等,就交换两个指针的元素值if nums[right] != 0:if right != left:nums[left], nums[right] = nums[right], nums[left]# 右指针不是指向0,就可以把左指针往右移动left += 1return nums

算法步骤解析

  1. 初始化指针

    • left 指针用于跟踪在数组中应该插入下一个非零元素的位置。初始化为0,指向数组的起始位置。
  2. 遍历数组

    • 使用 right 指针遍历整个数组。right 指针用于检查每个元素是否为非零。
    • right 从0开始,直到数组末尾。
  3. 检查并交换

    • 如果 nums[right](当前元素)不为零,进入交换逻辑:
      • 检查是否需要交换:如果 right 指针的位置不等于 left 指针的位置(这意味着 rightleft 之间至少有一个零),则执行交换操作:
        • nums[right](非零元素)和 nums[left]left 指向的是第一个零元素的位置或者是另一个非零元素的位置)进行交换。
      • 移动 left 指针:无论是否进行了交换,left 指针都需要向右移动一位,因为现在 left 的位置已经填充了一个非零元素,下一个可能的非零元素应该放在 left + 1 的位置。
  4. 循环直到数组结束

    • 继续上述步骤直到 right 指针遍历完数组。

结果

  • 该方法通过一次遍历完成了非零元素的前移和零的后移操作。
  • 这种策略保证了只有当非零元素和零之间有间隔时才进行交换,减少了不必要的操作,增加了算法的效率。
  • 在遍历结束后,所有的非零元素都保持了它们的相对位置并且排在数组的前面,所有的零都移动到了数组的后部。

性能

  • 时间复杂度:由于算法只进行了一次遍历,所以时间复杂度是 (O(n)),其中 (n) 是数组的长度。
  • 空间复杂度:算法在原数组上进行操作,没有使用额外的存储空间,因此空间复杂度是 (O(1))。

这篇关于力扣刷题4.22的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/927523

相关文章

两数之和--力扣1

两数之和 题目思路C++代码 题目 思路 根据题目要求,元素不能重复且不需要排序,我们这里使用哈希表unordered_map。注意题目说了只对应一种答案。 所以我们在循环中,使用目标值减去当前循环的nums[i],得到差值,如果我们在map中能够找到这个差值,就说明存在两个整数的和为目标值。 如果没有找到,就将当前循环的nums[i]以及下标i放入map中,以便后续查

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl

力扣第347题 前K个高频元素

前言 记录一下刷题历程 力扣第347题 前K个高频元素 前K个高频元素 原题目: 分析 我们首先使用哈希表来统计数字出现的频率,然后我们使用一个桶排序。我们首先定义一个长度为n+1的数组,对于下图这个示例就是长度为7的数组。为什么需要一个长度为n+1的数组呢?假如说总共有三个数字都为1,那么我们需要把这个1放在数组下标为3的位置,假如说数组长度为n,对于这个例子就是长度为3,那么它的

hot100刷题第1-9题,三个专题哈希,双指针,滑动窗口

求满足条件的子数组,一般是前缀和、滑动窗口,经常结合哈希表; 区间操作元素,一般是前缀和、差分数组 数组有序,更大概率会用到二分搜索 目前已经掌握一些基本套路,重零刷起leetcode hot 100, 套路题按套路来,非套路题适当参考gpt解法。 一、梦开始的地方, 两数之和 class Solution:#注意要返回的是数组下标def twoSum(self, nums: Lis

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237

总结,删除链表节点问题使用到列表,哈希表,递归比较容易超时,我觉得使用计数排序比较稳,处理起来也不是很难。 1. 力扣3217:从链表中移除在数组中的节点 1.1 题目: 给你一个整数数组 nums 和一个链表的头节点 head。从链表中移除所有存在于 nums 中的节点后,返回修改后的链表的头节点。 示例 1: 输入: nums = [1,2,3], head = [1,2,3,

力扣 739. 每日温度【经典单调栈题目】

1. 题目 理解题意: 1.1. 给一个温度集合, 要返回一个对应长度的结果集合, 这个结果集合里面的元素 i 是 当前 i 位置的元素的下一个更高温度的元素的位置和当前 i 位置的距离之差, 若是当前元素不存在下一个更高温度的元素, 则这个位置用0代替; 2. 思路 本题用单调栈来求解;单调栈就适用于来求当前元素左边或者右边第一个比当前元素大或者小的元素;【单调栈:让栈中的元素保持单调

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II 1.题目 1.1递增子序列 题目链接:491. 非递减子序列 - 力扣(LeetCode) 视频讲解:回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列_哔哩哔哩_bilibili 文档讲解:https://programmercarl.com/0491.%E9%80%92%E

力扣接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]输出:6解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 示例 2: 输入:height

每日一题,力扣leetcode Hot100之238.除自身以外数组的乘积

乍一看这个题很简单,但是不能用除法,并且在O(N)时间复杂度完成或许有点难度。 考虑到不能用除法,如果我们要计算输出结果位置i的值,我们就要获取这个位置左边的乘积和右边的乘积,那么我新设立两个数组L和R。 对于L来说,由于表达的是位置i左边的数的乘积,那么L[0]=1,因为第一个数字左边没数那么为了不影响乘积初始值就设置为1,那么L[1]=L[0]*nums[0],那么L[i]=L[i-1

代码随想录刷题day24丨93.复原IP地址 ,78.子集 , 90.子集II

代码随想录刷题day24丨93.复原IP地址 ,78.子集 , 90.子集II 1.题目 1.1复原IP地址 题目链接:93. 复原 IP 地址 - 力扣(LeetCode) 视频讲解:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址_哔哩哔哩_bilibili 文档讲解:https://programmercarl.com/0093.%E5%A4%8