我有一个包含从整数到字符的映射的库。我也有一个整数形式的字符串。我正在尝试编写一个方法,在解释字符串时将返回所有可能的字符组合。例如:
给定以下库a=1, b=2, c=3, k=11
和字符串"1123"
,输出应该是包含"aabc", "kbc"
的列表。假设可以在库中找到所有给定的数字。
我目前的解决方案如下:
public static ArrayList<String> d(String s) {
ArrayList<String> s2 = new ArrayList<String>();
if (s.length() == 1) {
s2.add(""+library.get(Integer.valueOf(s)));
return s2;
}
for (int i=0; i < s.length(); i++) {
String curr = s.substring(0, i + 1);
if (library.containsKey(Integer.valueOf(curr))){
ArrayList<String> strings = d(s.substring(i + 1));
char c2 = library.get(Integer.valueOf(curr));
for (String tmp : strings){
s2.add(c2 + tmp);
}
}
}
return s2;
}
有没有更优化的方法来解决这个问题?还有什么是我的解决方案的复杂性?我的假设是O(N ^ 3)时间。
答案 0 :(得分:2)
您的问题映射到以下语法:
S -> SA | SB | SC | SK | ε
A -> 1
B -> 2
C -> 3
K -> 11
这是一个无上下文的语法,这意味着任何体面的解析器(CYK,Earley)都会在O(n 3 )时解析它作为最坏的情况场景。任何比这更糟的事情,你肯定是在错误的轨道上。
(注意:虽然语法是无上下文的,但它定义的语言实际上是规则的。增加的复杂性来自于我们生成所有可能的解析树的要求。如果要求只是决定一个整数是否是我们语言中的有效句子,正则表达式((1)|(2)|(3)|(11))+
就够了)
答案 1 :(得分:1)
这个问题让我想起一个据称在Google采访中被问到的人:
编写一个程序来计算所有不同的方法来建造一个N高度乐高塔,其长度和宽度为1,高度由一个集合给出(即[1,2,3,4])
在我们的案例中,library
是集合,我们必须考虑一个额外的约束:一个片段必须与文本匹配。
由此,我们可以尝试动态编程解决方案来计算可能的“建筑物”的数量:
public static int nCases(String s)
{
int ncases[] = new int[s.length()];
for(int i = 0; i < s.length(); i++)
{
ncases[i] = 0;
for(Map.Entry<Integer,Character> piece: library.entrySet())
{
String mapStr = piece.getKey().toString();
int j = i+1-mapStr.length();
int prev = 1;
if(j-1>=0) prev = ncases[j-1];
if(j>= 0 && s.substring(j, i+1).equals(mapStr))
ncases[i] += prev;
}
}
if(ncases.length>0)
return ncases[ncases.length-1];
return 0;
}
此解决方案可轻松修改以跟踪每个案例,从而提供您所要求的列表:
private static class Pair<T,L>
{
public Pair(T first, L second) {
this.first = first;
this.second = second;
}
T first;
L second;
}
public static List<String> dynamicd(String s)
{
Pair<Integer,List<String>> ncases[] = new Pair[s.length()];
for(int i = 0; i < s.length(); i++)
{
ncases[i] = new Pair<Integer, List<String>>(0, new ArrayList<String>());
for(Map.Entry<Integer,Character> piece: library.entrySet())
{
String mapStr = piece.getKey().toString();
int j = i+1-mapStr.length();
Pair<Integer, List<String>> prev =
new Pair<Integer, List<String>>(1,new ArrayList<String>());
prev.second.add("");
if(j-1>=0) prev = ncases[j-1];
if(j>= 0 && s.substring(j, i+1).equals(mapStr))
{
ncases[i].first += prev.first;
for(String pcase: prev.second)
ncases[i].second.add(pcase+piece.getValue());
}
}
}
if(ncases.length>0)
return ncases[ncases.length-1].second;
return new ArrayList<>();
}
如果N = s.length()
和M = library.size()
,此方法的时间复杂度最差为O(N*M)
答案 2 :(得分:0)
这是代码(自我解释)
public static Collection<String> allPermutations(int num) {
TreeNode root = createTree(toArray(num));
Collection<String> result = new ArrayList<String>();
allLeafNodes(root, result);
return result;
}
private static Integer[] toArray(int num) {
ArrayDeque<Integer> array = new ArrayDeque<Integer>();
do{
array.push(num % 10);
num /= 10;
} while (num > 0);
return array.toArray(new Integer[0]);
}
private static TreeNode createTree(Integer[] integers) {
return doCreateTree(0, "", integers);
}
private static TreeNode doCreateTree(int index, String parentString, Integer[] integers) {
String nodeData = parentString + AlphabetMatcher.match(index);
TreeNode root = new TreeNode(nodeData);
if (integers.length != 0) {
root.left = doCreateTree(integers[0], nodeData, Arrays.copyOfRange(integers, 1, integers.length));
if (integers.length > 1) {
int newIndex = integers[0]* 10 + integers[1];
root.right = doCreateTree(newIndex, nodeData, Arrays.copyOfRange(integers, 2, integers.length));
}
}
return root;
}
private static void allLeafNodes(TreeNode root, Collection<String> result) {
if (root != null) {
if (root.right == null && root.left ==null) {
result.add(root.data);
}
allLeafNodes(root.left, result);
allLeafNodes(root.right, result);
}
}
private static class TreeNode {
private String data;
private TreeNode left;
private TreeNode right;
public TreeNode(String data) {
this.data = data;
}
}
private static class AlphabetMatcher {
private static final String[] alphabet = {"", "a", "b", "c", "d", "e",
"f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
"s", "t", "u", "v", "w", "x", "v", "z"};
public static String match(int number) {
return alphabet[number];
}
}
以下是测试用例
@Test
public void allPermutationsTest() {
Collection<String> result = StringUtil.allPermutations(1221);
org.assertj.core.api.Assertions.assertThat(result).hasSize(5).containsAll(Arrays.asList("abba","abu", "ava", "lba", "lu"));
result = StringUtil.allPermutations(10);
org.assertj.core.api.Assertions.assertThat(result).hasSize(2).containsAll(Arrays.asList("a","j"));
}