LeetCode刷题总结(C语言版)动态规划类

编程总结

每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧


动态规划 – 自下而上的解决问题;记忆化搜索,自顶向下的解决问题。
动态规划
– 动态规划–将原问题拆解成若干子问题,同时保存子问题的答案,使每个子问题只求解一次,最终获得原问题的答案。

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶
  2. 2 阶
    示例 2:
    输入: 3
    输出: 3
    解释: 有三种方法可以爬到楼顶。
  3. 1 阶 + 1 阶 + 1 阶
  4. 1 阶 + 2 阶
  5. 2 阶 + 1 阶
// 递归 
int climbStairs(int n){
    if (n <= 2) {
        return n;
	}

    return climbStairs(n - 1) + climbStairs(n - 2);
}
// 记忆化搜索 -- 自顶往下
int memo[64] = {0};
int climbStairs(int n) {
    if (n <= 2) {
        return n;
	}
	// 如果满足条件则直接返回记忆数组里的值,减少递归次数
	if (n < 64 && memo[n] != 0) {
		return memo[n];
	}
    // 不满足条件才进行递归 O(n)
	memo[n] = climbStairs(n-1) + climbStairs(n-2);
	
	return memo[n];
}
// 动态规划 -- 自下往上
int climbStairs(int n){
    int i, a1, a2, res;
    if (n <= 2) {
        return n;
	}
    a1 = 1;
    a2 = 2;
    res = 0;
	// 自下而上的进行计算,动态规划
    for (i = 3; i <= n; i++) {
        res = a1 + a2;
        a1  = a2;
        a2  = res;
    }
    return res;
}

343. 整数拆分

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

思路是:1)先思考自顶往下的记忆化搜索的方式借助常规的递归的思路,但是依靠记忆化数组,减少递归次数,就有了记忆化搜索的方法。
2)再思考动态规划的方式,自底向上的方式,由小至多累加上去,直接想动态递归的思路较难。

// 记忆化搜索 -- 自顶往下
int memo[64] = {0}; // memo[i]表示将i分割后可以获得的最大乘积
int integerBreak(int n) {
	int res = -1;

	if (n == 1 || n == 2) {  //memo[1] || memo[2] == 1
		return 1;
	}
	
	if (memo[n] != 0) {
		return memo[n];
	}
	// res  i*(n-i) i*integerBreak(n-i)
	//  1     1*2       1*1
	//  2     2*1       2*1
	for (int i = 1; i <= n-1; i++) { // memo[3] == 2
		res = max3(res, i*(n-i), i*integerBreak(n-i));
	}
	memo[n] = res;

	return res;
}
// 动态规划-- 自底往上
int memo[64] = {0}; // memo[i]表示将i分割后可以获得的最大乘积
int integerBreak(int n) {

    memo[1] = 1;
    memo[2] = 1;
    for(int i = 3; i <= n; i++){
        // 求解memo[i]
        for(int j = 1; j <= i - 1; j++){
            // 将i分割成 j+(i-j), memo[i-j]为i-j可以获得的最大乘积
            memo[i] = max3( memo[i], j*memo[i-j], j*(i-j) );
        }
    }

	return memo[n];
}

198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
LeetCode刷题总结(C语言版)动态规划类_第1张图片

也可以利用记忆化搜索来解决该问题,先写出递归函数。

**

0-1 背包问题

**
LeetCode刷题总结(C语言版)动态规划类_第2张图片
LeetCode刷题总结(C语言版)动态规划类_第3张图片
调试程序可以采用如下图片的数据,利于理解背包算法:
LeetCode刷题总结(C语言版)动态规划类_第4张图片
如图,在放置a[1][2]这个元素时考虑:如果不放 ID1 的物品,那么背包价值为6,如果考虑放 ID1 的物品,需要回到a[0][0]的价值,加上放 ID1 物品的价值和为10,两者比较(10 > 6),放的价值大,所以考虑放 ID1的物品。
LeetCode刷题总结(C语言版)动态规划类_第5张图片
如图,在放置a[2][4]这个元素时考虑:如果不放 ID2 的物品,那么背包价值为16,如果考虑放 ID2 的物品,需要回到a[1][1]的价值 6 ,加上放 ID2 物品的价值和为18,两者比较(18 > 16),放的价值大,所以考虑放 ID2的物品。

如下代码,就是建立上述图片里的二维数组的值(先求解了第0行数组和第1行往后的逐列逐行数组)
LeetCode刷题总结(C语言版)动态规划类_第6张图片

你可能感兴趣的:(匠心)