2020-02-13
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
最基本的问题: dp[i] = dp[i-1] + dp[ i - 2]
class Solution { public: int climbStairs(int n) { int dp[2]; dp[0] = dp[1] = 1; for(int i = 1; i < n; i++){ int temp = dp[0]+dp[1]; dp[0] = dp[1]; dp[1] = temp; } return dp[1]; } };
198. 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
class Solution { public: int rob(vector<int>& nums) { int n = nums.size(); if(n == 0) return 0; vector<int> dp(n+1); dp[1] = nums[0]; for(int i = 2; i <= n; i++) dp[i] = max(dp[i-1],dp[i-2]+nums[i-1]); return dp[n]; } };
213. 打家劫舍 II(环形街道)
从 1 - n-1,从2到n执行两遍:
class Solution { public: int rob(vector<int>& nums) { int n = nums.size(); if(n == 0) return 0; if(n == 1) return nums[0]; vector<int> dp(n+1); vector<int> d(n+1); dp[1] = nums[0]; for(int i = 2; i <= n-1; i++) dp[i] = max(dp[i-1],dp[i-2]+nums[i-1]); for(int i = 2; i <=n; i++) d[i] = max(d[i-1],d[i-2]+nums[i-1]); return max(dp[n-1],d[n]); } };
空间优化加函数
class Solution { public: int rob(vector<int>& nums) { int n = nums.size(); if(n == 0) return 0; if(n == 1) return nums[0]; return max(rob(nums,0,n-2),rob(nums,1,n-1)); } int rob(vector<int>&nums,int l,int r){ int pre2 = 0,pre1 = 0; for(int i = l; i <= r; i++){ int cur = max(pre1,pre2 + nums[i]); pre2 = pre1; pre1 = cur; } return pre1; } };
信件错排(较难)
题目描述:有 N 个 信 和 信封,它们被打乱,求错误装信方式的数量。
定义一个数组 dp 存储错误方式数量,dp[i] 表示前 i 个信和信封的错误方式数量。假设第 i 个信装到第 j 个信封里面,而第 j 个信装到第 k 个信封里面。根据 i 和 k 是否相等,有两种情况:
- i==k,交换 i 和 j 的信后,它们的信和信封在正确的位置,但是其余 i-2 封信有 dp[i-2] 种错误装信的方式。由于 j 有 i-1 种取值,因此共有 (i-1)*dp[i-2] 种错误装信方式。
- i != k,交换 i 和 j 的信后,第 i 个信和信封在正确的位置,其余 i-1 封信有 dp[i-1] 种错误装信方式。由于 j 有 i-1 种取值,因此共有 (i-1)*dp[i-1] 种错误装信方式。
综上所述,错误装信数量方式数量为:
母牛生产
题目描述:假设农场中成熟的母牛每年都会生 1 头小母牛,并且永远不会死。第一年有 1 只小母牛,从第二年开始,母牛开始生小母牛。每只小母牛 3 年之后成熟又可以生小母牛。给定整数 N,求 N 年后牛的数量。
第 i 年成熟的牛的数量为:
总结:斐波那契数列类的问题是一维类型的dp,关键是找到递推关系:
2020-02-15
91. 解码方法
一条包含字母 A-Z 的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
分析:判断当前数字,和前一个数字,dp[i] = dp[ i- 1] (有条件)+ dp[ i- 2](有条件)
class Solution { public: int numDecodings(string s) { int n = s.size(); if(n == 0) return 0; vector<int> dp(n+1); dp[0] = 1; // 0 的情况 dp[1] = s[0] == '0'?0:1; for(int i = 2; i <= n; i++){ /*1.可拆分时:f(n) = f(n-1) 2.可组合时:f(n) = f(n-2) 3.既可拆分又可组合时:f(n) = f(n-1) + f(n-2)*/ int one = s[i-1]-'0'; if( one != 0)//注意条件 dp[i]+= dp[i-1]; int two = (s[i-2]-'0')*10+s[i-1]-'0'; if(two >= 10 && two <= 26)//注意条件 dp[i] += dp[i-2]; } return dp[n]; } };