程序员必掌握的算法系列之动态规划算法

2023-09-21 15:16:40

一:引言

动态规划是一种重要的算法思想,其在程序员的日常工作中经常被使用到。它可以解决许多实际问题,如最短路径、最大子序列和等等。掌握动态规划算法不仅能提高程序员的编程能力,还可以优化算法的时间复杂度和空间复杂度。因此,作为程序员,必须深入学习和应用动态规划算法。

二:动态规划算法介绍

动态规划是一种将复杂问题分解成简单子问题的思想,通过将问题划分为相互重叠的子问题,并将子问题的解保存起来,从而避免重复计算。在动态规划中,常见的几个关键概念包括状态定义、状态转移方程和初始条件。

以下是一些常见的动态规划算法和应用场景:

1. 最长公共子序列(Longest Common Subsequence)

最长公共子序列是指给定两个序列 X 和 Y,找出它们最长的公共子序列。这个问题可以用动态规划来解决,其中状态定义为当前已比较的子序列长度;状态转移方程为:如果 X[i] == Y[j],则 dp[i][j] = dp[i-1][j-1] + 1;否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。

示例代码(Java):

public int longestCommonSubsequence(String text1, String text2) {
    int m = text1.length();
    int n = text2.length();
    int[][] dp = new int[m+1][n+1];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (text1.charAt(i-1) == text2.charAt(j-1)) {
                dp[i][j] = dp[i-1][j-1] + 1;
            } else {
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    return dp[m][n];
}

示例代码(Python):

def longestCommonSubsequence(text1, text2):
    m = len(text1)
    n = len(text2)
    dp = [[0] * (n+1) for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if text1[i-1] == text2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]

2. 背包问题(Knapsack Problem)

背包问题是指给定一组物品和一个背包,每个物品有自己的重量和价值,要求选择一些物品放入背包中,使得在满足背包最大承重下,物品的总价值最大化。这个问题可以用动态规划来解决,其中状态定义为已考虑的物品数量和背包剩余承重;状态转移方程为:如果当前物品重量小于等于背包剩余承重,选择放入物品或不放入物品的最大价值;否则,不放入物品。

示例代码(Java):

public int knapsack(int[] weights, int[] values, int capacity) {
    int n = weights.length;
    int[][] dp = new int[n+1][capacity+1];
    for (int i = 1; i <= n; i++) {
        int weight = weights[i-1];
        int value = values[i-1];
        for (int j = 1; j <= capacity; j++) {
            if (weight <= j) {
                dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight] + value);
            } else {
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    return dp[n][capacity];
}

示例代码(Python):

def knapsack(weights, values, capacity):
    n = len(weights)
    dp = [[0] * (capacity+1) for _ in range(n+1)]
    for i in range(1, n+1):
        weight = weights[i-1]
        value = values[i-1]
        for j in range(1, capacity+1):
            if weight <= j:
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight] + value)
            else:
                dp[i][j] = dp[i-1][j]
    return dp[n][capacity]

3. 股票买卖的最佳时机(Best Time to Buy and Sell Stock)

股票买卖的最佳时机是一个动态规划问题。给定一个数组,其中第 i 个元素表示第 i 天的股票价格。可以选择在任意一天买入股票,并在未来的某一天卖出。求出能够获取的最大利润。例如,对于数组 [7, 1, 5, 3, 6, 4],最大利润为 5,即在第 2 天买入股票(价格为1),第 5 天卖出股票(价格为6)。

public int maxProfit(int[] prices) {
    int minPrice = Integer.MAX_VALUE; // 初始化最低价格为最大值
    int maxProfit = 0; // 初始利润为0
    for (int i = 0; i < prices.length; i++) {
        if (prices[i] < minPrice) {
            minPrice = prices[i]; // 更新最低价格
        } else if (prices[i] - minPrice > maxProfit) {
            maxProfit = prices[i] - minPrice; // 更新最大利润
        }
    }
    return maxProfit;
}
def maxProfit(prices):
    minPrice = float('inf')
    maxProfit = 0
    for price in prices:
        if price < minPrice:
            minPrice = price
        elif price - minPrice > maxProfit:
            maxProfit = price - minPrice
    return maxProfit

4. 斐波那契数列

图示

Java示例代码:
public class Fibonacci {
    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }

    public static void main(String[] args) {
        int n = 7;
        System.out.println("第 " + n + " 个斐波那契数是:" + fibonacci(n));
    }
}
Python示例代码:
def fibonacci(n):
    if n <= 1:
        return n
    dp = [0] * (n + 1)
    dp[0] = 0
    dp[1] = 1
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]

n = 7
print("第", n, "个斐波那契数是:", fibonacci(n))

5. 爬楼梯问题

Java示例代码:
public class ClimbingStairs {
    public static int climbStairs(int n) {
        if (n <= 2) {
            return n;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }

    public static void main(String[] args) {
        int n = 4;
        System.out.println("爬楼梯的方法数为:" + climbStairs(n));
    }
}
Python示例代码:
def climbStairs(n):
    if n <= 2:
        return n
    dp = [0] * (n + 1)
    dp[1] = 1
    dp[2] = 2
    for i in range(3, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]

n = 4
print("爬楼梯的方法数为:", climbStairs(n))

三:总结

动态规划算法在程序员的日常工作中扮演着重要的角色。通过掌握动态规划算法,程序员能够解决各种实际问题,并优化算法的时间复杂度和空间复杂度。我们应该积极学习和研究动态规划算法,并在日常编程中灵活应用。希望以上介绍的动态规划算法能给广大程序员带来帮助,提高编程能力。

更多推荐

强化学习从基础到进阶-案例与实践[4]:深度Q网络-DQN、double DQN、经验回放、rainbow、分布式DQN

【强化学习原理+项目专栏】必看系列:单智能体、多智能体算法原理+项目实战、相关技巧(调参、画图等、趣味项目实现、学术应用项目实现专栏详细介绍:【强化学习原理+项目专栏】必看系列:单智能体、多智能体算法原理+项目实战、相关技巧(调参、画图等、趣味项目实现、学术应用项目实现对于深度强化学习这块规划为:基础单智能算法教学(g

分布式运用之rsync远程同步

一、rsync的相关知识1.1rsync简介rsync(RemoteSync,远程同步)是一个开源的快速备份工具,可以在不同主机之间镜像同步整个目录树,支持增量备份,并保持链接和权限,且采用优化的同步算法,传输前执行压缩,因此非常适用于异地备份、镜像服务器等应用。rsync的官方站点的网址是rsync.samba.or

ubuntu搭建sftp服务

安装OpenSSH服务器Ubuntu通常已经预装了OpenSSH客户端,但如果您还没有OpenSSH服务器,请在终端中执行以下命令来安装:sudoaptupdatesudoaptinstallopenssh-server创建SFTP用户和组创建一个新的用户组(例如sftp_users),用于管理SFTP用户:sudog

Linux之shell条件测试

目录作用基本用法格式:案例-f用法[]用法[[]]用法(())语法文件测试参数案例编写脚本,测试文件是否存在,不存在则创建整数测试作用操作符案例系统用户个数小于50的则输出信息逻辑操作符符号案例命令分隔符案例分析案例1---判断当前已登录的账户数,超过5个则输出信息案例2---取出/etc/passwd文件的第6行内容

Layui快速入门之第十四节 分页

目录一:基本用法API渲染属性二:自定义主题三:自定义文本四:自定义排版五:完整显示一:基本用法分页组件laypage提供了前端的分页逻辑,使得我们可以很灵活处理不同量级的数据,从而提升渲染效率<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>分页</title

STM32低功耗分析

1.ARM发布最新内核2023年5月29日,Arm公司今天发布了处理器核心:Cortex-X4、Cortex-A720和Cortex-A520。这些核心都是基于Armv9.2架构,只支持64位指令集,不再兼容32位应用。Arm公司表示,这些核心在性能和效率方面都有显著的提升,同时也加强了安全性和可扩展性。Cortex-

字符串相似度算法

相似度算法JaccardSimilarityCoefficient、JaroWinkler、CosineSimilarity、Levenshtein距离编辑算法案例。Jaccard相似性系数衡量两个集合的相似程度,通过计算两个集合的交集大小除以并集大小得出。适用于处理文本、推荐系统、生物信息学等领域CosineSimi

青龙面板从0到1的实现

文章目录需要有一台云服务器Docker、SSH、青龙如何打开云服务器上的青龙面板青龙注册登录看这个青龙配置最后、从此需要有一台云服务器我这里选择的是阿里云新用户免费送的三个月服务器,服务器操作系统:CenOS(其他操作系统也可以:Ubantu、Debian)。Docker、SSH、青龙为云服务器系统安装Docker容器

支付功能、支付平台、支持渠道如何测试?

有学员提问:作为一个支付平台,接入了快钱、易宝或直连银行等多家的渠道,内在的产品流程是自己的。业内有什么比较好的测试办法,来测试各渠道及其支持的银行通道呢?作为产品,我自己办了十几张银行卡方便测试,但QA和开发不愿意这样做,怎么办呢?回答:对支付平台而言,与支付渠道相关的测试大致可以分为:测试支付渠道功能、测试支付产品

scons体验以及rtthread中的简单使用

SCons是一个用于构建软件项目的软件构建工具。它使用Python脚本作为配置文件,提供了一种简单而灵活的方式来描述软件项目的构建过程。下面是一个简单的SCons使用示例:安装SCons:首先,确保你已经安装了Python。然后,可以使用Python的包管理器pip安装SCons。在命令行中运行以下命令安装SCons:

【谢希尔 计算机网络】第2章 物理层

目录通信基础基本概念两个公式lim奈氏准则香农定理奈氏准则VS香农定理编码与调制​编辑物理层下面的传输媒体导引型传输媒体1.双绞线2.同轴电缆3.光缆非导引型传输媒体无线电微波通信卫星通信无线局域网使用的ISM频段信道复用技术频分复用、时分复用和统计时分复用波分复用码分复用CDMA工作原理CDMA的重要特点数字传输系统

热文推荐