C ++与Java记忆化差异

时间:2019-01-09 11:14:19

标签: java c++ recursion dynamic-programming memoization

因此,我一直在尝试解决分词动态编程问题,这基本上意味着给定一个字符串字典和一个字符串,看看字典中的单词是否可以组合成字符串。例如,给定单词“ applepenapple”和字典[“ apple”,“ pen”],它应该返回true。

我有一个有效的Java解决方案,但我正在尝试提高C ++技能。我的问题是,即使我的代码看上去与Java中的工作解决方案极为相似,我也没有通过适当的测试案例,而且我不知道为什么。

C ++代码:

bool wordBreak(string s, vector<string> &wordDict) {
    vector<int> bArr(s.length(), -1);
    unordered_set<string> set(wordDict.begin(), wordDict.end());
    return wordBreak(s, bArr, 0, set);
}

bool wordBreak(string s, vector<int> &bArr, int start, unordered_set<string> &set) {
    if (start == s.length())
        return true;
    //If we have a memoized solution to this problem, avoid recurion
    if (bArr[start] != -1)
        return (bArr[start] == 1);
    for (int end = start + 1; end <= s.length(); end++) {
        if (set.count(s.substr(start, end)) && wordBreak(s, bArr, end, set)) {
            bArr[start] = 1;
            return bArr[start] == 1;
        }
    }
    bArr[start] = 0;
    return false;
}

使用Java的工作代码:

public boolean wordBreak(String s, List<String> wordDict) {
    Integer[] memo =new Integer[s.length()];
    Arrays.fill(memo,-1);
    return word_Break(s, new HashSet(wordDict), 0, memo);
}

public boolean word_Break(String s, Set<String> wordDict, int start, Integer[] memo) {
    if (start == s.length()) {
        return true;
    }
    if (memo[start] != -1) {
        return memo[start]==1;
    }
    for (int end = start + 1; end <= s.length(); end++) {
        if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end, memo)) {
            memo[start] = 1;
            return memo[start] == 1;
        }
    }
    memo[start] = 0;
    return false;
}

对于带有字典[“ apple”,“ pen”]的“ applepenapple”,C ++代码返回false,但我不知道为什么,因为java返回true才是正确的。两种解决方案之间的唯一主要区别(我认为)是我的C ++使用向量而不是Java代码中的本机数组。最初,我认为这可能与使用自动存储(堆栈)与自由存储(堆)的C ++有关,这就是为什么我使用向量而不是C样式的数组来避免由于RAII而导致的内存管理的原因。尽管进行了此更改,该错误仍然存​​在。有一个更简单的解决方案可以完全避免递归,但是我很好奇为什么C ++返回的输出与Java不同。

1 个答案:

答案 0 :(得分:4)

我看到一个潜在的问题。来自java.lang.String Javadoc(重点是我):

  

public String substring(int beginIndex, int endIndex)

     

返回一个新字符串,该字符串是该字符串的子字符串。子字符串从指定的beginIndex开始,并扩展到索引endIndex-1处的字符。因此,子字符串的长度为endIndex-beginIndex。

     

示例:

"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile"
     

参数:

     

beginIndex-起始索引(包含首尾)。

     

endIndex-结束索引,排他。

来自cppreference.com documentation on strings

  

basic_string substr( size_type pos = 0, size_type count = npos ) const;

     

返回一个子字符串[pos,pos + count)。如果所请求的子字符串超出了字符串的末尾,或者如果count == npos,则返回的子字符串为[pos,size())。

     

参数

     

pos-要包含的第一个字符的位置

     

count-子字符串的长度

也就是说,在Java中,应将索引作为第二个参数传递给String.substring(...),但在C ++中,应将长度传递给basic_string::substr(...)。但是,您正在这样做:

s.substr(start, end)

s.substring(start, end)

在两种情况下

也许将C ++调用调整为

s.substr(start, end - start)

会起作用吗?