简体   繁体   English

计算Java中给定二进制字符串的所有可能解码组合

[英]Count all possible decoding Combination of the given binary String in Java

Suppose we have a string of binary values in which some portions may correspond to specific letters, for example:假设我们有一串二进制值,其中某些部分可能对应于特定字母,例如:

A = 0
B = 00
C = 001
D = 010
E = 0010
F = 0100
G = 0110
H = 0001

For example, if we assume the string "00100" , we can have 5 different possibilities:例如,如果我们假设字符串"00100" ,我们可以有5种不同的可能性:

ADA
AF
CAA
CB
EA

I have to extract the exact number of combinations using Dynamic programming.我必须使用动态编程提取确切数量的组合。

But I have difficulty in the formulation of subproblems and in the composition of the corresponding vector of solutions.但是我在子问题的制定和相应的解向量的组成方面有困难。

I appreciate any indications of the correct algorithm formulation.我很欣赏正确算法公式的任何迹象。

class countString {

    static int count(String a, String b, int m, int n) {

        if ((m == 0 && n == 0) || n == 0)
            return 1;

        if (m == 0)
            return 0;

        if (a.charAt(m - 1) == b.charAt(n - 1))
            return count(a, b, m - 1, n - 1) +
                   count(a, b, m - 1, n);
        else
            return count(a, b, m - 1, n);
    }

    public static void main(String[] args) {
        Locale.setDefault(Locale.US);
        ArrayList<String> substrings = new ArrayList<>();
        substrings.add("0");
        substrings.add("00");
        substrings.add("001");
        substrings.add("010");
        substrings.add("0010");
        substrings.add("0100");
        substrings.add("0110");
        substrings.add("0001");

        if (args.length != 1) {
            System.err.println("ERROR - execute with: java countString -filename- ");
            System.exit(1);
        }

        try {
            Scanner scan = new Scanner(new File(args[0])); // not important
            String S = "00100";

            int count = 0;

            for(int i=0; i<substrings.size(); i++){
                count = count + count(S,substrings.get(i),S.length(),substrings.get(i).length());
            }

            System.out.println(count);

        } catch (FileNotFoundException e) {
            System.out.println("File not found " + e);
        }
    }
}

In essence, Dynamic Programming is an enhanced brute-force approach.本质上,动态编程是一种增强的蛮力方法。

Like in the case of brute-force, we need to generate all possible results.就像在蛮力的情况下一样,我们需要生成所有可能的结果。 But contrary to a plain brute-force the problem should be divided into smaller subproblems, and previously computed result of each subproblem should be stored and reused.但是与普通的蛮力相反,问题应该被分成更小的子问题,并且每个子问题的先前计算的结果应该被存储和重用。

Since you are using recursion you need to apply so-called Memoization technic in order to store and reuse the intermediate results.由于您使用的是递归,因此您需要应用所谓的记忆技术来存储和重用中间结果。 In this case, HashMap would be a perfect mean of storing results.在这种情况下, HashMap将是存储结果的完美手段。

But before applying the memoization in order to understand it better, it makes sense to start with a clean and simple recursive solution that works correctly, and only then enhance it with DP.但是在应用memoization以便更好地理解它之前,先从一个干净且简单且正常工作的递归解决方案开始是有意义的,然后才使用 DP 对其进行增强。

Plain Recursion普通递归

Every recursive implementation should contain two parts:每个递归实现都应该包含两个部分:

  • Base case - that represents a simple edge-case (or a set of edge-cases) for which the outcome is known in advance.基本情况- 表示一个简单的边缘情况(或一组边缘情况),其结果是预先知道的。 For this problem, there are two edge-cases: the length of the given string is 0 and result would be 1 (an empty binary string "" results into an empty string of letters "" ), another case is when it's impossible to decode a given binary string and result will be 0 (in the solution below it resolves naturally when the recursive case is being executed).对于这个问题,有两种极端情况:给定字符串的长度为0 ,结果为1 (空二进制字符串""导致空字符串"" ),另一种情况是无法解码给定的二进制字符串和结果将为0 (在下面的解决方案中,它在执行递归案例时自然解析)。

  • Recursive case - a part of a solution where recursive calls a made and when the main logic resides.递归案例- 解决方案的一部分,其中递归调用和主逻辑驻留。 In the recursive case , we need to find each binary "binary letter" at the beginning of the string and then call the method recursively by passing the substring (without the "letter").递归的情况下,我们需要在字符串的开头找到每个二进制“二进制字母”,然后通过传递子字符串(不带“字母”)递归调用该方法。 Results of these recursive calls need to be accumulated in the total count that will returned from the method.这些递归调用的结果需要累积在从方法返回的总数中。

In order to implement this logic we need only two arguments: the binary string to analyze and a list of binary letters :为了实现这个逻辑,我们只需要两个参数:要分析的二进制字符串二进制字母列表

public static int count(String str, List<String> letters) {
    if (str.isEmpty()) { // base case - a combination was found
        return 1;
    }

    // recursive case
    int count = 0;
    
    for (String letter: letters) {
        if (str.startsWith(letter)) {
            count += count(str.substring(letter.length()), letters);
        }
    }        
    return count;
}

This concise solution is already capable of producing the correct result.这个简洁的解决方案已经能够产生正确的结果。 Now, let's turn this brute-force version into a DP-based solution, by applying the memoization .现在,让我们通过应用memoization将这个蛮力版本变成基于 DP 的解决方案。

Dynamic Programming动态规划

As I've told earlier, a HashMap will be a perfect mean to store the intermediate results because allows to associate a count (number of combinations) with a particular string and then retrieve this number almost instantly ( in O(1) time ).正如我之前所说, HashMap将是存储中间结果的完美方法,因为它允许将计数(组合数)与特定字符串相关联,然后几乎立即检索该数字(O(1)时间内)。

That how it might look like:它可能看起来像这样:

public static int count(String str, List<String> letters, Map<String, Integer> vocab) {
    if (str.isEmpty()) { // base case - a combination was found
        return 1;
    }
    if (vocab.containsKey(str)) { // result was already computed and present in the map 
        return vocab.get(str);
    }

    int count = 0;

    for (String letter: letters) {
        if (str.startsWith(letter)) {
            count += count(str.substring(letter.length()), letters, vocab);
        }
    }
    vocab.put(str, count); // storing the total `count` into the map

    return count;
}

main()

public static void main(String[] args) {
    
    List<String> letters = List.of("0", "00", "001", "010", "0010", "0100", "0110", "0001"); // binary letters

    System.out.println(count("00100", letters, new HashMap<>())); // DP
    System.out.println(count("00100", letters));                  // brute-force recursion
}

Output:输出:

5   // DP
5   // plain recursion

A link to Online Demo在线演示的链接

Hope this helps.希望这可以帮助。 Idea is to create every possible string with these values and check whether input starts with the value or not.想法是使用这些值创建每个可能的字符串,并检查input是否以该值开头。 If not then switch to another index.如果没有,则切换到另一个索引。

If you have test cases ready with you you can verify more.如果您准备好测试用例,您可以验证更多。 I have tested only with 2-3 values.我只测试了 2-3 个值。

public int getCombo(String[] array, int startingIndex, String val, String input) {
    int count = 0;
    for (int i = startingIndex; i < array.length; i++) {
        String matchValue = val + array[i]; 

        if (matchValue.length() <= input.length()) {
            // if value matches then count + 1
            if (matchValue.equals(input)) {
                count++;
                System.out.println("match Found---->" + count); //ommit this sysout , its only for testing.
                return count;
            } else if (input.startsWith(matchValue)) { // checking  whether the input is starting with the new value 
                // search further combos
                count += getCombo(array, 0, matchValue, input);
            }
        }
    }
    return count;
}

In main Method在主要方法中

String[] arr = substrings.toArray(new String[0]);
int count = 0;
for (int i = 0; i < arr.length; i++) {
    System.out.println("index----?> " + i);
   
    //adding this condition for single  inputs i.e "0","010";
    if(arr[i].equals(input))
         count++;
    else 
        count = count + getCombo(arr, 0, arr[i], input);
}

System.out.println("Final count :  " + count);

My test results :我的测试结果:

input : 00100
Final count 5 

input : 000
Final count 3 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM