Hot 100(二)

221. 最大正方形

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        # 动态规划
        # dp[i][j]表示以matrix[i][j]为右下角的最大正方形边长
        # 状态转移:dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 0
        
        maxSide = 0
        rows, columns = len(matrix), len(matrix[0])
        dp = [[0] * columns for _ in range(rows)]
        for i in range(rows):
            for j in range(columns):
                if matrix[i][j] == '1':
                    if i == 0 or j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
                    maxSide = max(maxSide, dp[i][j])
        
        maxSquare = maxSide * maxSide
        return maxSquare

236. 二叉树的最近公共祖先

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 函数功能为给 p 或 q 找祖先
        if not root or root == p or root == q:
            return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if not left:
            return right
        if not right:
            return left
        return root

238. 除自身以外数组的乘积

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        # # 两个数组,分别存储 i 位置左侧数字和右侧数字的乘积
        # n = len(nums)
        # l = [1 for _ in range(n)]
        # r = [1 for _ in range(n)]
        # for i in range(1, n):
        #     l[i] = l[i-1] * nums[i-1]
        # for i in range(n-2, -1, -1):
        #     r[i] = r[i+1] * nums[i+1]
        
        # res = [0 for _ in range(n)]
        # for i in range(n):
        #     res[i] = l[i] * r[i]
        
        # return res

        # O(1)时间复杂度,可以省去 r 数组,替换为一个值,动态更新
        n = len(nums)
        res = [1 for _ in range(n)]
        r = 1  # 记录右侧数字乘积
        for i in range(1, n):
            res[i] = res[i-1] * nums[i-1]
        for i in range(n-1, -1, -1):
            res[i] = res[i] * r
            r *= nums[i]
        return res

239. 滑动窗口最大值

单调队列

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        # # 优先级队列,时间复杂度 O(nlogn)
        # n = len(nums)
        # q = [(-nums[i], i) for i in range(k)]  # 默认是最小堆
        # heapq.heapify(q)

        # res = [-q[0][0]]
        # for i in range(k, n):
        #     heapq.heappush(q, (-nums[i], i))
        #     # 判断堆顶元素是否在窗口内
        #     while q[0][1] < i-k+1:
        #         heapq.heappop(q)
        #     # 更新 res
        #     res.append(-q[0][0])
        
        # return res

        # 单调队列
        # 新加入元素如果比队尾元素大,就把比新加入元素小的都剔除,因为不可能是最大值了,新元素在后面
        # 如果队首元素在窗口内,队首就是最大值
        n = len(nums)
        q = []  # 存储元素的索引,如果存储值的话,无法判断队首元素是否在窗口内
        for i in range(k):
            while q and nums[i] >= nums[q[-1]]:
                q.pop(-1)
            q.append(i)
        
        res = [nums[q[0]]]
        for i in range(k, n):
            # 新元素入队
            while q and nums[i] >= nums[q[-1]]:
                q.pop(-1)
            q.append(i)
            # 判断队首元素是否在窗口内
            while q[0] <= i - k:
                q.pop(0)
            res.append(nums[q[0]])
        return res

279. 完全平方数

class Solution:
    def numSquares(self, n: int) -> int:
        # 动态规划
        # 状态转移:dp[i] = min(dp[i], dp[i - j*j] + 1)
        dp = [float('inf') for _ in range(n+1)]
        dp[0] = 0
        dp[1] = 1
        for i in range(2, n+1):
            for j in range(1, int(i**0.5)+1):
                dp[i] = min(dp[i], dp[i - j*j] + 1)
        return dp[n]

283. 移动零

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # j = -1  # j标识第一个 0 的位置,与后面非 0 的数交换
        # for i in range(len(nums)):
        #     if nums[i] == 0:
        #         if j == -1:
        #             j = i
        #     else:
        #         if j != -1:
        #             nums[i], nums[j] = nums[j], nums[i]
        #             j += 1

		# 两个指针i和j
        j = 0
        for i in range(len(nums)):
			# 当前元素!=0,就把其交换到左边,等于0的交换到右边,i 和 j 一起移动
            # 如果是 0,j 不动,标识 0 的位置
            if nums[i]:
                nums[j],nums[i] = nums[i],nums[j]
                j += 1

        

287. 寻找重复数

class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        # 看做链表,如果存在重复数字,则链表中存在环
        # 找到环的入口
        fast = 0
        slow = 0
        while True:
            fast = nums[nums[fast]]
            slow = nums[slow]
            if(fast == slow):
                break
        
        # f = 2s and f-s = nb; s = nb and f = 2nb
        # 从头统计走过的步数k,当k = a + nb时,正好在入口节点
        # 因此 让 slow 再向前走 a 步,正好到入口节点
        finder = 0
        while True:
            finder = nums[finder]
            slow = nums[slow]
            if slow == finder:
                break     
        
        return slow

297. 二叉树的序列化与反序列化

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Codec:

    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        # # BFS
        # if not root: 
        #     return ""
        # q = deque()
        # q.append(root)
        # res = ''
        # while q:
        #     node = q.popleft()
        #     if node != None:
        #         res += str(node.val) + ','
        #         q.append(node.left)
        #         q.append(node.right)
        #     else:
        #         res += 'X,'
        # return res

        # DFS
        if root == None: return 'X,'
        leftserilized = self.serialize(root.left)
        rightserilized = self.serialize(root.right)
        return str(root.val) + ',' + leftserilized + rightserilized
        

    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        # # BFS
        # if not data: return None
        # data = data.split(',')
        # root = TreeNode(data.pop(0))
        # q = [root]
        # while q:
        #     node = q.pop(0)
        #     if data:
        #         val = data.pop(0)
        #         if val != 'X':
        #             node.left = TreeNode(val)
        #             q.append(node.left)
        #     if data:
        #         val = data.pop(0)
        #         if val != 'X':
        #             node.right = TreeNode(val)
        #             q.append(node.right)
        # return root 

        data = data.split(',')
        root = self.buildTree(data)
        return root 

    def buildTree(self,data):
        val = data.pop(0)
        if val == 'X': return None
        node = TreeNode(val)
        node.left = self.buildTree(data)
        node.right = self.buildTree(data)
        return node

# Your Codec object will be instantiated and called as such:
# ser = Codec()
# deser = Codec()
# ans = deser.deserialize(ser.serialize(root))

301. 删除无效的括号

class Solution:
    def __init__(self):
        self.max_len = 0
        self.max_valid = 0  # 最长可能的括号数
        self.res_set = set()
        self.n = 0

    def removeInvalidParentheses(self, s: str) -> List[str]:
        # DFS
        # 全局变量记录最长长度 & 最终结果集合

        @lru_cache(None)
        def dfs(i, cur, score):
            # print(i, cur, score)
            # 剪枝
            if score < 0 or score > self.max_valid:
                return
            # 截止条件: 到最后一个字符, score=0为合法字符串 & 长度大于当前最大 len,更新
            if i == self.n:
                if score == 0 and len(cur) >= self.max_len:
                    if len(cur) > self.max_len:
                        self.res_set.clear()
                    self.res_set.add(cur)
                    self.max_len = len(cur)
                return
            # 做选择
            c = s[i]
            if c == '(':
                dfs(i+1, cur+c, score+1)
                dfs(i+1, cur, score)
            elif c == ')':
                dfs(i+1, cur+c, score-1)
                dfs(i+1, cur, score)
            else:
                dfs(i+1, cur+c, score)

        self.n = len(s)
        l, r = 0, 0
        for ch in s:
            if ch == '(':
                l += 1
            elif ch == ')':
                r += 1
        self.max_valid = min(l, r)
        # print(s, self.max_valid)
        dfs(0, "", 0)
        return list(self.res_set)

309. 最佳买卖股票时机含冷冻期

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 动态规划
        if not prices:
            return 0
        
        n = len(prices)
        # f[i][0]: 手上持有股票的最大收益
        # f[i][1]: 手上不持有股票,并且处于冷冻期中的累计最大收益
        # f[i][2]: 手上不持有股票,并且不在冷冻期中的累计最大收益
        f = [[-prices[0], 0, 0]] + [[0] * 3 for _ in range(n - 1)]
        for i in range(1, n):
            f[i][0] = max(f[i - 1][0], f[i - 1][2] - prices[i])
            f[i][1] = f[i - 1][0] + prices[i]
            f[i][2] = max(f[i - 1][1], f[i - 1][2])
        
        return max(f[n - 1][1], f[n - 1][2])

312. 戳气球

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        # # 自顶向下,分治
        # # 把戳气球操作倒过来,看做是每次增加一个气球
        # n = len(nums)
        # val = [1] + nums + [1]

        # @lru_cache(None)
        # def solve(i, j):
        #     if i >= j - 1:
        #         return 0
        #     res = 0
        #     for k in range(i+1, j):
        #         temp = val[i] * val[j] * val[k]
        #         temp += solve(i, k) + solve(k, j)
        #         res = max(res, temp)
        #     return res
        
        # return solve(0, n+1)

        # 动态规划
        n = len(nums)
        rec = [[0] * (n + 2) for _ in range(n + 2)]
        val = [1] + nums + [1]

        # 注意遍历顺序,i 需要倒序,j 正序
        # 原因是 dp[i][j] 依赖 dp[i][k] 其中 k<j, dp[i][k]位于 dp[i][j]同行左侧,表示 j 需要正序遍历
        # dp[i][j] 依赖 dp[k][j], 其中 k>i, dp[k][j] 位于 dp[i][j]同列下侧,表示 i 需要倒序遍历
        for i in range(n - 1, -1, -1):
            for j in range(i + 2, n + 2):
                for k in range(i + 1, j):
                    total = val[i] * val[k] * val[j]
                    total += rec[i][k] + rec[k][j]
                    rec[i][j] = max(rec[i][j], total)
        
        return rec[0][n + 1]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值