力扣75——一维动态规划

总结leetcode75中的一维动态规划算法题解题思路。
上一篇:力扣75——回溯

1 第 N 个泰波那契数

题目

泰波那契序列 Tn 定义如下: 

T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2

给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

题解:
动态规划。按照公式进行迭代。这题的特点是,如何不使用临时变量而只用3个变量进行迭代。

class Solution {
public:
	int tribonacci(int n) {
        if (n==0) return 0;
        if (n<3) return 1;
		double n0 = 0, n1 = 1, n2 = 1;
		for (int i = 0; i <= n - 3; ++i) {
			n2 = n0 + n1 + n2;
			n1 = n2 - n1 - n0;
			n0 = n2 - n1 - n0;
            /*
			while (n2 > pow(2, 31)) {
				n2 -= pow(2, 31);
			}
			while (n1 > pow(2, 31)) {
				n1 -= pow(2, 31);
			}
            */
		}

		return n2;
	}
};

2 使用最小花费爬楼梯

题目

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。
一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

 

题解1:题目是想找到一种方法,使得爬完这个楼梯的费用最少。如果一个人想爬到楼梯上面去,最后就只有2种可能从第cost.size-1向上走一步到达;从第cost.size-2向上走2步到达。那么,只要算出分别爬到第cost.size-1和第cost.size-2所需的费用,然后再选择较小的那一个,即为所求结果。
所以可以从第1个台阶开始算,算出一个人爬到这个台阶的费用,然后往上递推计算即可。

class Solution {
public:
	int minCostClimbingStairs(vector<int>& cost) {
		vector<int> result(cost.size(), 0);
		result[0] =cost[0];
		result[1] = cost[1];
		for (int i = 2; i < cost.size(); ++i) {
			result[i] = result[i - 1] > result[i - 2] ? result[i - 2] + cost[i] : result[i - 1] + cost[i];
		}
		return min(result[cost.size() - 1], result[cost.size() - 2]);
	}
};

题解2:
同题解1。但是空间复杂度更低。因为我们只是需要最终结果,所以只需要2个变量来递推就行,不需要一个vector

class Solution {
public:
	int minCostClimbingStairs(vector<int>& cost) {
		//vector<int> result(cost.size(), 0);
		int result0 = cost[0], result1 = cost[1], tmp = 0;
		for (int i = 2; i < cost.size(); ++i) {
			tmp = result1;
			result1 = result1 > result0 ? result0 + cost[i] : result1 + cost[i];
			result0 = tmp;
		}
		return min(result0, result1);
	}
};

3 打家劫舍

题目

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约
因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统
会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能
够偷窃到的最高金额。

题解:
动态规划。与题目2类似,只是这次需要3个变量来递推。
问题分析:直接看这一排房屋的最后两个,如果想要偷最多,最后这两个房子肯定是要偷一个的。可以证明,如果这两个房子都不偷,得到的金额为a,那么a+最后一个房子的钱,肯定是大于a的。
思路分析:为了确定它是偷最后一个还是偷倒数第二个,还需要知道倒数第三个和倒数第四个要不要偷。所以可以从第一个开始计算,然后递推求解。
解题思路:从第一个房间开始递推,计算偷窃该房子后,金额是多少。设当前房子为i,如果进去偷,则第i-1是不能偷的。那么是2种可能,偷完第i-3后直接偷第i;偷完第i-2后,直接偷第i。具体选择依据偷完它们后哪个金额更大来决定。

class Solution {
public:
	int rob(vector<int>& cost) {
		if (cost.size() < 2) return cost[0];
		int result0 = 0, result1 = cost[0], result2 = cost[1], tmp = 0;
		for (int i = 2; i < cost.size(); ++i) {
			tmp = result2;
			result2 = result1 > result0 ? result1 + cost[i] : result0 + cost[i];
			result0 = result1;
			result1 = tmp;

		}
		return max(result2, result1);
	}
};

4 多米诺和托米诺平铺

题目

有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 "L" 的托米诺形。两种形状都
可以旋转。

给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。返回对 109 + 7 取模 的值。
平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻
单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。

题解:
动态规划。对于每一列,如果其左边均铺满瓷砖,右侧未铺,则其总共有4种状态:
一个正方形都没有被覆盖,记为状态0;
只有上方的正方形被覆盖,记为状态1;
只有下方的正方形被覆盖,记为状态2;
上下两个正方形都被覆盖,记为状态3。

通过递推迭代,即可得到结果。


class Solution {
public:
    const long long mod = 1e9 + 7;
    int numTilings(int n) {
        vector<vector<long long>> dp(n + 1, vector<long long>(4));
        dp[0][3] = 1;
        for (int i = 1; i <= n; i++) {
            dp[i][0] = dp[i - 1][3];
            dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % mod;
            dp[i][2] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
            dp[i][3] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3]) % mod;
        }
        return dp[n][3];
    }
};


1- 4解题总结

题目特点:一个位置的状态,受到之前位置的影响。
解题方法:从第一个位置开始,计算出它达到每个状态的得分,然后递推下一个位置。
解题重点1:如何将题目转化为状态递推问题。
解题重点2:如何用更少的变量来递推。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小欣CZX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值