初级算法-动态规划

Posted 方丈的寺院

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初级算法-动态规划相关的知识,希望对你有一定的参考价值。

摘要

本篇主要介绍动态规划解题思路

概括

动态规划主要是解一些递归问题,也就是将递归写成非递归方式,因为编辑器无法正确对待递归,递归方法会导致很多计算结果被重复计算,比如菲波那切数列。

所以动态规划的解题思路也就是

  1. 列出递归表达式

  2. 将递归方法写成非递归方式

比如菲波那切数列
F(n) = F(n-1) + F(n-2)
使用两个中间变量存储之前的计算结果,就改写成了非递归方式实现,也就是动态规划。

常见的题

leetcode 动态规划题
https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/23/dynamic-programming/

一. 爬楼梯

假设你正在爬楼梯。需要 n 步你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

按照解题方法,写列出递归方程
设定dp[i] 表示走到某个台阶的方法,那么就有递归方程

1dp[1] = 1;dp[2] = 2(一次走一步/一次走二步)
2dp[3] = dp[1] + dp[2] (从dp[1]中方法中,走2步上来,或者从dp[2]种方法中走1步上来)
3dp[n] = dp[n-2] + dp[n-1]

写成非递归方法

 1public static int climbStairs(int n) {
2        if(n < 1) {
3            return 0;
4        }
5
6        if (n == 1) {
7            return 1;
8        }
9
10        if (n == 2) {
11            return 2;
12        }
13        int dp[] = new int [] {1,2};
14        int result = dp[0] + dp[1];
15        for (int i = 3; i <= n; i++) {
16            result = dp[0] + dp[1];
17            dp[0] = dp[1];
18            dp[1] = result;
19        }
20        return result;
21    }

二.  最大子序列

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

  1. 列出递归方程
    以 nums[-2,1,-3,4,-1,2,1,-5,4] 为例, dp[i]表示遍历到第i个数时,当前最大连续子数组和
    dp[1] = -2, dp[2] = Math.max(dp[1] + nums[2],nums[2]),因为要求是连续子数组,所以nums[i]必须接上,
    然后再比较历史最大的的连续子数组和这次的最大值

代码如下

 1 public static int maxSubArray(int[] nums) {
2        if (nums.length == 0) {
3            return 0;
4        }
5
6        if (nums.length == 1) {
7            return nums[0];
8        }
9        int result =  Math.max(nums[0]+nums[1],nums[1]);
10        int dp = result;
11        int max = Math.max(result, nums[0]);
12        for (int i = 2; i< nums.length; i++) {
13            result = Math.max(dp+nums[i],nums[i]);
14            dp = result;
15            // 如果比历史的大,就替换
16            if (result > max) {
17                max = result;
18            }
19        }
20        return max;
21    }

三. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额

如 [2,7,9,3,1]
设定dp[i] 是偷i个房屋,所能偷窃到的最高金额,dp[1] = 2, dp[2] = 7, dp[3] = 2+9,Math.max(dp[1] + nums[3], dp[2])
递归方程

1dp[i] = max(dp[i-2] + nums[i], dp[i-1])

非递归方法实现

 1 public static int rob(int[] nums) {
2        if (nums.length ==0) {
3            return 0;
4        }
5        if (nums.length == 1) {
6            return nums[0];
7        }
8
9        if (nums.length  ==2) {
10            return Math.max(nums[0],nums[1]);
11        }
12
13        int dp[] = new int[] {nums[0], Math.max(nums[0], nums[1])};
14        int result=0;
15        for (int i = 2; i < nums.length; i++) {
16            result = Math.max(dp[0] + nums[i], dp[1]);
17            dp[0] = dp[1];
18            dp[1] = result;
19        }
20        return result;
21    }
里写图片描述


以上是关于初级算法-动态规划的主要内容,如果未能解决你的问题,请参考以下文章

初级算法探索——动态规划篇(二十七)

初级算法探索——动态规划篇(二十九)

初级算法探索——动态规划篇(二十二)

初级算法探索——动态规划篇(三十)

初级算法探索——动态规划篇(二十九)

初级算法探索——动态规划篇(二十六)