1

我正在处理一个 DP 问题,其中删除了空格的字符串,我需要实现自下而上和记忆化版本以将字符串拆分为单个英文单词。然而,我得到了自下而上的版本,然而,记忆似乎有点复杂。

 /* Split a string into individual english words
 * @String str the str to be splitted
 * @Return a sequence of words separated by space if successful,
     null otherwise
 */
public static String buttom_up_split(String str){
    int len = str.length();
    int[] S = new int[len+1];
    /*Stores all the valid strings*/
    String[] result = new String[len+1];  
    /*Initialize the array*/
    for(int i=0; i <= len; i++){
        S[i] = -1;
    }
    S[0] =0;
    for(int i=0; i < len; i++){
        if(S[i] != -1){
            for(int j= i+1; j <= len; j++){
                String sub = str.substring(i, j);
                int k = j;      
                if(isValidEnglishWord(sub)){
                    S[k] = 1; //set true indicates a valid split
                    /*Add space between words*/
                    if(result[i] != null){ 
                        /*Add the substring to the existing words*/
                        result[i+ sub.length()] = result[i] + " " + sub;
                    }
                    else{
                        /*The first word*/
                        result[i+ sub.length()] = sub;
                    }
                }

            }
        }
    }
    return result[len];  //return the last element of the array
}

我真的很困惑如何将这个buttom_up_version转换为memoized版本,希望有人能帮忙..

4

2 回答 2

1

好吧,我不是记忆的出口,但我的想法是对以前的好英语单词有一个“记忆”。目标是节省计算时间:在您的情况下,调用 isValidEnglishWord()。

因此,您需要以这种方式调整您的算法:

  1. 遍历“str”字符串
  2. 从中提取一个子字符串
  3. 检查子字符串是否是您记忆中的有效单词。
    1. 它在内存中:在结果中添加空格和单词。
    2. 它不在内存中:调用 isValidEnglishWord 并处理它的返回。

它会给出类似的东西(未经测试或编译)

// This is our memory
import java.util.*

private static Map<String, Boolean> memory = new HashMap<String, Boolean>()

public static String buttom_up_split(String str){
   int len = str.length();
   int[] S = new int[len+1];

   String[] result = new String[len+1];  
   for(int i=0; i <= len; i++){
      S[i] = -1;
   }
   S[0] =0;
   for(int i=0; i < len; i++){
      if(S[i] != -1){
         for(int j= i+1; j <= len; j++){
            String sub = str.substring(i, j);
            int k = j;    

            // Order is significant: first look into memory !
            Boolean isInMemory = memory.contains(sub);
            if (isInMemory || isValidEnglishWord(sub)){
                S[k] = 1;
                if(result[i] != null){ 

                    // Memoize the result if needed.
                    if (!isInMemory) {
                        memory.put(sub, true);
                    }

                    result[i+ sub.length()] = result[i] + " " + sub;
                } else {
                    result[i+ sub.length()] = sub;
                }
            }

        }
    }
}
return result[len];

}

于 2012-06-02T07:54:11.877 回答
0

就个人而言,我总是更喜欢尽可能透明地使用记忆而不修改算法。这是因为我希望能够与记忆分开测试算法。此外,我正在开发一个 memoization 库,您只需将 @Memoize 添加到 memoization 适用的方法中。但不幸的是,这对你来说为时已晚。

上次我使用 memoization(没有我的库)时,我使用代理类实现了它。一个重要的说明是这个实现不支持递归。但这应该不是问题,因为您的算法不是递归的。

其他一些参考是:

关于您的算法的评论:您如何处理其中包含其他单词的单词?像“verbose”包含“verb”,“theory”包含“the”等...

于 2012-06-03T10:45:21.247 回答