📜  查找数字数组的所有可能解释

📅  最后修改于: 2021-04-17 13:32:27             🧑  作者: Mango

考虑一个将字母转换为整数的编码系统,其中“ a”表示为1,“ b”表示为2,..“ z”表示为26。给定一个数字数组(1到9)作为输入,编写一个输出所有数字的函数输入数组的有效解释。

例子

Input: {1, 1}
Output: ("aa", 'k") 
[2 interpretations: aa(1, 1), k(11)]

Input: {1, 2, 1}
Output: ("aba", "au", "la") 
[3 interpretations: aba(1,2,1), au(1,21), la(12,1)]

Input: {9, 1, 8}
Output: {"iah", "ir"} 
[2 interpretations: iah(9,1,8), ir(9,18)]

请注意,我们无法更改数组的顺序。这意味着{1,2,1}不能成为{2,1,1}
乍一看,它看起来像是排列/组合的问题。但是仔细观察,您会发现这是一个有趣的树问题。
这里的想法是字符串最多可以采用两条路径:
1.处理一位数
2.处理两位数
这意味着我们可以在这里使用二叉树。用一位数字处理将是左子代,而两位数字将是右子代。如果两位数的值大于26,则我们的右子元素将为null,因为我们没有大于26的字母。

我们来看一个示例.Array a = {1,2,1}。下图显示了我们的树如何生长。

“” {1,2,1}            Codes used in tree
                       /             \               "a" --> 1
                      /               \              "b" --> 2 
                  "a"{2,1}            "l"{1}         "l" --> 12
                 /        \          /     \
                /          \        /       \
            "ab"{1}        "au"    "la"      null
             /    \
            /      \
         "aba"      null

大括号{}包含仍在等待处理的数组。请注意,对于每个级别,我们的数组大小都会减小。如果您仔细观察,不难发现树高始终为n(数组大小)
如何打印所有字符串(解释)?输出字符串是树的叶子节点。例如,对于{1,2,1},输出为{aba au la}。
我们可以得出结论,主要有两个步骤可以打印给定整数数组的所有解释。

步骤1:使用叶节点中的所有可能解释创建一个二叉树。

步骤2:从步骤1中创建的二叉树中打印所有叶节点。

以下是上述算法的Java实现。

// A Java program to print all interpretations of an integer array
import java.util.Arrays;
  
// A Binary Tree node
class Node {
  
    String dataString;
    Node left;
    Node right;
  
    Node(String dataString) {
        this.dataString = dataString;
        //Be default left and right child are null. 
    }
  
    public String getDataString() {
        return dataString;
    }
}
  
public class arrayToAllInterpretations {
  
    // Method to create a binary tree which stores all interpretations 
    // of arr[] in lead nodes
    public static Node createTree(int data, String pString, int[] arr) {
  
        // Invalid input as alphabets maps from 1 to 26
        if (data > 26) 
            return null;
  
        // Parent String + String for this node
        String dataToStr = pString + alphabet[data];
  
        Node root = new Node(dataToStr);
  
        // if arr.length is 0 means we are done
        if (arr.length != 0) {
            data = arr[0];
  
            // new array will be from index 1 to end as we are consuming 
            // first index with this node
            int newArr[] = Arrays.copyOfRange(arr, 1, arr.length);
  
            // left child
            root.left = createTree(data, dataToStr, newArr);
  
            // right child will be null if size of array is 0 or 1
            if (arr.length > 1) {
  
                data = arr[0] * 10 + arr[1];
  
                // new array will be from index 2 to end as we 
                // are consuming first two index with this node
                newArr = Arrays.copyOfRange(arr, 2, arr.length);
  
                root.right = createTree(data, dataToStr, newArr);
            }
        }
        return root;
    }
  
    // To print out leaf nodes
    public static void printleaf(Node root) {
        if (root == null) 
            return;
  
        if (root.left == null && root.right == null) 
            System.out.print(root.getDataString() + "  ");
          
        printleaf(root.left);
        printleaf(root.right);
    }
  
    // The main function that prints all interpretations of array
    static void printAllInterpretations(int[] arr) {
  
        // Step 1: Create Tree
        Node root = createTree(0, "", arr);
  
        // Step 2: Print Leaf nodes
        printleaf(root);
  
        System.out.println();  // Print new line
    }
  
    // For simplicity I am taking it as string array. Char Array will save space
    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"};
  
    // Driver method to test above methods 
    public static void main(String args[]) {
  
        // aacd(1,1,3,4) amd(1,13,4) kcd(11,3,4)
        // Note : 1,1,34 is not valid as we don't have values corresponding
        // to 34 in alphabet
        int[] arr = {1, 1, 3, 4};
        printAllInterpretations(arr);
  
        // aaa(1,1,1) ak(1,11) ka(11,1)
        int[] arr2 = {1, 1, 1};
        printAllInterpretations(arr2);
  
        // bf(2,6) z(26)
        int[] arr3 = {2, 6};
        printAllInterpretations(arr3);
  
        // ab(1,2), l(12)  
        int[] arr4 = {1, 2};
        printAllInterpretations(arr4);
  
        // a(1,0} j(10)  
        int[] arr5 = {1, 0};
        printAllInterpretations(arr5);
  
        // "" empty string output as array is empty
        int[] arr6 = {};
        printAllInterpretations(arr6);
  
        // abba abu ava lba lu
        int[] arr7 = {1, 2, 2, 1};
        printAllInterpretations(arr7);
    }
}

输出:

aacd  amd  kcd  
aaa  ak  ka  
bf  z  
ab  l  
a  j  
  
abba  abu  ava  lba  lu  

锻炼:
1.该解决方案的时间复杂度是多少? [提示:树的大小+查找叶节点]
2.我们可以在创建树时存储叶节点,这样就不需要再次运行循环来获取叶节点了吗?
3.我们如何减少多余的空间?