LintCode第107题-单词拆分-新版

发布于:2025-08-17 ⋅ 阅读:(12) ⋅ 点赞:(0)

描述

给定字符串 s 和单词字典 dict,判断是否可以利用字典 dict 中的出现的单词拼接出 s,其中字典 dict 中的单词可以重复使用。

因为我们已经使用了更强大的数据,所以普通的DFS方法无法解决此题

s.length<=1e5
dict.size<=1e5

样例 1:

输入:

s = "lintcode"
dict = ["lint", "code"]

输出:

true

解释:

lintcode可以分成lint和code。

样例 2:

输入:

s = "a"
dict = ["a"]

输出:

true

解释:

a在dict中

思路:判断dict是否可以拼出目标字符串s.首先判断使用哪种算法

简单来说 常用的求方案总数 最值 可行性大多数用动态规划  即不是具体的方案 

也可以细分通过最优子结构和重叠子问题判断

最优子结构(切最后一段
把字符串 s[0..i) 能否拆分,拆到“最后一段”来想:
存在某个切分点 j<i,若

  • 前缀 s[0..j) 可拆(这是一个更小的同类问题),并且

  • 最后一段 s[j..i) 在词典里,
    s[0..i) 也可拆。
    这直接给出状态与转移:

  • dp[i] = OR_{j<i}( dp[j] && inDict(s[j..i)) ) OR即逻辑或

  • 等价文字写法就是存在某个 j(0 ≤ j < i),使得前缀 s[0..j) 可拆且最后一段 s[j..i) 在字典里,那么 dp[i] 为真

重叠子问题
不同的 i 会反复查询相同的前缀可行性,比如 dp[10]dp[11] 都会用到 dp[7]dp[8] 等。DP一次算好可以重复利用

知道用动态规划后那么下面就是动态规划的四要素

//状态 dp[i]

//状态转移方程 递推一下

判断“前 i 个字符可拼”就看“它的最后一刀切在哪个 j”

“左边可拼 + 右边是词” ⇒ 整体可拼

所以在代码里对所有 j

if (dp[j] && wordSet.contains(s.substring(j, i))) {
    dp[i] = true; break;
}

其中状态转移方程为:dp[i]=dp[j]&&wordSet.contains(s.substring(j,i));

//初始化dp[0]=true;

//边界条件s.length()<Set.size()&&s.length()>=0

代码如下:

    public class Solution {

        /**

         * @param s: A string

         * @param wordSet: A dictionary of words dict

         * @return: A boolean

         */

        public boolean wordBreak(String s, Set<String> wordSet) {

          // 健壮性

        if (s == null || wordSet == null) return false;

         int n=s.length();

         boolean dp[]=new boolean[n+1];//易错点1  容易少写一个 为n因为dp[0]占据了一位 dp[i] 表示:前 i 个字符 即

         //s = "leet",n = 4

        //我们需要 dp[0], dp[1], dp[2], dp[3], dp[4] 共 5 个状态:

        //dp[0]=空串,dp[4]=整串结果 →自然是 n+1 即dp[]数组是状态表示  表示长度为 n 的串,有 //n+1 个切分点(含头尾)

         dp[0]=true;

         int maxWordLength=0;//最长单词长度

         int minWordLength=Integer.MAX_VALUE;//最短单词长度        

        //maxWordLength:保证不检查比任何词都长的片段 → 收紧 j 的起点。

        //minWordLength:保证不检查比任何词都短的片段 → 可以提前从 i=minWordLength 开跑,//并收紧 j 的终点 剪枝截取片段是从j至i

         //分别统计单词的最长长度和最短长度

         for(String str:wordSet)

         {

             int currentWordLength=str.length();

            if (currentWordLength == 0)

                {

                continue;

                }  

             if(maxWordLength<currentWordLength)

             {

                 maxWordLength=currentWordLength;

             }

             if(minWordLength>currentWordLength)

             {

                minWordLength=currentWordLength;

             }

         }

         for(int i=minWordLength;i<=n;i++)

         {

             int jStart = Math.max(0, i - maxWordLength);

             for (int j = jStart; j < i; j++)

             {

              if(dp[j]&&wordSet.contains(s.substring(j,i)))

              {

                  dp[i] = true;

                   break;

              }

             }

         }

         return dp[n];

        }

    }


网站公告

今日签到

点亮在社区的每一天
去签到