【问题标题】:Getting specific combinations of a character array获取字符数组的特定组合
【发布时间】:2020-07-14 01:47:46
【问题描述】:

我对制作自己的算法还很陌生,但我在尝试为我正在创建的游戏创建一个算法时遇到了困难。新机制正在寻找玩家可以在这个单词争夺游戏中输入的隐藏单词。

问题

假设我有一个包含 { h, o, t, e, l, b, o, w } 的字符数组。我需要能够像这样在哪里获得数组的组合:

  1. 每个单词至少包含 3 个字母
  2. 必须使用所有字母,否则序列无效。
  3. 没有重叠

所需序列:

  1. 热,弯头
  2. 热,低头
  3. 酒店,弓
  4. hotelbow

我的想法是我可以使用我的数据库检查每个序列中的有效单词,并且在示例中序列 1 和 3 是有效的。

这是一个简单的例子,如果数组小于或等于 5 个字符,也可以只有 1 个序列,如果数组有 9 个字符,则可以有 3 个有效的密码。

添加另一个示例,其中字符数组包含 { s, i, x, c, a, t, r, o, w }:

所需顺序:

  1. 六、猫、行
  2. 六、猫头鹰
  3. 六,阿罗
  4. sixca, 特罗
  5. 六猫,行
  6. 六只猫

在这个例子中,只有序列 1 在检查后是有效的,但它能够找出 3 个隐藏的单词来奖励玩家。

【问题讨论】:

  • 我猜你的意思是 seq 1 & 3 是有效的(不是 1 & 2)。我对其进行了编辑,但如果您真的是指 1 和 2,请随时恢复(并解释原因,因为这对我来说没有意义)。字母的顺序必须相同吗?那么{hob, towel} 无效?
  • 啊,错了,是的,您对编辑的看法是正确的。我很欣赏编辑。是的,字母的顺序必须相同,因此 {hob, towel} 无效。
  • 同一个数组可以容纳2个以上的单词吗?
  • 是的,可以辨认出两个以上的单词。

标签: java arrays algorithm


【解决方案1】:

这里有一些针对这个问题的递归算法的伪代码。基本思想是将问题分解成更小的问题,直到你到达一个可以轻松解决的基本条件(在这种情况下,要么我们使用了所有字母,要么没有足够的字母来组成一个单词)。

// This method "bootstraps" the recursive algorithm
public List<List<String>> findWords(String input) {
    List<List<String>> results = new ArrayList<>();
    findHiddenWordsRecursive(input, new ArrayList(), results);
    return results;
}

private void findHiddenWordsRecursive(String remainingLetters,
                              List<String> partialResult,
                              List<List<String>> results) {

   If there are no remaining letters, then we used all the letters,
   so add the "partial results" to the results, then return.
 
   If there aren't enough letters remaining to make a word, return.

   Loop over all the possible lengths the next word could have.
   (minimum is 3, max is remainingLetters.length).

   For each possible length N:

       If the first N letters of remaining letters is a dictionary word:
           Copy partialResult into a new list called "nextPartialResult".
           Add the word to nextPartialResult.

           Define a string "nextRemainingLetters" which is the substring
           of remainingLetters starting at index N.

           Call findHiddenWordsRecursive(nextRemainingLetters,
                                         nextPartialResult,
                                         results)
}

【讨论】:

    【解决方案2】:

    这完全符合您的要求。为简单起见,我使用了deque

    import java.util.*;
    
    public class Main {
        
        public static HashSet<String> dictionary = new HashSet<String>(); 
        
        public static void test(Deque<String> deque){
            for (Iterator itr = deque.iterator(); itr.hasNext();) { 
                if(!dictionary.contains(itr.next())) return;
            }
            
            System.out.print("Found combination: ");
            for (Iterator itr = deque.iterator(); itr.hasNext();) { 
                System.out.print(itr.next() + " ");
            }
            System.out.println();
        }
        
        public static void checkCombinations(String s, int index, Deque<String> deque){
            int rest = s.length() - index;
            if(rest < 6) {
                deque.addLast(s.substring(index, s.length()));
                test(deque);
                deque.removeLast();
                return;
            }
            for(int i = index + 3; i < s.length() - 2; i++){
                deque.addLast(s.substring(index, i));
                checkCombinations(s, i, deque);
                deque.removeLast();
            }
            deque.addLast(s.substring(index, s.length()));
            test(deque);
            deque.removeLast();
        }
        
        public static void main(String[] args) {
            Deque<String> deque = new LinkedList<String>();
            dictionary.add("hotel"); 
            dictionary.add("bow"); 
            dictionary.add("hot"); 
            dictionary.add("elbow");
            checkCombinations("hotelbow", 0, deque);
        }
    }
    

    输出:

    Found combination: hot elbow 
    Found combination: hotel bow 
    

    【讨论】:

      【解决方案3】:

      这个问题似乎非常适合递归解决方案。我的方法是定义递归如下:

      • 输入:字符数组s和限制startend。该过程仅考虑从start(包括)到end(不包括)的s 部分。这将表示为s[start,end)
      1. [初始化] 定义一个名为result的空序列列表。
      2. [递归案例]如果end-start &gt;= 6,定义一个分区索引p,范围从start+3end-3(含)。递归地在列表left 中收集s[start,p) 的序列,并在列表right 中类似地收集s[p,end) 的序列。追加到result 的笛卡尔积leftright。 (即,对于作为left 的元素的每个序列f 和作为right 的元素的每个序列g,将串联的序列f, g 附加到result。)
      3. [基本情况] 如果end-start &gt;= 3,将整个单词s[start,end) 附加到result。 (可选:仅在 s[start,end) 是有效单词时附加。)
      4. 返回result

      要生成整个列表,请使用原始字符数组调用此方法,并使用 0 表示 start,使用数组长度表示 end

      如果您只对有效序列感兴趣,您可以将字典测试注入此过程。然后在第 3 步中,仅在通过测试时将s[start,end) 附加到result。这样,您只返回有效的序列开始。这会更有效率,特别是考虑到无效序列通常会更常见。请注意,这将打开该方法返回空列表的可能性,因此left 和/或right 在步骤 2 中可能为空;如果发生这种情况,笛卡尔积也将为空。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多