Leetcode 【485、1004、1052】

2019-06-17  本文已影响0人  牛奶芝麻
问题描述:【Array】485. Max Consecutive Ones
解题思路:

因为要找最长连续 1 子数组的长度,所以我们只需要遍历一次,记录每段连续 1 的长度;如果遇到 0,就更新当前最大长度,然后当前长度清零,继续向后遍历。时间复杂度为 O(n)。

Python3 实现:
class Solution:
    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
        max_ = tem = 0
        for i in range(len(nums)):
            if nums[i] == 0:
                max_ = max(max_, tem)  # 更新当前最大长度
                tem = 0
            else:
                tem += 1
        return max(max_, tem)

问题描述:【Array】487. Max Consecutive Ones

收费暂时做不了 hhh~ 题目是最多改变其中 1 个 0 变成 1,然后求最长连续 1 子数组的长度。可以采用滑动窗口的做法,在下面的 1004 题有具体的解法,代码和 1004 完全一样。


问题描述:【Sliding Window】1004. Max Consecutive Ones III
解题思路:

这道题是最多改变 K 个 1 变成 0,然后求最长连续 1 子数组的长度。很容易想到滑动窗口的思路(487 做法和本题做法一致,只不过 487 中 K = 1):

我们来定义本题的滑动窗口:因为肯定将所有 K 个 0 改成 1 才能获得最大长度,因此滑动窗口中记录包含 K 个 0 之后的最长连续 1 子数组。注意到这个滑动窗口的大小是不固定的,因此,我们在滑动的过程中,要记录滑动窗口的起始位置(终止位置不用记,因为终止位置就是当前遍历的位置)。

如何更新滑动窗口呢?如果我们的滑动窗口中已经有 K 个 0 了,后面又遇到一个 0,那么我们就要移动滑动窗口,根据滑动窗口的起始位置找到窗口中最前面的 0,然后这个 0 的下一个位置就是新滑动窗口的起始位置。注意,在这个过程中,还要减小滑动窗口的长度。

这样,我们只需要遍历 1 次,不断更新最大长度,就能得到结果。

注意:刚开始时滑动窗口中 0 的个数如果小于 K,我们只拓展窗口,不更新窗口的起始位置(最开始的起始位置为 0)。

Python3 实现:
class Solution:
    def longestOnes(self, A: List[int], K: int) -> int:
        sliding_window = 0  # 滑动窗口
        begin = 0  # 滑动窗口的起始位置
        nums0 = 0  # 滑动窗口中0的个数
        max_ = 0
        for i in range(len(A)):
            sliding_window += 1  # 拓展窗口长度
            if nums0 < K:  # 滑动窗口中 0 的个数小于 K,只拓展窗口
                if A[i] == 0:
                    nums0 += 1
            elif nums0 == K:
                if A[i] == 0:  # 如果再有 0 出现,更新滑动窗口
                    while A[begin] == 1:  # 找到滑动窗口中第1个0的位置
                        begin += 1
                        sliding_window -= 1
                    begin += 1  # 新滑动窗口的起始位置
                    sliding_window -= 1
            max_ = max(max_, sliding_window)  # 更新最大长度
        return max_

问题描述:【Sliding Window、DP、Array】1052. Grumpy Bookstore Owner
解题思路:

方法1(暴力 O(N^2),TLE):

这样,时间复杂度为 O(N*X),由于 X 也可能达到 N 的长度级别,因此为 O(N^2),超时。

方法2(DP O(N^2),勉强 AC):

尝试了一下动态规划,虽然时间复杂度还是 O(N^2),但勉强 AC 了。DP 思路如下:

但是,实际上这种做法还是 O(N*X) 的时间复杂度,但是竟然勉强 AC 了(可能脸好吧)。

Python3 实现(DP):

class Solution:
    def maxSatisfied(self, customers: List[int], grumpy: List[int], X: int) -> int:
        N = len(customers)
        dp1 = [0] * (N + 1)  # 不使用 X 技巧的累加初始满意度
        dp2 = [0] * (N + 1)  # 使用 X 技巧的最大满意度
        for i in range(1, N + 1):
            if grumpy[i-1] == 0:
                dp1[i] = dp1[i-1] + customers[i-1]
            else:
                dp1[i] = dp1[i-1]
        for i in range(1, N + 1):
            if grumpy[i-1] == 0 or i-X-1 < 0:
                dp2[i] = dp2[i-1] + customers[i-1]
            else:
                dp2[i] = max(dp2[i-1], dp1[i-X] + sum(customers[i-X:i]))
        return dp2[-1]

方法3(Sliding Window O(N),AC):

这也是一道经典的利用滑动窗口解决问题的题目。

我们来定义本题的滑动窗口:因为肯定当技能 X 发挥时能获得的满意度最大,且这个窗口是连续的,因此窗口的大小是固定的。长度为 X 的滑动窗口中记录增加的满意度。

这样,时间复杂度为 O(N)。

Python3 实现(Sliding Window):

class Solution:
    def maxSatisfied(self, customers: List[int], grumpy: List[int], X: int) -> int:
        N = len(customers)
        initial_satisfied = sum([customers[i] for i in range(N) if grumpy[i] == 0])  # 初始的满意度
        sliding_window = 0  # 大小为X的滑动窗口中保存增加的满意度
        add_satisfied = 0  # 大小为X的滑动窗口中增加的满意度的最大值
        for i in range(N):
            if i < X and grumpy[i] == 1:  # 没有达到窗口大小
                sliding_window += customers[i]
            elif i >= X:
                if grumpy[i] == 1:
                    sliding_window += customers[i]  # 滑动窗口中增加当前满意度
                if grumpy[i-X] == 1:
                    sliding_window -= customers[i-X]  # 滑动窗口移除满意度
            add_satisfied = max(add_satisfied, sliding_window)
        return initial_satisfied + add_satisfied  # 两者之和为最终满意度
上一篇下一篇

猜你喜欢

热点阅读