动态规划 - 分词

Posted

技术标签:

【中文标题】动态规划 - 分词【英文标题】:Dynamic Programming - Word Break 【发布时间】:2014-08-06 18:55:20 【问题描述】:

我正在尝试解决this问题。问题如下 给定一个输入字符串和一个单词字典,找出输入字符串是否可以分割成一个空格分隔的字典单词序列。

字典是一个字符串数组。

我的方法是以下递归 fn,存储递归调用的结果。输出很好,但我看到存储的结果从未使用过。 我的解决方案希望是正确的,因为它通过了测试用例。但是如果我知道是否使用了 DP,那就太好了。

代码是:

#include <iostream>
#include <string.h>
using namespace std;

int r[100][100] = 0;  //To Store the calculated values


bool searchWord(char q[], char D[][20], int start, int end) 
    cout << "In Search Word Loop with " << start << " " << end << endl;
    char temp[end - start + 1];
    int j = 0;

    for (int i = start; i <= end ; ++i) 
        //cout << "Looping i " << i << endl;
        temp[j] = q[i];
        j++;
    

    // cout << "For Word " << temp << endl;
    for (int i = 0; i < 12; ++i) 
        // cout << "Comparing with " << D[i] << endl;
        if (!strcmp(temp, D[i])) 
            cout << "Found Word" << temp << " " << D[i] << endl;
            return 1;
        
    

    return 0;


bool searchSentence(char q[], char D[][20], int qstart, int qend) 
    cout << "In Search Sentence Loop" << endl;
    if (r[qstart][qend] != 0) 
        cout << "DP Helped!!!" << endl;
        return 1;
    

    if (qstart == qend) 
        if (searchWord(q, D, qstart, qstart))
            return 1;
        else return 0;
    
    if (qstart > qend) return 1;

    int i;
    for (i = qstart; i <= qend; i++) 
        if (searchWord(q, D, qstart, i)) 
            r[i + 1][qend] = searchSentence(q, D, i + 1, qend);
            if (r[i + 1][qend] == 1) return 1;
        
    

    return 0;


int main() 
    char D[20][20] =  "i", "like", "sam", "sung", "samsung", "mobile", "ice", "cream", "icecream", "man", "go", "mango";
    char q[100] = "samsungmango";

    int index = 0; char ch;
    ch = q[0];
    while (ch != '\0') 
        index++;
        ch = q[index];
    

    if (searchSentence(q, D, 0, index - 1))
        cout << "Yes" << endl;
    else cout << "No" << endl;

【问题讨论】:

【参考方案1】:

递归是强制性的吗?我明白了,迭代 DP 解决方案最简单且紧凑:

#include <stdio.h>
#include <string.h>

int main() 
  const char *D[] =  "i", "like", "sam", "sung", "samsung", "mobile", "ice", "cream", "icecream", "man", "go", "mango", NULL;
  const char q[] = "samsungmango";
  char dp[100];
  short d_len[20];
  memset(dp, 0, sizeof(dp));
  dp[0] = 1; // 0 element is always reacheable
  int i, j;
  // compute dict string lengths
  for(i = 0; D[i]; i++)
      d_len[i] = strlen(D[i]);

  // Compute splits using DP array
  for(i = 0; q[i] != 0; i++)
      if(dp[i])  // this index is reacheable
          for(j = 0; D[j]; j++) // try to make next reacheable indexes
              if(strncmp(&q[i], D[j], d_len[j]) == 0)
                  dp[i + d_len[j]] = 1; // That position is reacheable, too

  // if EOLN(q) is reached, then yes
  printf("Answer is %s\n", dp[i]? "YES" : "NO");

 // main

【讨论】:

这个问题的最佳方法。简单有效。 你所说的“可达”是什么意思? reachable = 这个位置可以通过字典单词的组合到达。位置 0 代表“空字符串”。【参考方案2】:

您的代码实际上是错误的。要使您的代码失败,请尝试像“likeman”这样的输入

请注意,函数searchSentence 可能有两个不同的返回值,即 0 或 1。因此,如果您将 r 数组初始化为 0,则无法保证在 r[x][y] = 0 时它是一个新状态。用一些不可能的值初始化 r 数组,如该程序的 -1 或 2 并再次测试。现在你可以很容易地确认如果r[qbegin][qend] != -1那么这个状态已经被检查了所以你可以从这里返回r[qbegin][qend]

更新代码:

#include <iostream>
#include <string.h>
using namespace std;

int r[100][100];  //To Store the calculated values

bool searchWord(char q[], char D[][20], int start, int end)

    cout << "In Search Word Loop with " << start << " " << end << endl;



    char temp[end - start + 1];
    int j = 0;

    for (int i = start; i <= end ; ++i)
    
        //cout << "Looping i " << i << endl;
        temp[j] = q[i];
        j++;
    
    temp[j] = '\0';

    //cout << "For Word " << temp << endl;

    for (int i = 0; i < 12; ++i)
    
        // cout << "Comparing with " << D[i] << endl;
        if (!strcmp(temp, D[i]))
        
            cout << "Found Word" << temp << " " << D[i] << endl;
            return 1;
        
    

    return 0;


bool searchSentence(char q[], char D[][20], int qstart, int qend)

    cout << "In Search Sentence Loop" << endl;

    if (r[qstart][qend] != -1)
    
        cout << "DP Helped!!!" << endl;
        return r[qstart][qend];
    


    if (qstart == qend)
    
        if (searchWord(q, D, qstart, qstart))
            return 1;
        else return 0;
    
    if (qstart > qend) return 1;

    int i;

    for (i = qstart; i <= qend; i++)
    
        if (searchWord(q, D, qstart, i))
        
            r[i + 1][qend] = searchSentence(q, D, i + 1, qend);
            if (r[i + 1][qend] == 1) return 1;
        
    
    return 0;


int main()

    char D[20][20] =  "i", "like", "sam", "sung", "samsung", "mobile", "ice", "cream", "icecream", "man", "go", "mango";
    char q[100] = "ilike";

    int index = 0; char ch;
    ch = q[0];
    memset(r, -1, sizeof(r));
    while (ch != '\0')
    
        index++;
        ch = q[index];
    

    if (searchSentence(q, D, 0, index - 1))
    cout << "Yes" << endl;
    else cout << "No" << endl;

P.S : 有一些多余的代码行,但我没有更改它们,我在函数 searchWord 中的字符数组 temp 的末尾添加了一个空字符

【讨论】:

这不是逻辑,基本上这是一个错误和初始化的东西

以上是关于动态规划 - 分词的主要内容,如果未能解决你的问题,请参考以下文章

虾扯编程4——动态规划与背包问题

动态规划下的维特比算法在词性预测上的应用

NLP之最短路径分词

算法动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )

算法动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )

算法动态规划 ② ( 动态规划四要素 | 动态规划状态 State | 动态规划初始化 Initialize | 动态规划方程 Function | 动态规划答案 Answer )