Leetcode_3-18


123. 买卖股票的最佳时机 III

困难

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

**注意:**你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
     随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入:prices = [7,6,4,3,1] 
输出:0 
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

示例 4:

输入:prices = [1]
输出:0

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 105

动态规划

824ms 击败24.51%

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0

        dp = [[0 for _ in range(5)] for _ in range(len(prices))]

        dp[0][0] = 0
        dp[0][1] = -prices[0]
        dp[0][2] = 0
        dp[0][3] = -prices[0]
        dp[0][4] = 0

        for i in range(1, len(prices)):
            dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1])
            dp[i][2] = max(dp[i-1][1] + prices[i], dp[i-1][2])
            dp[i][3] = max(dp[i-1][2] - prices[i], dp[i-1][3])
            dp[i][4] = max(dp[i-1][3] + prices[i], dp[i-1][4])

        return max(dp[-1][2], dp[-1][4])

nextpage

188. 买卖股票的最佳时机 IV

困难

给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。

**注意:**你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入:k = 2, prices = [2,4,1]
输出:2
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。

示例 2:

输入:k = 2, prices = [3,2,6,5,0,3]
输出:7
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
     随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

提示:

  • 1 <= k <= 100
  • 1 <= prices.length <= 1000
  • 0 <= prices[i] <= 1000

动态规划

class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        if not prices:
            return 0

        dp = [[0 for _ in range(2*k+1)] for _ in range(len(prices))]

        for i in range(2*k+1):
            if i % 2 == 1:
                dp[0][i] = -prices[0]

        for i in range(1, len(prices)):
            for j in range(1,2*k+1):
                if j % 2 == 1:
                    dp[i][j] = max(dp[i-1][j-1] - prices[i], dp[i-1][j])
                else:
                    dp[i][j] = max(dp[i-1][j-1] + prices[i], dp[i-1][j])

        return dp[-1][-1]

nextpage

445. 两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例1:

img

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

示例2:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]

示例3:

输入:l1 = [0], l2 = [0]
输出:[0]

列表转换法

class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        l1_stack = []
        l2_stack = []

        while l1:
            l1_stack.append(l1.val)
            l1 = l1.next
        while l2:
            l2_stack.append(l2.val)
            l2 = l2.next

        if len(l1_stack) < len(l2_stack):
            l1_stack, l2_stack = l2_stack, l1_stack

        carry = 0
        for i in range(len(l1_stack)):
            if len(l2_stack)-i > 0:
                tmp = l1_stack[-1-i] + l2_stack[-1-i] + carry
            else:
                tmp = l1_stack[-1-i] + carry

            l1_stack[-1-i] = tmp%10
            carry = tmp//10

        if carry:
            l1_stack.insert(0,carry)
        
        host = ListNode(l1_stack[0])
        cur = host
        for i in range(1,len(l1_stack)):
            cur.next = ListNode(l1_stack[i])
            cur = cur.next

        return host

next page


513. 找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:

img

输入: root = [2,1,3]
输出: 1

示例 2:

img

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

提示:

  • 二叉树的节点个数的范围是 [1,104]
  • -231 <= Node.val <= 231 - 1

队列法(BFS)

from typing import Optional
from collections import deque

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        dq = deque()
        dq.append(root)
        dq.append("#")

        ans = root.val

        while not (len(dq) == 1 and dq[0] == "#"):
            tmp = dq.popleft()
            if tmp == "#":
                if dq[0] != "#":
                    ans = dq[0].val
                dq.append("#")
                continue

            if tmp.left:
                dq.append(tmp.left)
            if tmp.right:
                dq.append(tmp.right)
            
        return ans

next page


617. 合并二叉树

给你两棵二叉树: root1root2

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

img

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

提示:

  • 两棵树中的节点数目在范围 [0, 2000]
  • -104 <= Node.val <= 104

递归法

# 方法一 我自己写的 非常冗余
class Solution:
    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:

        def merge(root1,root2,root1_parent,direction):
            if root1 == None and root2 == None:
                return
            elif root1 == None or root2 == None:
                if root2:
                    if direction == "left":
                        root1_parent.left = root2
                    elif direction == "right":
                        root1_parent.right = root2
                return

            root1.val += root2.val
            merge(root1.left,root2.left,root1,"left")
            merge(root1.right,root2.right,root1,"right")

        if root1 == None:
            return root2
        merge(root1,root2,root1,"")
        return root1

# 方法二 精简递归
class Solution:
    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root1:
            return root2
        if not root2:
            return root1
        
        root1.val += root2.val
        root1.left  = self.mergeTrees(root1.left,root2.left)
        root1.right = self.mergeTrees(root1.right,root2.right)

        return root1

next page


1963. 使字符串平衡的最小交换次数

给你一个字符串 s下标从 0 开始 ,且长度为偶数 n 。字符串 恰好n / 2 个开括号 '['n / 2 个闭括号 ']' 组成。

只有能满足下述所有条件的字符串才能称为 平衡字符串

  • 字符串是一个空字符串,或者
  • 字符串可以记作 AB ,其中 AB 都是 平衡字符串 ,或者
  • 字符串可以写成 [C] ,其中 C 是一个 平衡字符串

你可以交换 任意 两个下标所对应的括号 任意 次数。

返回使 s 变成 平衡字符串 所需要的 最小 交换次数。

示例 1:

输入:s = "][]["
输出:1
解释:交换下标 0 和下标 3 对应的括号,可以使字符串变成平衡字符串。
最终字符串变成 "[[]]" 。

示例 2:

输入:s = "]]][[["
输出:2
解释:执行下述操作可以使字符串变成平衡字符串:
- 交换下标 0 和下标 4 对应的括号,s = "[]][][" 。
- 交换下标 1 和下标 5 对应的括号,s = "[[][]]" 。
最终字符串变成 "[[][]]" 。

示例 3:

输入:s = "[]"
输出:0
解释:这个字符串已经是平衡字符串。

提示:

  • n == s.length
  • 2 <= n <= 106
  • n 为偶数
  • s[i]'['']'
  • 开括号 '[' 的数目为 n / 2 ,闭括号 ']' 的数目也是 n / 2

标准题解

class Solution:
    def minSwaps(self, s: str) -> int:
        cnt = mincnt = 0
        for ch in s:
            if ch == '[':
                cnt += 1
            else:
                cnt -= 1
                mincnt = min(mincnt, cnt)
        return (-mincnt + 1) // 2

我的做法(超时57/59 )

class Solution:
    def minSwaps(self, s: str) -> int:
        def checkEffctive(s):
            i, depth = 0, 0

            while i < len(s):
                while i < len(s) and s[i] == "[":
                    i += 1
                    depth += 1
                while i < len(s) and s[i] == "]":
                    i += 1
                    depth -= 1
                if depth < 0:
                    return False

            if depth != 0:
                return False
            return True

        def swap(a,b):
            a,b = b,a

        s = list(s)
        ans = 0
        left = 0
        right = len(s) - 1

        while left < right and not checkEffctive(s):
            while left < right and s[left] != "]":
                left += 1
            while left < right and s[right] != "[":
                right -= 1
            s[left], s[right] = s[right], s[left]
            ans += 1

        return ans
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值