动态规划篇-06:单词拆分

139、单词拆分

老样子,还是先尝试找出状态转移方程

状态转移方程

对问题进行分解,尝试从子问题入手解决。这也是前文提到过的 “分解问题” 的思想

 对于输入的字符串 s,如果我能够从单词列表 wordDict 中找到一个单词匹配 s 的前缀 s[0..k],那么只要我能拼出 s[k+1..],就一定能拼出整个 s。换句话说,我把规模较大的原问题 wordBreak(s[0..]) 分解成了规模较小的子问题 wordBreak(s[k+1..]),然后通过子问题的解反推出原问题的解。

先找到字符串的一个前缀,如果我能拼出它剩下的部分,那么我就能拼出整个字符串。相当于将“拼出字符串”这个问题分解为“前缀” + “剩下部分”

base case

想要从wordDict中拼出字符串s,将其分为“前缀” 和 “剩下部分” 两部分。先判断 “前缀” 在 wordDict中是否存在,如果存在再判断 “剩下部分” 是否能拼出

考虑边界,当前缀的长度和字符串s的长度相等时,说明该字符串可以被拼出

if( 前缀 == s.length()){
    return true;
}

明确状态

前文已经讲过多次,“状态”就是原问题或者子问题中会变化的变量。

在此题中,状态就是 “当前字符串是否能被拼出”

确定选择

选择就是导致状态变化的行为,在此题中对应的是字符串s的 “前缀”。

定义dp函数

定义dp(string s,int i) 表示:字符串s从i下标开始是否能够拼出

联系框架

遍历所有可能的前缀,从而得出所有状态的结果

使用了备忘录的自上而下的递归解法

class Solution {
    HashSet<String> wordDict;
    int[] memo;
    public boolean wordBreak(String s, List<String> wordDict) {
        //将wordDict转为hashset,以便于后面使用contains方法
        this.wordDict = new HashSet<>(wordDict);
        //设置备忘录并初始化
        this.memo = new int[s.length()];
        //-1表示尚未判断,0表示无结果,1表示有结果
        Arrays.fill(memo,-1);
        return dp(s,0);
    }
    boolean dp(String s,int i){
        //base case : 当前缀长度和字符串s长度相等时说明s可以被拼出
        if(i == s.length()){
            return true;
        }
        //如果备忘录中存在该数据,直接取用
        if(memo[i] != -1){
            return memo[i] == 0 ? false : true;
        }
        //遍历选择列表:所有可能的前缀
        for(int len = 1;len + i <= s.length();len++){
            //获得前缀字符串并判断是否存在于wordDict中
            String prefix = s.substring(i,i + len);
            //如果存在,那么问题转变为判断从(i+len)下标开始是否能拼出
            if(wordDict.contains(prefix)){
                boolean subPreblem = dp(s,i + len);
                if(subPreblem ){
                    memo[i] = 1;
                    return true;
                }
            }            
        }
        memo[i] = 0;
        return false;
    }
}
  • wordBreak 函数接受一个字符串 s 和一个单词字典 wordDict 的列表作为输入。它将单词字典转换成 HashSet,以便进行快速查找。同时,它初始化了一个长度为字符串 s 长度的备忘录数组 memo,并将其中所有元素都设为 -1。然后,它调用 dp 函数,并传入字符串 s 和起始索引 0。
  • memo数组元素的含义是 memo[i] :从索引i开始的子串能否被拼出来的结果
  • dp 函数用于判断从索引 i 开始的子串是否可以被拼出来。它首先检查是否达到了字符串末尾,如果是的话,直接返回 true,表示该子串可以被拼出。然后,它检查备忘录数组 memo 中是否已经计算过该索引位置的结果,如果是的话,就直接返回相应的值。如果 memo[i] 的值为 0,表示子串无法被拼出,返回 false;如果 memo[i] 的值为 1,表示子串可以被拼出,返回 true。

如果备忘录数组中没有存储对应索引位置的结果,那么函数进入循环,遍历从索引 i 开始的所有前缀。对于每个前缀,它检查该前缀是否存在于单词字典中。如果存在,就递归调用自身,并更新索引为 i+len,判断剩余部分是否可以被拼出来。如果递归调用的结果为 true,表示剩余部分可以被拼出,那么将 memo[i] 的值设为 1,并返回 true。

如果没有找到匹配的前缀,那么将 memo[i] 的值设为 0,表示子串无法被拼出,返回 false。

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提到的是文本排版中的几个概念,它们通常与图形设计软件如Adobe InDesign中的选项有关。下面是这些术语的简要说明: 1. 字符间隔(Character Spacing): 这是调整单个字符之间的空间,也称为字间距。在InDesign中,可以通过“Type” > “ Kerning” 来设置。 2. 单词间隔(Word Spacing, Tw): 指的是单词之间的间距,即单词末尾和下一个单词开头之间的空白。在InDesign中,这个设置通常在“Type” > “Tracking” 或者使用快捷键Ctrl+T(Windows/Linux)或Command+T(Mac)来调整。 3. 水平缩放(Horizontal Scaling, Tz): 用于调整文本框相对于页面的比例,它不会改变字符大小,而是改变文本框的尺寸。 4. Leading (Leading, TL): 也叫行距,是指文本行之间的距离,它包括基线到基线的距离以及任何额外的行间距。在InDesign中,可以在“Type” > “Line Spacing” 设置。 5. 文本字体(Font, Tf): 选择合适的字体样式、大小和系列是排版的重要部分。在InDesign中,点击“Type” > “Font” 或者直接在工具栏上选择字体并输入大小。 6. 渲染(Render, Tr): 这个术语可能不太准确,可能是指文本的渲染质量或预览效果。在InDesign中,确保文本以适当的分辨率显示,可以在“Output” > “Previews” 中设置。 要具体操作,打开InDesign,选择所需的文本,然后在菜单栏中找到相应的选项进行调整。请注意,每个软件可能有不同的界面和命名方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值