分类: 未分类

  • Next Greater Element I,LeetCode,496

    题目描述:

    给定两个没有重复元素的数组 nums1nums2 ,其中 nums1nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。

    nums1 中的数字在 nums2 中是唯一的,但 nums2 中的数字不一定在 nums1 中。

    示例:

    输入: nums1 = [4,1,2], nums2 = [1,3,4,2].

    输出: [-1,3,-1]

    解释: 对于num1中的数字4,你无法在 num2 中找到一个更大的数字,因此输出 -1。 对于num1中的数字1,num2 中数字1右边的下一个较大数字是 3。 对于num1中的数字2,你无法在 num2 中找到一个更大的数字,因此输出 -1。

    解题思路:

    1. 单调栈:使用单调栈来解决这个问题。单调栈是一种特殊的栈,用于处理序列中元素的前驱问题和后继问题。在这个问题中,我们可以利用单调栈找到 nums2 中每个元素的下一个更大的元素。
    2. 哈希表:使用哈希表来存储 nums2 中每个元素的下一个更大的元素,以便快速查找。

    具体步骤:

    1. 构建单调栈和哈希表
      • 遍历 nums2,使用一个栈来维护一个单调递减的序列。
      • 对于每个元素 num
        • 如果栈不为空且当前元素 num 大于栈顶元素,说明找到了栈顶元素的下一个更大的元素,将其弹出并记录到哈希表中。
        • 将当前元素 num 压入栈中。
    2. 查找结果
      • 遍历 nums1,对于每个元素,直接在哈希表中查找其下一个更大的元素。

    代码实现:

    def nextGreaterElement(nums1, nums2):

    单调栈和哈希表

    stack = []
    next_greater = {}
    
    # 遍历nums2,构建单调栈和哈希表
    for num in nums2:
        while stack and num > stack[-1]:
            next_greater[stack.pop()] = num
        stack.append(num)
    
    # 处理栈中剩余的元素,这些元素没有下一个更大的元素
    while stack:
        next_greater[stack.pop()] = -1
    
    # 遍历nums1,查找每个元素的下一个更大的元素
    result = [next_greater[num] for num in nums1]
    
    return result

    示例

    nums1 = [4,1,2] nums2 = [1,3,4,2] print(nextGreaterElement(nums1, nums2)) # 输出: [-1, 3, -1]

    复杂度分析:

    • 时间复杂度:O(n + m),其中 n 是 nums2 的长度,m 是 nums1 的长度。我们首先遍历 nums2 构建单调栈和哈希表,然后遍历 nums1 查找结果。
    • 空间复杂度:O(n),主要用于存储单调栈和哈希表。

    总结:

    通过单调栈和哈希表的结合,我们可以高效地解决这个问题。单调栈帮助我们找到每个元素的下一个更大的元素,而哈希表则用于快速查找结果。这种方法在处理类似的前驱和后继问题时非常有效。

  • Teemo Attacking,LeetCode,495

    好的,我们来详细解析一下 LeetCode 上的 495 号问题:Teemo Attacking。

    题目描述

    在《英雄联盟》的世界中,有一个叫 Teemo 的英雄,他的技能可以让敌人中毒。现在给定一个数组 timeSeries,其中 timeSeries[i] 表示 Teemo 在第 i 秒时对敌人发动攻击的时间点。每次攻击会让敌人中毒 duration 秒。如果 Teemo 在敌人中毒期间再次攻击,中毒时间会重新计算。

    你需要计算敌人总共中毒的时间。

    示例

    示例 1:

    输入: timeSeries = [1,4], duration = 2 输出: 4 解释: 在第 1 秒开始中毒,持续 2 秒,总共中毒 2 秒。 在第 4 秒再次攻击,重新计算中毒时间,持续 2 秒,总共中毒 4 秒。

    示例 2:

    输入: timeSeries = [1,2], duration = 2 输出: 3 解释: 在第 1 秒开始中毒,持续 2 秒。 在第 2 秒再次攻击,重新计算中毒时间,但只多中毒 1 秒,因为第 1 秒的攻击还在持续。

    解题思路

    1. 初始化变量
      • total 用于记录总的中毒时间。
      • last 用于记录上一次攻击的时间点。
    2. 遍历攻击时间点
      • 对于每个攻击时间点 t
        • 如果当前攻击时间点 t 与上一次攻击时间点 last 的间隔大于或等于 duration,说明上一次中毒已经结束,直接加上 duration
        • 如果间隔小于 duration,说明上一次中毒还未结束,只加上两次攻击之间的间隔时间 t - last
        • 更新 last 为当前攻击时间点 t
    3. 处理最后一次攻击
      • 最后一次攻击后,无论是否有新的攻击,都需要加上 duration 秒的中毒时间。

    代码实现

    class Solution: def findPoisonedDuration(self, timeSeries, duration): if not timeSeries: return 0

        total = 0
        last = timeSeries[0]
    
        for t in timeSeries[1:]:
            if t - last >= duration:
                total += duration
            else:
                total += t - last
            last = t
    
        total += duration  # 处理最后一次攻击
        return total

    复杂度分析

    • 时间复杂度:O(n),其中 n 是 timeSeries 的长度,因为我们只需要遍历一次数组。
    • 空间复杂度:O(1),因为我们只使用了常数级别的额外空间。

    总结

    这个问题的核心在于正确处理每次攻击的中毒时间,特别是当两次攻击间隔小于 duration 时,需要仔细计算实际增加的中毒时间。通过遍历攻击时间点并累加中毒时间,我们可以高效地解决这个问题。

    希望这个详细的解析对你有所帮助!如果有任何进一步的问题,欢迎继续提问。

  • Target Sum,LeetCode,494

    题目描述(LeetCode 494. Target Sum)

    给你一个整数数组 nums 和一个整数 target

    向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

    • 例如,数组 [1, 2, 3]target = 3 可以构造出以下表达式:
      • 1 + 2 + 3 = 6
      • +1 - 2 + 3 = 2
      • +1 + 2 - 3 = 0
      • -1 + 2 + 3 = 4
  • Reverse Pairs,LeetCode,493

    LeetCode 493题 “Reverse Pairs” 是一个中等难度的题目,主要考察的是归并排序的应用以及如何处理逆序对的问题。下面我将详细解释题目的要求、解题思路以及具体的代码实现。

    题目描述

    给定一个整数数组 nums,返回数组中的逆序对的数量。逆序对的定义是:对于数组中的两个元素 nums[i]nums[j],如果满足 i < jnums[i] > 2 * nums[j],则 (nums[i], nums[j]) 是一个逆序对。

    解题思路

    这个问题可以通过暴力枚举来解决,但时间复杂度会达到 O(n^2),对于大数据集来说效率太低。更好的方法是使用归并排序的思想,时间复杂度可以优化到 O(n log n)。

    归并排序的过程中,当我们合并两个有序数组时,可以同时统计逆序对的数量。具体步骤如下:

    1. 分割数组:将数组递归地分割成更小的数组,直到每个数组只有一个元素。
    2. 合并数组:在合并两个有序数组的过程中,统计逆序对的数量。
    3. 统计逆序对:在合并时,如果左数组的当前元素大于右数组的当前元素的2倍,那么左数组中当前元素及其后面的所有元素都与右数组的当前元素构成逆序对。

    代码实现

    以下是使用归并排序思想的 Python 代码实现:

    class Solution: def reversePairs(self, nums): def mergeSort(l, r): if l >= r: return 0

            mid = (l + r) // 2
            count = mergeSort(l, mid) + mergeSort(mid + 1, r)
    
            # 统计逆序对
            j = mid + 1
            for i in range(l, mid + 1):
                while j <= r and nums[i] > 2 * nums[j]:
                    j += 1
                count += j - (mid + 1)
    
            # 合并两个有序数组
            nums[l:r+1] = sorted(nums[l:r+1])
            return count
    
        return mergeSort(0, len(nums) - 1)

    示例

    sol = Solution() print(sol.reversePairs([1, 3, 2, 3, 1])) # 输出: 2

    详细解释

    1. mergeSort 函数
      • 这是一个递归函数,用于对数组进行归并排序并统计逆序对。
      • lr 分别是当前子数组的左右边界。
      • 首先递归地对左右子数组进行排序并统计逆序对。
      • 然后在合并前,通过双指针方法统计逆序对的数量。
      • 最后合并两个有序子数组。
    2. 统计逆序对
      • 使用两个指针 iji 遍历左子数组,j 遍历右子数组。
      • 如果 nums[i] > 2 * nums[j],则 j 向右移动,直到不满足条件。
      • 此时,j - (mid + 1) 就是与 nums[i] 构成逆序对的右子数组元素的数量。
    3. 合并数组
      • 使用 Python 的内置 sorted 函数合并两个有序子数组。

    复杂度分析

    • 时间复杂度:O(n log n),归并排序的时间复杂度。
    • 空间复杂度:O(n),递归调用栈和临时数组的空间。

    通过这种方法,我们能够高效地解决 Reverse Pairs 问题。希望这个详细的解释和代码实现对你有所帮助!如果有任何进一步的问题,欢迎继续提问。

  • Construct the Rectangle,LeetCode,492

    LeetCode 492题 “Construct the Rectangle” 是一个数学问题,要求我们为一个给定的面积找到最接近的矩形尺寸(长和宽)。具体来说,我们需要找到一个矩形的长度 L 和宽度 W,使得 L * W = area,并且 L 和 W 的差值尽可能小。

    题目描述

    给定一个整数 area,找到三个整数 LW,使得:

    1. L * W = area
    2. L >= W
    3. L 和 W 的差值尽可能小

    示例

    输入: area = 4 输出: [2, 2] 解释: 2 * 2 = 4 且 2 - 2 = 0,差值最小。

    输入: area = 37 输出: [37, 1] 解释: 37 * 1 = 37 且 37 - 1 = 36,这是唯一可能的组合。

    解题思路

    1. 从平方根开始:为了使 L 和 W 的差值尽可能小,我们可以从 sqrt(area) 开始向下查找。因为平方根处的值是最接近的两个因数。
    2. 遍历因数:从 sqrt(area) 开始向下遍历,找到第一个能整除 area 的数,这个数作为宽度 W,对应的商作为长度 L。
    3. 返回结果:返回 [L, W]

    代码实现

    以下是 Python 的实现代码:

    import math

    def constructRectangle(area):

    从平方根开始向下遍历

    for w in range(int(math.sqrt(area)), 0, -1):
        if area % w == 0:
            return [area // w, w]

    示例

    print(constructRectangle(4)) # 输出: [2, 2] print(constructRectangle(37)) # 输出: [37, 1]

    详细解释

    1. 导入 math 库:用于计算平方根。
    2. 遍历范围range(int(math.sqrt(area)), 0, -1)sqrt(area) 向下遍历到 1。
    3. 判断整除if area % w == 0 检查当前宽度 w 是否能整除 area
    4. 返回结果:如果找到符合条件的宽度 w,则返回 [area // w, w],其中 area // w 是长度 L。

    复杂度分析

    • 时间复杂度:O(sqrt(area)),因为我们最多遍历到 sqrt(area)
    • 空间复杂度:O(1),只使用了常数级别的额外空间。

    这种方法高效且直观,能够很好地解决题目要求。希望这个解释对你有帮助!如果有其他问题,欢迎继续提问。

  • Increasing Subsequences,LeetCode,491

    LeetCode 491题 “Increasing Subsequences” 是一个中等难度的题目,主要考察的是深度优先搜索(DFS)和回溯算法。题目要求找到给定数组中的所有递增子序列。

    题目描述

    给定一个整型数组,你的任务是找到所有的递增子序列,递增子序列的长度至少为2。

    示例

    输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

    解题思路

    1. 深度优先搜索(DFS):通过递归的方式遍历所有可能的子序列。
    2. 回溯:在递归过程中,如果当前子序列不再满足递增条件,则回溯到上一步。
    3. 去重:使用集合来避免重复的子序列。

    详细步骤

    1. 初始化:定义一个结果集 res 和一个临时路径 path
    2. 递归函数:定义一个递归函数 dfs(start),从数组的 start 位置开始搜索。
    3. 递归终止条件:当遍历到数组末尾时,检查 path 的长度是否大于1,如果是则加入结果集。
    4. 递归逻辑
      • 遍历从 start 到数组末尾的所有元素。
      • 如果当前元素可以加入 path(即当前元素大于 path 的最后一个元素或者 path 为空),则将其加入 path 并继续递归。
      • 递归结束后,回溯,即从 path 中移除当前元素。

    代码实现

    def findSubsequences(nums): def dfs(start, path): if len(path) > 1: res.append(path[:]) used = set() for i in range(start, len(nums)): if nums[i] in used: continue if not path or nums[i] >= path[-1]: used.add(nums[i]) dfs(i + 1, path + [nums[i]])

    res = []
    dfs(0, [])
    return res

    示例

    nums = [4, 6, 7, 7] print(findSubsequences(nums))

    代码解释

    1. findSubsequences 函数:主函数,初始化结果集 res 并调用 dfs 函数。
    2. dfs 函数
      • start:当前开始搜索的位置。
      • path:当前递增子序列。
      • used:用于去重的集合,避免在同一层递归中使用相同的元素。
    3. 递归逻辑
      • 遍历从 start 到数组末尾的所有元素。
      • 如果当前元素未在当前层使用过,并且可以加入 path,则加入 path 并继续递归。
      • 递归结束后,回溯。

    复杂度分析

    • 时间复杂度:O(2^N),在最坏情况下,每个元素都有两种选择(加入或不加入子序列)。
    • 空间复杂度:O(N),递归栈的深度最多为 N。

    通过上述步骤和代码实现,可以有效地找到数组中的所有递增子序列。希望这个详细的解答对你有所帮助!如果有任何进一步的问题,欢迎继续提问。

  • The Maze,LeetCode,490

    题目描述

    由空地和墙组成的迷宫中有一个球。球可以向上(u)、下(d)、左(l)或右(r)四个方向滚动,但在遇到墙壁前不会停止滚动。当球停下时,可以选择下一个方向。迷宫中有一个终点,当球到达终点时,游戏结束。

    给定迷宫的二维网格,其中 1 表示墙壁, 表示空地,以及球的起始位置和终点位置,请判断球能否到达终点。

    示例

    输入 1: 迷宫由以下二维数组表示

    0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 0 0 0 0 0

    输入 2: 球的初始位置 (rowStart, colStart) = (0, 4) 输入 3: 球的终点位置 (rowEnd, colEnd) = (4, 4)

    输出: true

    解释: 球可以按照如下路径从起点滚到终点: (0, 4) -> (0, 3) -> (1, 3) -> (1, 2) -> (1, 1) -> (1, 0) -> (2, 0) -> (2, 1) -> (2, 2) -> (3, 2) -> (4, 2) -> (4, 3) -> (4, 4)

    解题思路

    1. 深度优先搜索(DFS)
      • 从起始位置开始,尝试四个方向滚动。
      • 每个方向上,球会一直滚动直到遇到墙壁或边界。
      • 到达新位置后,递归地继续搜索。
      • 如果到达终点,返回 true
      • 使用一个集合记录已经访问过的位置,避免重复搜索。
    2. 广度优先搜索(BFS)
      • 使用队列存储待访问的位置。
      • 从起始位置开始,将四个方向上的可行位置加入队列。
      • 每次从队列中取出一个位置,检查是否到达终点。
      • 如果到达终点,返回 true
      • 否则,继续将新位置加入队列。

    代码实现(DFS)

    def hasPath(maze, start, destination): def dfs(maze, start, destination, visited): if start == destination: return True visited.add(start) directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] for dx, dy in directions: x, y = start while 0 <= x + dx < len(maze) and 0 <= y + dy < len(maze[0]) and maze[x + dx][y + dy] == 0: x += dx y += dy if (x, y) not in visited and dfs(maze, (x, y), destination, visited): return True return False

    visited = set()
    return dfs(maze, tuple(start), tuple(destination), visited)

    示例输入

    maze = [ [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [1, 1, 0, 1, 1], [0, 0, 0, 0, 0] ] start = [0, 4] destination = [4, 4]

    调用函数

    print(hasPath(maze, start, destination)) # 输出: True

    代码实现(BFS)

    from collections import deque

    def hasPath(maze, start, destination): queue = deque([tuple(start)]) visited = set([tuple(start)]) directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    while queue:
        x, y = queue.popleft()
        if (x, y) == tuple(destination):
            return True
        for dx, dy in directions:
            nx, ny = x, y
            while 0 <= nx + dx < len(maze) and 0 <= ny + dy < len(maze[0]) and maze[nx + dx][ny + dy] == 0:
                nx += dx
                ny += dy
            if (nx, ny) not in visited:
                visited.add((nx, ny))
                queue.append((nx, ny))
    return False

    示例输入

    maze = [ [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [1, 1, 0, 1, 1], [0, 0, 0, 0, 0] ] start = [0, 4] destination = [4, 4]

    调用函数

    print(hasPath(maze, start, destination)) # 输出: True

    总结

    • DFS 适合于路径搜索,但可能会遇到深度很大的情况,导致栈溢出。
    • BFS 适合于寻找最短路径,且不会因为深度过大而出现问题,但需要更多的空间来存储队列。

    根据具体问题的需求选择合适的算法。在这个迷宫问题中,两种方法都可以有效解决。

  • Robot Room Cleaner,LeetCode,489

    好的,我们来详细讨论一下 LeetCode 上的第 489 题:Robot Room Cleaner。

    题目描述

    这道题要求我们模拟一个机器人在一个未知的房间内进行清洁的过程。房间的布局是未知的,机器人只能通过有限的方向移动(通常是上、下、左、右),并且机器人不能回到已经清洁过的位置。

    机器人有一个 clean 方法用来清洁当前位置,以及一个 move 方法用来移动到下一个位置。如果移动失败(比如遇到了墙壁),move 方法会返回 false。机器人还有一个 turnLeftturnRight 方法用来改变方向。

    解题思路

    这道题可以使用深度优先搜索(DFS)来解决这个问题。关键点在于如何避免重复访问已经清洁过的位置,以及如何确保机器人能够回到出发点。

    1. 方向控制:定义一个方向数组,比如 [(0, 1), (1, 0), (0, -1), (-1, 0)],分别代表上、右、下、左四个方向。
    2. 状态记录:使用一个集合来记录已经清洁过的位置。
    3. 回溯:在每次移动到一个新位置后,进行清洁,并递归地探索其他方向。探索完所有方向后,需要回到上一个位置。

    代码实现

    以下是一个 Python 示例代码,假设机器人类已经定义好了 clean, move, turnLeft, turnRight 方法。

    class Solution: def cleanRoom(self, robot): def go_back(): robot.turnRight() robot.turnRight() robot.move() robot.turnRight() robot.turnRight()

        def dfs(x, y, d):
            robot.clean()
            visited.add((x, y))
    
            for i in range(4):
                new_d = (d + i) % 4
                new_x, new_y = x + directions[new_d][0], y + directions[new_d][1]
    
                if (new_x, new_y) not in visited and robot.move():
                    dfs(new_x, new_y, new_d)
                    go_back()
    
                robot.turnRight()
    
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        visited = set()
        dfs(0, 0, 0)

    假设机器人类如下:

    class Robot: def clean(self): pass

    def move(self):
        pass
    
    def turnLeft(self):
        pass
    
    def turnRight(self):
        pass

    详细解释

    1. go_back 函数:这个函数用于让机器人回到上一个位置。具体操作是先转180度,然后移动一步,再转回原来的方向。
    2. dfs 函数:这是一个深度优先搜索函数,参数 (x, y, d) 分别表示当前的位置和方向。
      • 首先清洁当前位置,并将当前位置加入 visited 集合。
      • 然后尝试四个方向(通过循环和方向数组 directions 实现)。
      • 如果新位置没有被访问过且可以移动,递归调用 dfs
      • 每次尝试新方向前,先右转,以便下一次循环时尝试下一个方向。
    3. 主函数:初始化方向数组和访问集合,从 (0, 0, 0)(即起始位置和向上方向)开始进行深度优先搜索。

    注意事项

    • 机器人类的具体实现细节(如 clean, move, turnLeft, turnRight 方法)需要根据题目提供的接口来调整。
    • 这道题的关键在于理解和实现回溯过程,确保机器人能够回到出发点。

    希望这个详细的解答能帮助你理解并解决这道题目。如果有更多问题,欢迎继续提问!

  • Zuma Game,LeetCode,488

    《Zuma Game》(祖玛游戏)是 LeetCode 上的第 488 题,这是一个中等难度的题目,主要考察的是深度优先搜索(DFS)和广度优先搜索(BFS)的算法应用。

    题目描述

    在一个二维的平面中,有一些彩球按顺序排列成一行,你需要通过射出彩球来消除这些彩球。当三个或更多相同颜色的彩球相连时,这些彩球会被消除。你需要找到消除所有彩球所需的最少射击次数。

    输入:

    • board:一个字符串,表示初始彩球的排列。
    • hand:一个字符串,表示你手中持有的彩球。

    输出:

    • 返回消除所有彩球所需的最少射击次数。如果无法消除所有彩球,则返回 -1。

    示例

    输入:board = "WRRBBW", hand = "RB" 输出:-1 解释:无法通过手中的彩球消除所有彩球。

    输入:board = "WWRRBBWW", hand = "WRBRW" 输出:2 解释:可以通过以下步骤消除所有彩球:

    1. 射击手中的 'R' 到位置 3,使得 "WWRRBBWW" 变为 "WWRRRBBWW"。
    2. 射击手中的 'B' 到位置 6,使得 "WWRRRBBWW" 变为 "WWRRRBBBW"。 这时,三个 'R' 和三个 'B' 相连,被消除,剩下的 "WWW" 也会被自动消除。

      解题思路

    深度优先搜索(DFS)

    • 从左到右遍历 board,找到第一个可以插入的位置。
    • 尝试将手中的彩球插入到该位置,并递归地进行下一步搜索。
    • 每次插入后,检查是否有连续的三个或更多相同颜色的彩球,如果有则消除它们,并继续递归搜索。
    • 记录每次搜索的结果,找到最少射击次数。

  • 广度优先搜索(BFS)
    • 使用队列来存储当前的状态(当前的 board 和手中的 hand)。
    • 从初始状态开始,逐层扩展状态,每次尝试将手中的彩球插入到 board 中的不同位置。
    • 检查是否有连续的三个或更多相同颜色的彩球,如果有则消除它们,并更新状态。
    • 记录每层扩展的次数,找到最少射击次数。
  • 代码实现(DFS 示例)

    class Solution: def findMinStep(self, board: str, hand: str) -> int: from collections import Counter

        def clean_board(b):
            # 消除连续的三个或更多相同颜色的彩球
            j = 0
            while j < len(b):
                k = j
                while k < len(b) and b[k] == b[j]:
                    k += 1
                if k - j >= 3:
                    b = b[:j] + b[k:]
                    j = 0
                else:
                    j = k
            return b
    
        def dfs(b, h):
            if not b:
                return 0
            b = clean_board(b)
            cnt = Counter(h)
            res = float('inf')
            j = 0
            while j < len(b):
                k = j
                while k < len(b) and b[k] == b[j]:
                    k += 1
                need = 3 - (k - j)
                if cnt[b[j]] >= need:
                    cnt[b[j]] -= need
                    res = min(res, dfs(b[:j] + b[k:], ''.join(cnt.elements())) + need)
                    cnt[b[j]] += need
                j = k
            return res
    
        result = dfs(board, hand)
        return result if result != float('inf') else -1

    示例使用

    sol = Solution() print(sol.findMinStep("WWRRBBWW", "WRBRW")) # 输出:2 print(sol.findMinStep("WRRBBW", "RB")) # 输出:-1

    关键点

    1. 递归与回溯:通过递归尝试每一种可能的插入方式,并在回溯时恢复状态。
    2. 状态清理:在每次插入后,需要清理 board 中的连续相同颜色的彩球。
    3. 剪枝优化:如果当前状态无法继续消除彩球,则提前返回,避免无效搜索。

    通过以上思路和代码实现,可以有效地解决 LeetCode 488 题《Zuma Game》。希望这个详细的解答对你有所帮助!如果有更多问题,欢迎继续提问。

  • Max Consecutive Ones II,LeetCode,487

    题目描述:

    给定一个二进制数组,你可以最多翻转一个 1,求最长连续 1 的个数。

    示例:

    输入: [1,0,1,1,0] 输出: 4 解释: 翻转第二个 0 可以得到最长的连续 1 的序列。

    解题思路:

    这道题可以使用滑动窗口的技巧来解决。滑动窗口的思路是维护一个窗口,这个窗口内最多包含一个 ,然后计算这个窗口的长度。

    具体步骤:

    1. 初始化变量:
      • leftright 指针,表示窗口的左右边界。
      • zero_count 记录窗口内 的个数。
      • max_len 记录最长连续 1 的长度。
    2. 滑动窗口:
      • 使用 right 指针遍历数组。
      • 如果当前元素是 zero_count 增加。
      • 如果 zero_count 超过 1,说明窗口内有两个 ,需要移动 left 指针,直到 zero_count 重新变为 1
      • 在每次移动 right 指针后,更新 max_lenright - left + 1
    3. 返回结果:
      • 遍历结束后,max_len 就是所求的最长连续 1 的长度。

    代码实现:

    def findMaxConsecutiveOnes(nums): left = 0 zero_count = 0 max_len = 0

    for right in range(len(nums)):
        if nums[right] == 0:
            zero_count += 1
    
        while zero_count > 1:
            if nums[left] == 0:
                zero_count -= 1
            left += 1
    
        max_len = max(max_len, right - left + 1)
    
    return max_len

    示例

    nums = [1, 0, 1, 1, 0] print(findMaxConsecutiveOnes(nums)) # 输出: 4

    解释:

    • leftright 指针用于维护滑动窗口的边界。
    • zero_count 用于记录当前窗口内 的个数。
    • zero_count 超过 1 时,说明窗口内有两个 ,需要移动 left 指针,直到窗口内只有一个
    • 每次移动 right 指针后,更新 max_len 为当前窗口的长度。

    复杂度分析:

    • 时间复杂度: O(n),其中 n 是数组的长度。每个元素被访问两次(一次是 right 指针,一次是 left 指针)。
    • 空间复杂度: O(1),使用了常数个额外空间。

    这种方法高效且直观,利用滑动窗口的技巧很好地解决了问题。希望这个解释对你有所帮助!如果有其他问题,欢迎继续提问。