2025高频面试算法总结篇【动态规划】

news2025/4/18 22:25:35

文章目录

  • 直接刷题链接直达
  • 编辑距离
  • 最长回文子串
  • 完全平方数
  • 最长递增子序列
  • 正则表达式匹配
  • 零钱兑换
  • 鸡蛋掉落
  • 单词拆分


直接刷题链接直达

动态规划(Dynamic Programming, DP)是一种通过拆解子问题并利用子问题的最优解来构建整体问题的最优解的方法,通常用于具有重叠子问题最优子结构的优化问题。

  • 最优子结构:一个问题的最优解包含其子问题的最优解。例如,最短路径问题,求从A到B的最短路径,其中A到C和C到B的最短路径也必须是最优的。
  • 重叠子问题:相同的子问题在递归过程中会被多次计算。例如,斐波那契数列 F(n) = F(n-1) + F(n-2),计算 F(n-2) 时也需要计算 F(n-3)

如果问题满足这两个特性,通常可以考虑使用动态规划。

(1)状态的定义是解决动态规划的关键。通常可以通过以下方式思考:

  1. 分析问题,找出“规模较小”的子问题。
  2. 确定状态变量,这些变量应该能唯一标识一个子问题的情况。
    • 一般来说,状态变量的选取往往与问题的输入参数有关。
    • 例如,背包问题中 dp[i][j] 表示前 i 个物品,在总容量为 j 的背包中的最优解。
    • 在最长公共子序列问题中 dp[i][j] 表示 s1 的前 i 个字符和 s2 的前 j 个字符的最长公共子序列长度。

(2)状态转移方程用于描述如何从较小的子问题递推到较大的子问题。常见的方法:

  • 考虑决策过程:在某个状态下,可以有哪些选择?
  • 根据子问题的解构建当前问题的解

例如:

  • 斐波那契数列dp[n] = dp[n-1] + dp[n-2]
  • 0/1 背包问题dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]) (取或者不取当前物品)

(3)初始状态是动态规划表 dp 的起点,通常根据问题的边界条件来确定。例如:

  • 斐波那契数列:dp[0] = 0, dp[1] = 1
  • 背包问题:dp[0][j] = 0(没有物品可选时,价值均为0)

(4)动态规划可以通过**自顶向下(带记忆化的递归)自底向上(迭代)**来实现:

  • 自顶向下:递归 + 记忆化搜索(Memoization),避免重复计算
  • 自底向上:直接从小规模问题开始填表,通常是 O(n)O(n^2)

  • 最佳折扣问题
    • double calculateMinPrice(int [] counts, double [] prices, Map<int[], Double> promotions)
    • counts表示一个要买的商品数量列表(如0011表示第3件和第4件都买一个),prices表示单价,promotions表示折扣表 比如 0011->9 表示第3件和第4件一起打包买打9折,输出一个最低价格
    • 实现类似 动态规划_最小费用购物问题
  • 设计一个模糊匹配算法,给定一个字符串列表和一个字符串,输出列表中最匹配的那个(若都不匹配可输出空串)
    • 类似于 72. 编辑距离,基于字符长度配置好阈值
  • 最长回文子串
    • 5. 最长回文子串
  • 完全平方数
    • 279. 完全平方数
  • 最长递增子序列
    • 300. 最长递增子序列
  • 正则表达式匹配
    • 10. 正则表达式匹配
  • 零钱兑换
    • 322. 零钱兑换
  • 鸡蛋掉落
    • dp[K] [N] = 1 + max(dp[K - 1] [i - 1] + dp[K] [N - i]) + 1 (i~(1,N)) (K蛋N层,最直观的DP,还有其他解法)
    • 887. 鸡蛋掉落
    • Egg Dropping Dynamic Programming (画状态转移表)
  • 单词拆分
    • 139. 单词拆分
    • 140. 单词拆分 II

编辑距离

给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

class Solution {
    // dp[i][j] : word1[0:i]转换成 word2[0:j] 所使用的最少操作数
    // dp[i][j] = (s[i] == s[j] && dp[i-1][j-1]) or (Math.min(插删替换))
    public int minDistance(String word1, String word2) {
        int m = word1.length(), n = word2.length();
        int[][] dp = new int[m+1][n+1];
        // 初始 dp[0][j] = j; dp[i][0] = i;
        for (int i = 0; i <= m; i++) {
            dp[i][0] = i;
        } 
        for (int j = 0; j <= n; j++) {
            dp[0][j] = j;
        }
        //
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (word1.charAt(i-1) == word2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1];
                }else {
                    dp[i][j] = 
                    Math.min(Math.min(dp[i][j-1], dp[i-1][j]),dp[i-1][j-1])+1;
                }
            }
        }

        return dp[m][n];
    }
}

最长回文子串

给你一个字符串 s,找到 s 中最长的 回文 子串。

class Solution {
    // dp[i][j] s[i-j] 是否为回文串
    public String longestPalindrome(String s) {
        if (s.length() <= 1) return s;
        boolean[][] dp = new boolean[s.length()][s.length()];
        for (int i = 0; i < s.length(); i++) {
            dp[i][i] = true;
        }
        int start = 0, maxlen = 1;
        for (int len = 2; len <= s.length(); len++) {
            for (int i = 0; i <= s.length() - len; i++) {
                int j = i + len - 1;
                if (len == 2 && s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = true;
                }else {
                    dp[i][j] = s.charAt(i) == s.charAt(j) && dp[i+1][j-1];
                }
                if (dp[i][j] && len > maxlen) {
                    start = i;
                    maxlen = len;
                }
            }
        }

        return s.substring(start, start+maxlen);
    }
}


完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

class Solution {
    // dp[i] = dp[i-完全平方数]+1
    public int numSquares(int n) {
        int[] dp = new int[n+1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j*j <= i; j++) {
                dp[i] = Math.min(dp[i], dp[i-j*j]+1);
            }
        }

        return dp[n];
    }
}

最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

class Solution {
    public int lengthOfLIS(int[] nums) {
        // dp[i] 以i结尾 的 最长严格递增子序列的长度
        int[] dp = new int[nums.length];
        Arrays.fill(dp, 1);
        int max = 1;
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }

            max = Math.max(max, dp[i]);

        }

        return max;
    }
}

正则表达式匹配

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s 的,而不是部分字符串。

class Solution {
    public boolean isMatch(String s, String p) {
        int n = s.length();
        int m = p.length();
        boolean[][] dp = new boolean[n + 1][m + 1];

        // 空字符串匹配空模式
        dp[0][0] = true;

        // 处理 p[j-1] 是 '*' 的情况 (匹配 0 次)
        for (int j = 2; j <= m; j++) {
            if (p.charAt(j - 1) == '*') {
                dp[0][j] = dp[0][j - 2]; 
            }
        }

        // 填充 DP 数组
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (p.charAt(j - 1) == '.' || p.charAt(j - 1) == s.charAt(i - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else if (p.charAt(j - 1) == '*') {
                    dp[i][j] = dp[i][j - 2]; // `*` 匹配 0 次
                    if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.') {
                        dp[i][j] = dp[i][j] || dp[i - 1][j]; // `*` 匹配多次
                    }
                }
            }
        }

        return dp[n][m];
    }
}

零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

class Solution {
    public int coinChange(int[] coins, int amount) {
        // dp[i] :可以凑成 i 所需的 最少的硬币个数 
        int[] dp = new int[amount+1];
        // dp[i] = dp[i-coins] + 1
        Arrays.fill(dp, amount + 1);
        dp[0] = 0;
        Arrays.sort(coins);
        for (int coin : coins) {
            if (coin <= amount) {
                dp[coin] = 1;
            }else {
                break;
            }
        }
        for (int i = 1; i <= amount; i++) {
            for (int coin : coins) {
                if (coin > i) {
                    break;
                }
                dp[i] = Math.min(dp[i], dp[i-coin]+1);
            }
        }

        return dp[amount] >= amount + 1 ? -1:dp[amount];

    }
}

鸡蛋掉落


单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

class Solution {
    // dp[i] 表示 s[0:i] 是否可以拆分成 wordDict 里的单词组合。
    // dp[i]=dp[j] 且 s[j:i] 在 wordDict
    public boolean wordBreak(String s, List<String> wordDict) {
        boolean[] dp = new boolean[s.length()+1];
        dp[0] = true;
        for(int i = 1; i <= s.length(); i++) {
            for (int j = 0; j <= i; j++) {
                if (dp[j] && wordDict.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break;
                }
            }
        }

        return dp[s.length()];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2337575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven中clean、compil等操作介绍和Pom.xml中各个标签介绍

文章目录 前言Maven常用命令1.clean2.vaildate3.compile4.test5.package6.verify7.install8.site9.deploy pom.xml标签详解格式<?xml version"1.0" encoding"UTF-8"?>(xml版本和编码)modelVersion&#xff08;xml版本&#xff09;groupId&#xff…

力扣刷题-热题100题-第35题(c++、python)

146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/lru-cache/?envTypestudy-plan-v2&envIdtop-100-liked 双向链表哈希表 内置函数 对于c有list可以充当双向链表&#xff0c;unordered_map充当哈希表&#xff1b;python有OrderedDic…

Nautilus 正式发布:为 Sui 带来可验证的链下隐私计算

作为 Sui 安全工具包中的强大新成员&#xff0c;Nautilus 现已上线 Sui 测试网。它专为 Web3 开发者打造&#xff0c;支持保密且可验证的链下计算。Nautilus 应用运行于开发者自主管理的可信执行环境&#xff08;Trusted Execution Environment&#xff0c;TEE&#xff09;中&a…

云服务器CVM标准型S5实例性能测评——2025腾讯云

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CPU采用采用 Intel Xeon Cascade Lake 或者 Intel Xeon Cooper Lake 处理器&#xff0c;主频2.5GHz&#xff0c;睿频3.1GHz&#xff0c;CPU内存配置2核2G、2核4G、4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3…

leetcode面试经典算法题——2

链接&#xff1a;https://leetcode.cn/studyplan/top-interview-150/ 20. 有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#x…

Ubuntu20.04安装企业微信

建议先去企业微信官网看一下有没有linux版本&#xff0c;没有的话在按如下方式安装&#xff0c;不过现在是没有的。 方案 1、使用docker容器 2、使用deepin-wine 3、使用星火应用商店 4. 使用星火包deepin-wine 5、使用ukylin-wine 本人对docker不太熟悉&#xff0c;现…

在Ubuntu服务器上部署xinference

一、拉取镜像 docker pull xprobe/xinference:latest二、启动容器&#xff08;GPU&#xff09; docker run -d --name xinference -e XINFERENCE_MODEL_SRCmodelscope -p 9997:9997 --gpus all xprobe/xinference:latest xinference-local -H 0.0.0.0 # 启动一个新的Docker容…

异步编程——微信小程序

1. 前言 引用来自&#xff1a;微信小程序开发中的多线程处理与异步编程_微信小程序 多线程-CSDN博客 微信小程序是基于JavaScript开发的&#xff0c;与浏览器JavaScript不同&#xff0c;小程序运行在WebView内部&#xff0c;没有多线程的概念。小程序的 JavaScript 是单线程的…

STM32 四足机器人常见问题汇总

文章不介绍具体参数&#xff0c;有需求可去网上搜索。 特别声明&#xff1a;不论年龄&#xff0c;不看学历。既然你对这个领域的东西感兴趣&#xff0c;就应该不断培养自己提出问题、思考问题、探索答案的能力。 提出问题&#xff1a;提出问题时&#xff0c;应说明是哪款产品&a…

Windows 下实现 PHP 多版本动态切换管理(适配 phpStudy)+ 一键切换工具源码分享

&#x1f680; Windows 下实现 PHP 多版本动态切换管理&#xff08;适配 phpStudy&#xff09; 一键切换工具源码分享 &#x1f4e6; 工具特点&#x1f9ea; 效果展示&#x1f9f1; 环境要求&#x1f9d1;‍&#x1f4bb; 源码展示&#xff1a;php_switcher.py&#x1f6e0; 打…

ReportLab 导出 PDF(图文表格)

ReportLab 导出 PDF&#xff08;文档创建&#xff09; ReportLab 导出 PDF&#xff08;页面布局&#xff09; ReportLab 导出 PDF&#xff08;图文表格) 文章目录 1. Paragraph&#xff08;段落&#xff09;2. Table&#xff08;表格&#xff09;3. VerticalBarChart&#xff0…

yolov8复现

Yolov8的复现流程主要包含环境配置、下载源码和验证环境三大步骤&#xff1a; 环境配置 查看电脑状况&#xff1a;通过任务管理器查看电脑是否有独立显卡&#xff08;NVIDIA卡&#xff09;。若有&#xff0c;后续可安装GPU版本的pytorch以加速训练&#xff1b;若没有&#xff0…

RestSharp和Newtonsoft.Json结合发送和解析http

1.下载RestSharp和Newtonsoft.Json 2编写ApiRequest和ApiResponse和调用工具类HttpRestClient 请求模型 /// <summary>/// 请求模型/// </summary>public class ApiRequest{/// <summary>/// 请求地址/api路由地址/// </summary>public string Route {…

【Pytorch之一】--torch.stack()方法详解

torch.stack方法详解 pytorch官网注释 Parameters tensors&#xff1a;张量序列&#xff0c;也就是要进行stack操作的对象们&#xff0c;可以有很多个张量。 dim&#xff1a;按照dim的方式对这些张量进行stack操作&#xff0c;也就是你要按照哪种堆叠方式对张量进行堆叠。dim的…

数据中台(大数据平台)之数据资源目录

数据资源目录是数据管理的账本&#xff0c;是数据应用的基础&#xff0c;更是是数据治理成果的体现&#xff0c;因此数据中台产品应提供数据资源目录编制、发布、资源挂载、下架的管理能力。 1.数据资源目录分类 资源目录能够支持基于业务特点创建和维护基础目录分类和特色目…

【随身WiFi】随身WiFi Debian系统优化教程

0.操作前必看 本教程基于Debian系统进行优化&#xff0c;有些操作对随身WiFi来说可能会带来负优化&#xff0c;根据需要选择。 所有操作需要在root用户环境下运行&#xff0c;否则都要加sudo 随身wifi Debian系统&#xff0c;可以去某安的随声WiFi模块自行搜索刷机 点赞&am…

JAVA Web_定义Servlet2_学生登录验证Servlet

题目 页面StudentLogin.html中有一HTML的表单代码如下&#xff1a; <form action"studentLogin" method"post">学生姓名&#xff1a;<input type"text" name"stuName" value""><br>登录密码&#xff1a;…

Unity入门笔记(缘更)

内容来源SiKi学院的Luna’s Fantasy 文章目录 一、基础知识1.准备2.基础知识1.层级(Layer)2.轴心点3.预制体(Prefab)4.刚体组件(Rigidbody)5.碰撞器组件(BoxCollider) 二、代码1.移动 一、基础知识 1.准备 Unity安装&#xff1a; https://unity.cn 2.基础知识 1.层级(Layer…

【Python】用Python写一个俄罗斯方块玩玩

【Python】用Python写一个俄罗斯方块玩玩 一、引言1.成品效果展示 二、思考准备1.思考设计2.代码设计2.1 游戏页面2.2 控件设计2.2.1 方块生成2.2.2 方块碰撞2.2.3 方块消融2.2.4 游戏主循环2.2.5 游戏窗口 三、游戏完整版 一、引言 今日看到侄子在玩游戏&#xff0c;凑近一看…

记录一次生产中mysql主备延迟问题处理

登录库&#xff1a; mysql -uXXXX -pXXXX -P3306 -hXXXXXX -A 备库上执行&#xff1a;show slave status\G 查看 seconds_Behind_Master&#xff0c;延迟 2705s&#xff0c;而且还一直在增加。 SHOW CREATE TABLE proc_i_income_temp; -- 查看表的结构 show index from proc…