计算 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);
}
}
}
希望这对您有所帮助。
想法是用这些值创建每个可能的字符串并检查 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
本质上,动态规划是一种增强的brute-force方法。
就像brute-force的情况一样,我们需要生成所有可能的结果。但是与普通的 brute-force 相反,问题应该被分成更小的子问题,每个子问题的先前计算结果应该被存储和重用。
由于您使用的是 递归 您需要应用 so-called Memoization 技术来存储和重用中间结果.在这种情况下,HashMap
将是存储结果的完美方式。
但在应用 memoization 之前,为了更好地理解它,从一个干净简单的 递归解决方案 开始是有意义的正常工作,然后才用 DP 增强它。
普通递归
每个递归实现都应该包含两部分:
基本案例 - 表示结果已知的简单 edge-case(或一组 edge-case)提前。对于此问题,有两个 edge-case:给定字符串的长度为 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.
将这个 brute-force 版本变成 DP-based 解决方案
动态规划
正如我之前所说,HashMap
将是存储中间结果的完美方式,因为允许将 count(组合数)与一个特定的字符串,然后几乎立即检索这个数字 (in O(1) time).
它可能看起来像:
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
假设我们有一个二进制值字符串,其中某些部分可能对应于特定的字母,例如:
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);
}
}
}
希望这对您有所帮助。
想法是用这些值创建每个可能的字符串并检查 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
本质上,动态规划是一种增强的brute-force方法。
就像brute-force的情况一样,我们需要生成所有可能的结果。但是与普通的 brute-force 相反,问题应该被分成更小的子问题,每个子问题的先前计算结果应该被存储和重用。
由于您使用的是 递归 您需要应用 so-called Memoization 技术来存储和重用中间结果.在这种情况下,HashMap
将是存储结果的完美方式。
但在应用 memoization 之前,为了更好地理解它,从一个干净简单的 递归解决方案 开始是有意义的正常工作,然后才用 DP 增强它。
普通递归
每个递归实现都应该包含两部分:
基本案例 - 表示结果已知的简单 edge-case(或一组 edge-case)提前。对于此问题,有两个 edge-case:给定字符串的长度为
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.
将这个 brute-force 版本变成 DP-based 解决方案动态规划
正如我之前所说,HashMap
将是存储中间结果的完美方式,因为允许将 count(组合数)与一个特定的字符串,然后几乎立即检索这个数字 (in O(1) time).
它可能看起来像:
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