LeetCode | 1-D Dynamic Programming

2022-4-25

70. Climbing Stairs

def climbStairs(n: int) -> int:
    ans = [0] * (n + 1)
    ans[0] = ans[1] = 1

    for i in range(2, n + 1):
        ans[i] = ans[i - 1] + ans[i - 2]
    return ans[-1]

def climbStairs2(n: int) -> int:
    step1, step2 = 1, 1
    for i in range(2, n + 1):
        tmp = step1 + step2
        step1 = step2
        step2 = tmp
    return step2

746. Min Cost Climbing Stairs

def minCostClimbingStairs(cost: List[int]) -> int:
    for index in range(2, len(cost)):
        cost[index] += min(cost[index - 1], cost[index - 2])
    return min(cost[-1], cost[-2])

198. House Robber

  • 边界处理直接开了新的money list2333;之前做的一版对边界是单独处理的;
  • rob2这里的思路实际上是考虑在Index位置的金额最大值取决于index-2及index-3的最大值,不需要考虑前述[:index-1](不包括Index-1)的情况,因为偷盗的金额是正数,假设我们在index时考虑index-4,它实际上是可以跳到index-2上再跳到index上,也就是说在考虑Index-2的时候就把index-4等考虑进去了!
  • rob3的思路【neetcode yyds】!妙哇!
    • 考虑每个房子,你有两种选择:偷或者不偷;ps:money[index]表示处于Index处当前偷的最大金额
    • 假设你在房子n,你选择偷,那么当前的偷的总金额为房子n偷的加上房子1到n-2房子中偷得到最大值,即nums[n]+money[n-2] (注意这里后面可以简化);假设你现在不偷,那么当前你拥有的偷盗金额就是money[n-1]!【所以实际上我们只需要动态存储2个元素就够够了】
    • 综上所述:money[n] = max(nums[n]+money[n-2], money[n-1])
    • 当然可以考虑就地修改nums list不用开辟新的money list;
  • 对比一下rob2中的money中的每位都是在考虑了在index时,偷了的情况下的最大偷盗金额;而rob3是把在index下偷和不偷的状态一起考虑了~
def rob1(nums: List[int]) -> int:
	if len(nums)==1: return nums[0]
	if len(nums)==2: return max(nums[-1], nums[-2])
	for i in range(2, len(nums)):
		nums[i] = nums[i] + max(nums[0:i-1])
	return max(nums[-1], nums[-2])
	
def rob2(nums: List[int]) -> int:
    money = [0, 0, 0]
    money.extend(nums)
    for index in range(3, 3 + len(nums)):
        money[index] = max(money[index - 2], money[index - 3]) + money[index]
    return max(money[-1], money[-2])
    
def rob3(nums: List[int]) -> int:
    rob1, rob2 = 0, 0
    # [rob1, rob2, n, n+1, n+2, ...]
    for num in nums:
        tmp = max(num + rob1, rob2)
        rob1 = rob2
        rob2 = tmp
    return rob2

213. House Robber II

  • 本题很自然的一个思路就是复用House Robber的模块;区别是II在I的基础上加了一个限制:头尾是连接的(circle);所以呢就是考虑在头部切断!变成链状的情况就可以复用模块I啦;
    • 第一个房子偷:helper(nums[:-1])
    • 第一个房子不偷:helper(nums[1:])
    • 但是要注意当nums的长度为1时,nums[:-1]和nums[1:]都是[],所以单独加了一条边界处理;neetcode这里是直接把nums[0]加到最后的return中,妙哇!
def rob(nums: List[int]) -> int:
    if len(nums) == 1: return nums[0]
    return max(helper(nums[:-1]), helper(nums[1:]))
def rob(nums: List[int]) -> int:
	return max(nums[0], helper(nums[:-1]), helper(nums[1:]))

def helper(nums: List[int]) -> int:
    rob1, rob2 = 0, 0
    for num in nums:
        tmp = max(num + rob1, rob2)
        rob1 = rob2
        rob2 = tmp
    return rob2

5. Longest Palindromic Substring

  • 参考neetcode+评论区改进!后来发现是英版lc中的most votes的第二个!
    • 主要思路:对s中的元素s[index],逐渐左右散开,判断是否是回文;【妙蛙种子的日常简直就是!之前想到回文串只会从外向里check,没想到还可以从里到外哇!】
    • 学习的点:
      1. 注意v1中slice的时间复杂度要考虑进去!(评论区的朋友赞一个)
      2. 可以看到v1中其实还有可复用的模块;v2做了改进!
      3. 奇偶情况的处理赞一个!【要不是看到这个解法,我可能又从mod出发讨论奇偶了衰orz】
def longestPalindrome(s: str) -> str:
    res = ''
    for i in range(len(s)):
        # odd case: 'aba'
        l, r = i, i
        while l >= 0 and r < len(s) and s[l] == s[r]:
            if r - l + 1 > len(res):
                res = s[l: r + 1]
            r += 1
            l -= 1
            
		# even case: 'abb'
        l, r = i, i + 1
        while l >= 0 and r < len(s) and s[l] == s[r]:
            if r - l + 1 > len(res):
                res = s[l: r + 1]
            r += 1
            l -= 1
    return res

def longestPalindrome2(s: str) -> str:
    res = ''
    for i in range(len(s)):
        # odd case: 'aba'
        tmp1 = helper(s, i, i)
        if len(tmp1) > len(res):
            res = tmp1
        
        # even case: 'abb'
        tmp2 = helper(s, i, i + 1)
        if len(tmp2) > len(res):
            res = tmp2
    return res

def helper(s, i, j):
    while i >=0 and j < len(s) and s[i] == s[j]:
        i -= 1
        j += 1
    return s[i+1: j]

647. Palindromic Substrings

  • 站在巨人的肩膀上!【思路同#5,故略】
def countSubstrings(s):
    count = 0
    for i in range(len(s)):
        count = helper(s, i, i, count)
        count = helper(s, i, i + 1, count)
    return count

def helper(s, i, j, count):
    while i >= 0 and j < len(s) and s[i] == s[j]:
        count += 1
        i -= 1
        j += 1
    return count

91. Decode Ways

果然对字符串的处理生得不行orz,硬给他int()了哈哈哈哈哈哈

  • 主要思路:
    • #70走楼梯的进阶版(好吧就是换了个壳撒)
    • 当前index的decode ways只取决于index-1和index-2位置的decode ways【当然这是由题目的限制得到的,1~26,最少一位,最多两位】
      • 考虑index-1: 相当于直接在index-1的decode ways的每个项 加上单个decode(当然要判断这个单个decode是不是合法的helper1)
      • 考虑index-2:相当于在index-2的decode ways的每个项 加上由两位index-1, index构成的两位数(当然这里也是要判断这个两位数是不是合法的helper2,check一下是不是10~26,这里就把示例3中的case就考虑到了!)
def numDecodings(s):
    a, b = 0, 1
    for i in range(len(s)):
        tmp1 = tmp2 = 0
        if helper1(s, i):
            tmp1 = b
        if helper2(s, i - 1, i):
            tmp2 = a
        tmp = tmp1 + tmp2
        a = b
        b = tmp
    return b


def helper1(s, i):
    if int(s[i]) != 0:
        return True
    return False


def helper2(s, i, j):
    if int(s[i]) * 10 + int(s[j]) >= 10 and int(s[i]) * 10 + int(s[j]) < 27:
        return True
    return False

明天看一下别人的解法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值