leetcode - 198,213. House Robber(II) & 91. Decode Ways

算法系列博客之Dynamic Programming

本篇博客将运用动态规划的思想来解决leetcode上198,213和91号问题


问题描述:

198 House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

题目描述了这样一个模型:
给出一个线性列表nums,每个元素有一个非负权值,求一个最大权值和
求权值和有一个限制——不能同时将任意两个相邻元素作为其加数因子

为了使权值最大化,自然是希望加的越多越好,往后加值的过程依赖于前面已得出的最大权值和
假定most[i]表示从第0个元素开始到第i个元素得到的最大权值和,则:
    most[i] = max(most[i-1], most[i-2] + nums[i])

正确性简单说明,most[i-1]得出的结果只能来源于两种:
    · nums[i-1]+most[i-3],这种情况下,nums[i]作为权值和的加数因子
    · most[i-2],这种情况下,nums[i]必然作为权值和的加数因子
因而,在整个线性规划的过程中,都是在尽最大可能加上更多的元素,整个过程结束之后,必然得到最大值。
由状态转移方程可以看出它只依赖于前两个状态,因此可以只存储三个状态以降低空间复杂度

class Solution(object):
    def rob(self, nums):
        if len(nums) == 0: return 0
        if len(nums) == 1: return nums[0]
        most1 = nums[0]
        most2 = nums[1] if nums[1] > nums[0] else nums[0]
        if len(nums) == 2: return most2
        for i in range(2, len(nums)):
            most3 = max(most2, most1+nums[i])
            most1 = most2
            most2 = most3
        return most3

时间复杂度分析,仅仅只是遍历了数组,且每个元素对应常数次指令数,是为O(n)
空间复杂度分析,整个算法仅仅只额外保存了三个状态,每个状态为一个整数,是为O(1)

213 House Robber II

Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

新的模型与之前不同的是这是一个环形列表
看似复杂了很多,即每个元素是否作为加数因子不仅依赖于前面还需依赖于后面
但,其实不需要这样考虑,依赖于后面就等同于后面的元素依赖于前面

如果我们选择一个起点,规定一个方向,整个过程仍然按照原来的模型进行运算
不难发现唯一出现问题的地方就是终点元素元素是否应该作为加数,而这个问题的根本原因在于它与起点元素被定义为相邻元素,那么只需考虑下面两种情况:
    · 起点元素作为了加数因子,终点元素一定就不能作为加数因子,因而最大权值和应该等于之前所定义的most[len - 1]
    · 起点元素没有作为加数因子,则假性去掉这个元素,起点顺移一位,终点元素是否作为加数因子交由算法自行决定

class Solution(object):
    def rob(self, nums):
        if len(nums) == 0: return 0
        if len(nums) == 1: return nums[0]
        if len(nums) == 2: return nums[0] if nums[0] > nums[1] else nums[1]
        return max(self.robber(nums[0:-1]), self.robber(nums[1:]))
    def robber(self, nums):
        if len(nums) == 1: return nums[0]
        most1 = nums[0]
        most2 = nums[1] if nums[1] > nums[0] else nums[0]
        if len(nums) == 2: return most2
        for i in range(2, len(nums)):
            most3 = max(most2, most1+nums[i])
            most1 = most2
            most2 = most3
        return most3

复杂度分析,时间上,仅仅只是两次执行之前的算法,因而仍为O(n);
空间上,较之前没有新占用任何空间,因而也仍为O(1)

91 Decode Ways

A message containing letters from A-Z is being encoded to numbers using the following mapping:
  ‘A’-> 1; ‘B’-> 2   … ‘Z’-> 26
Given an encoded message containing digits, determine the total number of ways to decode it.

For example,
Given encoded message “12”, it could be decoded as “AB” (1 2) or “L” (12).
The number of ways decoding “12” is 2.

将这题写到这篇的原因是,它和前面的规划策略相似,只是情况略微复杂一点
这里每个字符仍然可能有两种解码形式,与前面的字符一起解码或者单独解码
而复杂一点的来源在于与前面一起解码必须满足一定的约束条件

假设alone[i]表示第i个字符单独解码从起始到第i个字符的总解码方式数
together[i] 表示第i个字符与前一个子符一起解码的总解码方式数
则其状态转移方程如下:

如果s[i] != '0'
    alone[i] = alone[i-1] + together[i-1]
否则,alone[i] = 0

如果s[i-1] == '1' 或者 s[i-1] == '2' && '0'<=s[i]<='6'
    together[i] = alone[i-2] + together[i-2] = alone[i-1]
否则,together[i] = 0

同样,可以看出后一状态仅仅依赖于前一状态,因此只需要存储两个状态

class Solution(object):
    def numDecodings(self, s):
        if len(s) == 0: return 0
        if s[0] == '0': return 0
        alone = alone_pre = 1       # ways that s[i] decoded alone
        together = together_pre = 0 # ways that s[i] decoded with s[i-1]

        for i in range(1, len(s)):
            alone = alone_pre + together_pre if s[i] != '0' else 0
            together = alone_pre if s[i-1] == '1' or (s[i-1] == '2' and s[i] < '7') else 0
            alone_pre = alone
            together_pre = together
        return alone + together

时间复杂度分析,仅仅只是遍历一次s,遍历单位仅含常数条无嵌套指令,因而O(n)
空间复杂度分析,额外使用四个整形变量,因而O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值