算法题(动态规划)

一、题目

1、单词拆分(LC 139)

2、最长递增子序列(LC 300)

二、题解

1、单词拆分(LC 139)

(1)分析

这道题要求判断一个字符串能否按照字典里的单词进行拆分,本质是一个递归选择问题,可以用记忆化 DFS来做。

整体思路是从字符串的末尾往前拆分,每次从后往前截取一段单词,如果这段单词刚好在字典里,就继续递归判断前面剩下的字符串能不能继续拆分,直到把整个字符串拆完。为了提高查询速度,可以先把字典里的单词放进 HashSet,这样判断单词是否存在的速度会快很多,同时提前找出字典里最长单词的长度,用来限制截取范围,避免做无用的截取操作。

递归函数的核心是记录当前处理到字符串的哪个位置,用 i 表示当前处理到第 i 个字符,当 i 等于 0 时,说明整个字符串已经成功拆分完毕,直接返回成功。为了避免重复递归,使用一个 memo 记忆数组,记录每个位置能否成功拆分,如果已经计算过就直接返回结果,不用再重复执行递归。

在递归内部,从当前位置往前截取单词,长度不超过字典最长单词长度,只要找到一段存在于字典中的单词,并且前面的部分也能成功拆分,就说明当前位置是可以拆分的,记录结果并返回。如果遍历完所有可能都无法拆分,就记录为不可拆分。

(2)解答
java 复制代码
class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        int n = s.length();   //字符串的长度
        int maxLen = 0;       //字典字符串的最大长度
        for(String str : wordDict){
            maxLen = Math.max(maxLen, str.length());  //找出字典字符串的最大长度
        }
        Set<String> word =new HashSet<>(wordDict);  //用HashSet集合,提高查询效率
        int[] memo = new int[n + 1];       //记忆数组
        Arrays.fill(memo, -1);            //初始化元素为-1

        return dfs(n, maxLen, word, s, memo) == 1; 


    }
    public int dfs(int i, int maxLen, Set<String> word, String s, int[] memo){
        if( i == 0){ //成功拆分
            return 1;
        }
        if(memo[i] != -1){   //已经计算过
            return memo[i];
        }
        for(int j = i - 1; j >= Math.max(0, i - maxLen); j--){
            if(word.contains(s.substring(j, i)) && dfs(j, maxLen, word, s, memo) == 1){
                return memo[i] = 1;   //字典集合中存在当前字符串,且前面的字符串也能够成功拆分
            }
        }
        return memo[i] = 0;
    }
}

2、最长递增子序列(LC 300)

(1)分析

这道题求数组里最长的递增子序列长度,也可以用记忆化 DFS来实现。

核心思路是:以数组中每一个元素作为子序列的结尾,分别求出以它结尾的最长递增子序列长度,最后在所有结果里取最大值,就是整个数组的答案。递归函数的作用就是计算以第 i 个元素结尾的最长递增子序列长度,这样问题就被拆分成一个个更小的子问题。

在递归过程中,遍历 i 前面所有的元素,如果某个元素比 nums [i] 小,说明可以把 nums [i] 接在以这个元素结尾的子序列后面,形成更长的递增子序列。在所有符合条件的结果里选出最大的那一个,再加上当前元素本身,就是以 i 结尾的最长长度。为了避免重复计算,用 memo 数组记录已经算过的结果,只要某个位置算过,就直接返回,不用再重新递归。最后所得的 ans 值即为所求。

(2)解答
java 复制代码
class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;    //数组长度
        int[] memo = new int[n];  //记忆数组,存放以每个元素结尾的最长子序列大小
        int ans = 0;
        for(int i = 0; i < n; i++){
            ans = Math.max(ans, dfs(i, memo, nums)); //dfs(i) 以nums[i]结尾的最长子序列的长度
        }
        return ans;
        
    }
    public int dfs(int i, int[] memo, int[] nums){
        if(memo[i] != 0 ){          //说明计算过了  
        return memo[i];
        }
        int res = 0;
        for(int j = 0; j < i; j++){
            if(nums[i] > nums[j]){          //找到j<i且 nums[j]<nums[i],取最大的存放在memo[i]
                res = Math.max(res, dfs(j, memo, nums));
            }
        }
        res++;        //比前面最大的多一个
        return memo[i] = res;
    }
}
相关推荐
pen-ai1 小时前
Kennard-Stone (KS) 算法详解 —— 从实验设计到样本划分的经典方法
人工智能·算法·机器学习
开压路机1 小时前
数据结构:图
数据结构·算法
小白|1 小时前
cann-learning-hub:昇腾CANN社区学习中心完全指南
java·c++·算法
kobesdu1 小时前
当算法跑不通时:3D激光SLAM工程实践中的隐藏陷阱与全链路排查
算法·3d
金创想2 小时前
积木移动题目分析及解题思路——木块问题(1)
c++·算法·字符串·c·刷题·信息学奥赛·积木
研究点啥好呢2 小时前
小鹏汽车 机器人运动规划算法工程师 面试题精选:10道高频考题+答案解析
算法·机器人·汽车
小许同学记录成长2 小时前
原始 IQ 数据时频图生成
python·算法
小小测试开发2 小时前
OpenAI 模型攻克离散几何 80 年难题:Erdős 单位距离猜想被 AI 证明
人工智能·算法·机器学习
moonsims2 小时前
从“传感器融合”升级为“多机器人约束融合系统”-Factor Graph 多约束融合
人工智能·算法