【5月】LeetCode:我怎么还是这么菜

5.3

题目链接

53. 最大子序和

很喜欢的解法(DP)

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        maxSum=nums[0]
        tmp=0
        for i in nums:
            tmp=max(tmp+i,i)
            maxSum=max(maxSum,tmp)
        return maxSum

官方解(分治)

参考题解:最大子序和

但是仔细观察「方法二」,它不仅可以解决区间 [0,n−1],还可以用于解决任意的子区间 [l,r] 的问题。如果我们把 [0,n−1] 分治下去出现的所有子区间的信息都用堆式存储的方式记忆化下来,即建成一颗真正的树之后,我们就可以在 O(logn) 的时间内求到任意区间内的答案,我们甚至可以修改序列中的值,做一些简单的维护,之后仍然可以在 O(logn) 的时间内求到任意区间内的答案,对于大规模查询的情况下,这种方法的优势便体现了出来。这棵树就是上文提及的一种神奇的数据结构——线段树。

参考题解:【五种解法三种语言】(Java, JavaScript, Python)

import sys
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        return self.helper(nums, 0, len(nums) - 1)
    def helper(self, nums, l, r):
        if l > r:
            return -sys.maxsize
        mid = (l + r) // 2
        left = self.helper(nums, l, mid - 1)
        right = self.helper(nums, mid + 1, r)
        left_suffix_max_sum = right_prefix_max_sum = 0
        sum = 0
        for i in reversed(range(l, mid)):
            sum += nums[i]
            left_suffix_max_sum = max(left_suffix_max_sum, sum)
        sum = 0
        for i in range(mid + 1, r + 1):
            sum += nums[i]
            right_prefix_max_sum = max(right_prefix_max_sum, sum)
        cross_max_sum = left_suffix_max_sum + right_prefix_max_sum + nums[mid]
        return max(cross_max_sum, left, right)

5.4

题目链接

45. 跳跃游戏 II

官方解(贪心)

如果我们「贪心」地进行正向查找,每次找到可到达的最远位置,就可以在线性时间内得到最少的跳跃次数。
例如,对于数组 [2,3,1,2,4,2,3],初始位置是下标 0,从下标 0 出发,最远可到达下标 2。下标 0 可到达的位置中,下标 1 的值是 3,从下标 1 出发可以达到更远的位置,因此第一步到达下标 1。

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        maxPos, end, step = 0, 0, 0
        for i in range(n - 1):
            if maxPos >= i:
                maxPos = max(maxPos, i + nums[i])
                if i == end:
                    end = maxPos
                    step += 1
        return step

自己有参考的解法

# 之前看评论,说用if比用max好像要快些……
class Solution:
    def jump(self, nums: List[int]) -> int:
        count=0
        begin,end=0,0
        while endnowmax:
                    nowmax=i+nums[i]
            begin,end=end+1,nowmax
            count+=1
        return count

5.6

题目链接

983. 最低票价

很喜欢的解法(DP,从前向后)

参考题解:【熊猫刷题Python3】一维动态规划,易懂(附视频题解)

对于一年中的任意一天:
首先考虑当前天数是否在 days 中,如果不在,那我们可以贪心地选择不买。这是因为如果今天不用出行,那么也不必购买通行证,并且通行证越晚买越好。
如果在的话,我们就要从三种购买方式中选择一种花费费用最少的,即如果想到达第 i 天,就需要从 i 的前1或7或30天的后一位置花费对应cost[0]、cost[1]、cost[2]的钱才能到第 i 天。

class Solution:
    def mincostTickets(self, days: List[int], costs: List[int]) -> int:
        dp=[0 for i in range(days[-1]+1)]
        index=0
        for i in range(days[0],len(dp)):
            if i!=days[index]:
                dp[i]=dp[i-1]
            else:
                dp[i]=min(dp[max(0,i-1)]+costs[0],dp[max(0,i-7)]+costs[1],dp[max(0,i-30)]+costs[2])
                index+=1
        return dp[-1]

官方解(DP,从后向前)

我们用 dp(i) 来表示从第 i 天开始到一年的结束,我们需要花的钱。考虑到一张通行证可以让我们在「接下来」的若干天进行旅行,所以我们「从后往前」倒着进行动态规划。
但是观察方法一的递推式,我们可以看到,如果我们查询 dp(i),而第 i 天我们又不需要出行的话,那么 dp 函数会一直向后计算 dp(i+1)=dp(i+2)=dp(i+3) 一直到一年结束或者有一天我们需要出行为止。那么我们其实可以直接跳过这些不需要出行的日期,直接找到下一个需要出行的日期。

class Solution:
    def mincostTickets(self, days: List[int], costs: List[int]) -> int:
        N = len(days)
        durations = [1, 7, 30]
        @lru_cache(None)
        def dp(i):
            if i >= N:
                return 0
            ans = 10**9
            j = i
            for c, d in zip(costs, durations):
                while j < N and days[j] < days[i] + d:
                    j += 1
                ans = min(ans, dp(j) + c)
            return ans
        return dp(0)

5.7

题目链接

572. 另一个树的子树

很喜欢的解法(递归判断子树)

具体操作=官方题解1,即DFS暴力匹配,但是逻辑很清楚所以很喜欢。
参考题解:对称美!判断子树 vs 判断相等!

判断两个树是否相等的三个条件是与的关系,即:
1.当前两个树的根节点值相等;
2.并且,s 的左子树和 t 的左子树相等;
3.并且,s 的右子树和 t 的右子树相等。
而判断 t 是否为 s 的子树的三个条件是或的关系,即:
1.当前两棵树相等;
2.或者,t 是 s 的左子树;
3.或者,t 是 s 的右子树。

class Solution:
    def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
        def isSame(node1,node2):
            if not node1 and not node2:
                return True
            if not node1 or not node2:
                return False
            return isSame(node1.left,node2.left) and isSame(node1.right,node2.right) and node1.val==node2.val

        def isSub(node1,node2):
            if not node1 and not node2:
                return True
            if not node1 or not node2:
                return False
            return isSub(node1,node2.left) or isSub(node1,node2.right) or isSame(node1,node2)

        return isSub(t,s)

自己的解法(前序遍历比较结果)

前序遍历对单子树而言,得出的序列是真正的子树序列

具体思路基本上=官方题解2,即DFS序列上的串匹配。不过我不会写KMP……这个算法我就只能脑内跑结果(。以后有空试着写下……

class Solution:
    def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
        def helper(node,r):
            if not node:
                r.append('null')
                return
            r.append(str(node.val))
            helper(node.left,r)
            helper(node.right,r)
        ans1,ans2=[''],['']
        helper(t,ans1)
        helper(s,ans2)
        ans1=' '.join(ans1)
        ans2=' '.join(ans2)
        return True if ans1 in ans2 else False

官方解(树哈希)

参考题解:另一个树的子树

考虑把每个子树都映射成一个唯一的数,如果 t 对应的数字和 s 中任意一个子树映射的数字相等,则 t 是 s 的某一棵子树。

……我有点儿不懂……先马住,慢慢学习(

5.8

题目链接

221. 最大正方形

很喜欢的解法(DP)

参考题解:理解 三者取最小+1

【5月】LeetCode:我怎么还是这么菜_第1张图片

上面详解了 三者取最小 的含义:
图1:受限于左上的0
图2:受限于上边的0
图3:受限于左边的0
数字表示:以此为正方形右下角的最大边长
黄色表示:格子 ? 作为右下角的正方形区域

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        if matrix==[]:
            return 0
        matrix=[[0]*(len(matrix[0])+1)]+[[0]+list(map(int,i)) for i in matrix]
        s=0
        for i in range(1,len(matrix)):
            for j in range(1,len(matrix[0])):
                if matrix[i][j]==1:
                    matrix[i][j]=min(matrix[i-1][j-1],matrix[i-1][j],matrix[i][j-1])+1
                    s=max(s,matrix[i][j])
        return s**2

5.15

题目链接

560. 和为K的子数组

很喜欢的解法(前缀和+哈希表)

参考题解:【熊猫刷题Python3】前缀和+字典,易懂 (附视频题解)

比如我们到某一个位置 i 得到前缀和为 9,也就说从 0 位置到 i 位置的所有数字的和为 9, 如果目标 k 为 3,那么我们只需要找到当前状态下,前面出现了几次 6,就知道以 nums[i] 结尾的和为 3 的连续子数组的个数有多少个。

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        tmp=defaultdict(int)
        tmp[0]=1
        cur_sum = 0
        res = 0
        for i in nums:
            cur_sum += i
            if cur_sum - k in tmp:
                res += tmp[cur_sum - k]
            tmp[cur_sum] += 1
        return res

5.18

题目链接

152. 乘积最大子数组

官方解(DP)

参考题解:乘积最大子数组

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        maxf=nums[0]
        minf=nums[0]
        ans=nums[0]
        for i in range(1,len(nums)):
            tmp1,tmp2=maxf,minf
            maxf=max(tmp1*nums[i],max(nums[i],tmp2*nums[i]))
            minf=min(tmp2*nums[i],min(nums[i],tmp1*nums[i]))
            ans=max(ans,maxf)
        return ans

你可能感兴趣的:(【5月】LeetCode:我怎么还是这么菜)