【问题标题】:Data structure choice for dynamic programming动态规划的数据结构选择
【发布时间】:2014-06-18 04:16:31
【问题描述】:

为了实现一个DP算法来检测一个词是否可以分解成长度为'n'到1的子词,应该选择什么样的数据结构来缓存DP结果。 示例: 单词“pita”可以分解为“pit”、“it”和“i”,它们都是有效的字典单词。 DP算法应该会检测到这样的词。

我可以想象我需要从长度为 1 的单词开始并构建长度增加的子字符串,但我无法得出可以有效存储子问题结果的数据结构

【问题讨论】:

  • ArrayList 适合这个,它会自动增加
  • 函数返回什么?拆分方式的数量,或者只是有任何有效的拆分?还是有效拆分的集合?
  • 它应该只是一个布尔值,表示单词是否可以分解为从 n 到 1 的所有长度。对于 'pita' 它将是 'true' 但对于单词 'are' - 返回值应该是'假'
  • 所以应该是boolean[]dp,其中dp[i]表示从i开始,i的子串是否有有效分割,最终结果在dp[0]
  • tip 也有用吗?还是不允许更改字符位置?

标签: algorithm data-structures dynamic-programming


【解决方案1】:

如果您按顺序处理单词,则无需跟踪前一个单词,因为您不会再次访问它们,但您可以使用缓存来缓存字典中先前查找的子单词。 如果我理解这个问题,那么我认为以下 Java 代码可能会对您有所帮助:

String term = "pita";
Set<String> dictionary = new HashSet<String>();
boolean ans = true;
for(int i = 0; i < term.length() && ans == true; i++) {
    for(int j = i + 1; j < term.length(); j++) {
        String subTerm = term.substring(i, j);
        if(!dictionary.contains(subTerm)){
            ans = false;
            break;
        }
    }
}
System.out.println("ans [" = ans + "]");

对于字典,您可以使用哈希表,它支持使用 O(1) 来检查子 词存在与否。如果你缓存之前检查过的子词,它将花费相同的 O(1)

我认为这个问题适合 排序和搜索 技术而不是 DP,因为 它没有使用以前的答案来生成当前答案。

【讨论】:

  • 首先,内部循环将检查从 i 开始的每一对 (i,j),如果其中一对不在字典中,则结果将为 false。所以你的代码只是检查term 中的每个子字符串,它们都在字典中,这是不正确的。二、substring(start, end)的语法错误,应该是term.substring(i, j + 1),你试试看不一样。
【解决方案2】:

不需要特殊的数据结构,因为这样的布尔 DP 数组就足够了:-

isSentence[j] 告诉子串 str[j to n] 是有效的串联 英文单词/单词,其中 n 是最后一个索引

isSentence[j] = or(isword(str[j to i]) && isSentece[i+1]) for all i 从j到n

这里表示所有子问题的逻辑或,isword 是字典 返回布尔值和 && 逻辑与的查找

【讨论】:

    【解决方案3】:

    我可以想象我需要从长度为 1 的单词开始,并建立长度增加的子字符串,但我无法得出可以有效存储子问题结果的数据结构

    以下是用Java编写的伪代码可能无法编译

    TrieNode.java

    class TrieNode
    {
        public TrieNode (double a, double b, double g, int size)
        {
            this.alpha = a;
            this.beta = b;
            this.gamma = g;
            this.next = new TrieNode [size];
        }
        public double alpha, beta, gamma;
        public TrieNode [] next;
    }
    

    您可以将alphabetagamma 替换为问题的参数。

    Trie.java

    class Trie
    {
    
        private TrieNode root;
        private char base;
        private final int ALPHABET_SIZE;
    
        public Trie (int ALPHABET_SIZE, char base_char)
        {
            this.base = base_char;
            this.root=new TrieNode(0,0,0,ALPHABET_SIZE);
        }
    
        public boolean insert (String word, double [] param)
        {
            TrieNode current = this.root;
            int i = (-1);
    
            if (!validate(word))
                return false;
    
            char [] c = word.toCharArray();
    
            for (int i = 0; i < (c.length-1); i++)
            {
                if (current.next[c[i]-base] == null)
                    current.next[c[i]-base] = new TrieNode (0,0,0,ALPHABET_SIZE);
                current = current.next[c[i]-base];
            }
    
            if (current.next[c[i]-base] == null)
                current.next[c[i]-base] = new TrieNode (0,0,0,ALPHABET_SIZE);
    
            current.next[c[i]-base].alpha = param[0];
            current.next[c[i]-base].beta = param[1];
            current.next[c[i]-base].gamma = param[2];
            return true;
        }
    
        public boolean validate (String word)
        {
            for (char c : word.toCharArray())
                if (c < base || c > (base+ALPHABET_SIZE-1))
                    return false;
        }
    
    }
    

    这是一个基于索引的Trie,具有安全插入功能。

    MappedTrie.java

    class MappedTrie
    {
        public final char [] ALPHABET;
        private Trie trie;
    
        MappedTrie (char [] alphabet)
        {
            ALPHABET = alphabet;
            trie = new Trie (ALPHABET.length,0);
        }
    
        public boolean insert (String word, double [] param)
        {
            if (!validate(word))
                return false;
    
            String key = "";
    
            for (char c : word.toCharArray())
                key += encode(c);
    
            return trie.insert(key,param);
    
        }
    
        private char encode (char c)
        {
            for (int i=0; i<ALPHABET.length; i++)
                if (c == ALPHABET[i])
                    return i;
        }
    
        private char decode (char d)
        {
            return ALPHABET[d];
        }
    
        public boolean validate (String word)
        {
            boolean exist = false;
    
            for (char c : word.toCharArray())
            {
                exist = false;
                for (char d : ALPHABET) if (c == d) { exist = true; break; }
                if (!exist) return false;
            }
    
            return true;
        }
    
    }
    

    如果自定义字母表中的字符不相邻,我们可以将其映射到索引上。

    测试

    class Test
    {
        public static void main (String [] args)
        {
            // 'a'+0, 'a'+1, 'a'+2
            MappedTrie k = new MappedTrie(3, 'a');
    
            k.insert("aa", { 0.1, 0.2, 0.3 });
            k.insert("ab", { 0.4, 0.5, 0.6 });
            k.insert("ac", { 0.7, 0.8, 0.9 });
    
            k.insert("ba", { 0.01, 0.02, 0.03 });
            k.insert("bb", { 0.04, 0.05, 0.06 });
            k.insert("bc", { 0.07, 0.08, 0.09 });
    
            k.insert("ca", { 0.001, 0.002, 0.003 });
            k.insert("cb", { 0.004, 0.005, 0.006 });
            k.insert("cc", { 0.007, 0.008, 0.009 });
    
            // 'a' => 0, 'b' => 1, 'c' => 2
            MappedTrie t = new MappedTrie({'a','b','c'});
    
            t.insert("aa", { 0.1, 0.2, 0.3 });
            t.insert("ab", { 0.4, 0.5, 0.6 });
            t.insert("ac", { 0.7, 0.8, 0.9 });
    
            t.insert("ba", { 0.01, 0.02, 0.03 });
            t.insert("bb", { 0.04, 0.05, 0.06 });
            t.insert("bc", { 0.07, 0.08, 0.09 });
    
            t.insert("ca", { 0.001, 0.002, 0.003 });
            t.insert("cb", { 0.004, 0.005, 0.006 });
            t.insert("cc", { 0.007, 0.008, 0.009 });
        }
    }
    

    【讨论】:

      【解决方案4】:

      我认为使用unordered_map&lt;string, int&gt;unordered_set&lt;string&gt; 可能会很有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-07
        • 2014-03-25
        • 2016-02-09
        • 1970-01-01
        • 2015-03-02
        • 2020-07-05
        相关资源
        最近更新 更多