簡體   English   中英

計算Java中給定二進制字符串的所有可能解碼組合

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

假設我們有一串二進制值,其中某些部分可能對應於特定字母,例如:

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

例如,如果我們假設字符串"00100" ,我們可以有5種不同的可能性:

ADA
AF
CAA
CB
EA

我必須使用動態編程提取確切數量的組合。

但是我在子問題的制定和相應的解向量的組成方面有困難。

我很欣賞正確算法公式的任何跡象。

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);
        }
    }
}

本質上,動態編程是一種增強的蠻力方法。

就像在蠻力的情況下一樣,我們需要生成所有可能的結果。 但是與普通的蠻力相反,問題應該被分成更小的子問題,並且每個子問題的先前計算的結果應該被存儲和重用。

由於您使用的是遞歸,因此您需要應用所謂的記憶技術來存儲和重用中間結果。 在這種情況下, HashMap將是存儲結果的完美手段。

但是在應用memoization以便更好地理解它之前,先從一個干凈且簡單且正常工作的遞歸解決方案開始是有意義的,然后才使用 DP 對其進行增強。

普通遞歸

每個遞歸實現都應該包含兩個部分:

  • 基本情況- 表示一個簡單的邊緣情況(或一組邊緣情況),其結果是預先知道的。 對於這個問題,有兩種極端情況:給定字符串的長度為0 ,結果為1 (空二進制字符串""導致空字符串"" ),另一種情況是無法解碼給定的二進制字符串和結果將為0 (在下面的解決方案中,它在執行遞歸案例時自然解析)。

  • 遞歸案例- 解決方案的一部分,其中遞歸調用和主邏輯駐留。 遞歸的情況下,我們需要在字符串的開頭找到每個二進制“二進制字母”,然后通過傳遞子字符串(不帶“字母”)遞歸調用該方法。 這些遞歸調用的結果需要累積在從方法返回的總數中。

為了實現這個邏輯,我們只需要兩個參數:要分析的二進制字符串二進制字母列表

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;
}

這個簡潔的解決方案已經能夠產生正確的結果。 現在,讓我們通過應用memoization將這個蠻力版本變成基於 DP 的解決方案。

動態規划

正如我之前所說, HashMap將是存儲中間結果的完美方法,因為它允許將計數(組合數)與特定字符串相關聯,然后幾乎立即檢索該數字(O(1)時間內)。

它可能看起來像這樣:

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
}

輸出:

5   // DP
5   // plain recursion

在線演示的鏈接

希望這可以幫助。 想法是使用這些值創建每個可能的字符串,並檢查input是否以該值開頭。 如果沒有,則切換到另一個索引。

如果您准備好測試用例,您可以驗證更多。 我只測試了 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;
}

在主要方法中

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);

我的測試結果:

input : 00100
Final count 5 

input : 000
Final count 3 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM