算法将数字转换为String

时间:2017-03-13 16:23:55

标签: java algorithm

我需要设计一种算法,其中每个数字都被编码为字母表,例如:

  

1 = A,2 = B,3 = C ... 26 = Z

给定一组数字,我必须将它们翻译成字符串组合。例如:

  

123可以翻译成 - ABC(123),AW(123)和LC(12 3)

编写算法以查找数字组合 - 123123123。

现在这就是我写的内容,因为有多个“for”循环,我发现它效率低下。有没有更好的方法可以重写这个算法?

onEnter={requireAuth()}

}

  

对于'123' - [ABC,AW,LC]

     

对于'123123123' - [LCABCABC,AWABCABC,ABCAWABC,ABCLCABC,ABCABCLC,ABCABCABC,ABCABCAW]

4 个答案:

答案 0 :(得分:7)

这个问题迫切需要递归。这是一个快速而肮脏的实现,它接受输入"数字"以字符串形式使用substring()来消费数字。如果您愿意,可以调整它以使用数值方法从整数中获取第一个(或前两个)十进制数字。

如果您选择直接从int开始工作,那么从最开始(使用最低有效数字)开始可能比开始时更容易 - lastDigit = number % 10; otherDigits = number / 10

public List<String> encodings(String number) {
    List<String> out = new ArrayList<>();
    addEncodings("", number, out);
    return out;
}

private void addEncodings(String prefix, String number, List<String> out) {
    if (number.length() == 0) {
        out.add(prefix);
    } else {
        addParsingNDigits(1, prefix, number, out);
        addParsingNDigits(2, prefix, number, out);
    }

}

private void addParsingNDigits(int digits, String prefix, String number, List<String> out) {
    if (number.length() >= digits) {
        char encodedChar = parseChars(number, digits);
        if (encodedChar >= 'A' && encodedChar <= 'Z') {
            addEncodings(prefix + encodedChar, number.substring(digits), out);
        }
    }
}

private char parseChars(String number, int length) {
    int intVal = Integer.parseInt(number.substring(0, length));
    return (char) ('A' + intVal - 1);
}

我认为你的解决方案不会找到所有可能的编码 - 我认为你需要某种堆栈来解决它。由于递归方法调用,上面的解决方案隐式使用执行堆栈。另一种解决方案可以明确地放置代表&#34; todo&#34;计算到堆中的堆栈数据结构:

private static class StackItem {

    public StackItem(String prefix, String number) {
        this.prefix = prefix;
        this.number = number;
    }

    public String prefix;
    public String number;
}

public List<String> encodings(String number) {
    List<String> results = new ArrayList<>();
    Stack<StackItem> stack = new Stack<>();
    stack.push(new StackItem("", number));
    while (!stack.isEmpty()) {
        StackItem current = stack.pop();
        if (current.number.equals("")) {
            results.add(current.prefix);
        } else {
            addToStackTakingNChars(2, current, stack);
            addToStackTakingNChars(1, current, stack);
        }
    }
    return results;
}

private void addToStackTakingNChars(int n, StackItem current, Stack<StackItem> stack) {
    if (current.number.length() >= n) {
        char c = parseChars(current.number, n);
        if (c >= 'A' && c <= 'Z') {
            stack.push(new StackItem(current.prefix + c, current.number.substring(n)));
        }
    }
}

虽然&#34; println调试&#34;通常是一个坏习惯,用一些println()来运行这些例子可能是一个很好的学习练习,以观察它是如何工作的。

答案 1 :(得分:4)

我认为您可以在中间(递归地)拆分字符串,搜索两个子字符串中的所有组合并构建交叉产品。为了不错过任何组合,我们还必须通过在中间分割偏移量为1来构建两个子串的交叉积。像这样:

private static int[] values;

public static final Set<String> solve(String s) {
    values = new int[s.length()];
    for (int i = 0; i < values.length; i++)
        values[i] = s.charAt(i) - '0';
    return solve(0, values.length);
}

private static final Set<String> solve(int start, int len) {
    Set<String> ret = new HashSet<>();
    if (len == 1) {
        ret.add("" + ((char)(values[start] - 1 + 'A')));
    } else if (len == 2) {
        ret.add("" + ((char)(values[start] - 1 + 'A')) + 
                     ((char)(values[start + 1] - 1 + 'A')));
        int n = values[start] * 10 + values[start + 1];
        if (n <= 26)
            ret.add("" + ((char)(n - 1 + 'A')));
    } else {
        int next = start + len / 2;
        cross(solve(start, next - start), solve(next, start + len - next), ret);
        cross(solve(start, next - start + 1), solve(next + 1, start + len - next - 1), ret);
    }
    return ret;
}

private static final void cross(Set<String> a, Set<String> b, Set<String> target) {
    for (Iterator<String> itr = a.iterator(); itr.hasNext();) {
        String s = itr.next();
        for (Iterator<String> itr2 = b.iterator(); itr2.hasNext();) {
            target.add(s + itr2.next());
        }
    }
}

顺便说一下。 “123123123”的解决方案是以下27个字符串:LCABCAW,LCABCLC,ABCLCABC,ABCLCAW,ABCAWLC,AWLCABC,ABCAWAW,ABCAWABC,ABCLCLC,ABCABCABC,LCAWLC,LCAWAW,AWABCLC,LCAWABC,AWABCAW,LCLCAW,AWABCABC,LCLCLC,LCLCABC, LCABCABC,AWAWLC,AWAWABC,AWAWAW,ABCABCLC,ABCABCAW,AWLCAW,AWLCLC。

答案 2 :(得分:2)

为什么不直接使用ascii值?

您需要做的就是将号码转换为String Integer.toString(num),然后通过for-loop的{​​{1}}运行.length()并将String.charAt(i)转换回String,然后将16添加到int。然后你只需要转换为char。像这样:

int a = 123;
String str = Integer.toString(a);
char[] chars = new char[str.length()];
for(int i=0,n=str.length();i<n;i++){
     chars[i] = (char)(str.charAt(i)+16);
}
String message = String.valueOf(chars);

答案 3 :(得分:2)

使用标准DP算法可以在o(fib(n + 2))时间内完成此问题。 我们有n个子问题和按钮,我们可以在o(fib(i))时间内解决每个问题。 对该系列求和得到fib(n + 2)。

如果仔细考虑这个问题,你会发现它是一个fibunacci系列。 我拿了一个标准代码,然后根据我们的条件稍微改了一下。

空间显然与所有解决方案的大小有关(fib(n))。

考虑以下代码:

Map<Integer, String> mapping = new HashMap<Integer, String>();

List<String > iterative_fib_sequence(int input) {
    int length = Math.floor(Math.log10(Math.abs(input))) + 1;
    if (length <= 1) 
    {
        if (length==0)
        {
            return "";
        }
        else//input is a-j
        {
            return mapping.get(input);
        }
    }
    List<String> b = new List<String>();
    List<String> a = new List<String>(mapping.get(input.substring(0,0));
    List<String> c = new List<String>();

    for (int i = 1; i < length; ++i) 
    {
        int dig2Prefix = input.substring(i-1, i); //Get a letter with 2 digit (k-z)
        if (mapping.contains(dig2Prefix))
        {
            String word2Prefix = mapping.get(dig2Prefix);           
            foreach (String s in b)
            {
                c.Add(s.append(word2Prefix));
            }
        }

        int dig1Prefix = input.substring(i, i); //Get a letter with 1 digit (a-j)
        String word1Prefix = mapping.get(dig1Prefix);           
        foreach (String s in a)
        {
            c.Add(s.append(word1Prefix));
        }

        b = a;
        a = c;
        c = new List<String>();
    }
    return a;
}