A-从上往下打印二叉树&字符串的排列

题目23:从上往下打印二叉树的每个结点,同一层的结点按照从左到右的顺序打印。二叉树定义如下:

    public class TreeNode{
        public int value;
        public TreeNode leftNode;
        public TreeNode rightNode;

        public TreeNode() {}

        public TreeNode(int value) {
            this.value = value;
        }
    }

分析:
  前序遍历:根节点排最先,然后同级先左后右;中序遍历:先左后根最后右;后序遍历:先左后右最后根。本题则不同,不妨先画一下打印二叉树的过程,如下图和表所示:
在这里插入图片描述

步骤操作队列
1打印结点8结点6、10
2打印结点6结点10、5、7
3打印结点10结点 5、7、9、11
4打印结点5结点7 、9、11
5打印结点7结点 9、11
6打印结点9结点 11
7打印结点 11

  从根结点开始分析,为了能够打印值为8的结点的两个子节点,我们应该在遍历到该结点时把6和10两个结点保存到容器中,现在容器中有两个结点,按照从左到右的要求,先取出6结点,打印6结点的值时分别把5和7结点放入容器,此时容器中三个结点:10、5、7,接着取出10结点…以此类推,直至容器中没有结点。
  从上面的推理可以发现规律:每一次打印一个结点的时候,如果该结点有子结点,则把该结点的子结点放到一个队列的末尾。接下来到队列的头部取出最早进入队列的结点,重复前面的操作,直至队列中所有的结点都被打印出来为止。
  代码如下所示:

    public static void printFromTopToBottom(TreeNode pNode) {
        if (pNode == null) return;
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(pNode);
        while (queue.size() != 0) {
            TreeNode node = queue.poll();
            System.out.print(node.value + " ");
            if (node.leftNode != null) queue.add(node.leftNode);
            if (node.rightNode != null) queue.add(node.rightNode);
        }
    }

    public static void main(String[] args) {
        TreeNode node1 = new TreeNode(8);
        TreeNode node2 = new TreeNode(6);
        TreeNode node3 = new TreeNode(10);
        TreeNode node4 = new TreeNode(5);
        TreeNode node5 = new TreeNode(7);
        TreeNode node6 = new TreeNode(9);
        TreeNode node7 = new TreeNode(11);

        node1.leftNode = node2;
        node1.rightNode = node3;
        node2.leftNode = node4;
        node2.rightNode = node5;
        node3.leftNode = node6;
        node3.rightNode = node7;

        printFromTopToBottom(node1);

        printFromTopToBottom(null);
    }

题目28:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、cab和cba。
分析:
  对于复杂的问题,可以将问题分解,将一个字符串看成两部分组成:第一部分为它的第一个字符,第二部分是后面的所有字符。首先求所有可能出现在第一个位置的所有字符,即把第一个字符和后面的所有字符交换。第二步固定第一个字符,求后面所有字符的排列,这个时候仍然把后面的字符分成两部分…
  代码如下所示:

    public static ArrayList<String> permutation(String str) {
        ArrayList<String> result = new ArrayList<>();
        if (str == null || str.length() == 0) return result;
        char[] chars = str.toCharArray();
        getResult(chars, 0, str.length() - 1, result);
        return result;
    }

    public static void getResult(char[] chars, int start, int end, ArrayList<String> result) {
        if (start == end) result.add(String.valueOf(chars));
        else {
            for (int i = start; i <= end; i++) {
                swap(chars, start, i);  //交换
                getResult(chars, start + 1, end, result);
                swap(chars, start, i);  //换回来,保证下次位置是正确的
            }
        }
    }

    public static void swap(char[] chars, int a, int b) {
        if (a != b) {  // 会出现自身交换
            char temp = chars[a];
            chars[a] = chars[b];
            chars[b] = temp;
        }
    }

    public static void main(String[] args) {
        System.out.println(permutation("abc"));
        System.out.println(permutation("a"));
        System.out.println(permutation(""));
        System.out.println(permutation(null));
    }

变型1:如果不是求字符串的所有排列,而是求字符的所有组合,应该怎么办?还是输入a、b、c,则它们的所有组合有a、b、c、ab、ac、bc、abc。
分析:
   如果输入 n 个字符,则这 n 个字符能构成长度为 1 的组合、长度为 2 的组合、….、长度为 n 的组合。在求 n 个字符的长度为 m ( 1<=m<=n) 的 组合的时候,我们把这 n 个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取 m-1个字 符;如果组合里不包含第一个字符,则下一步在剩余的 n-1 个字符里选取 m 个字符。也就是说,我们可以把求 n 个字符组成长度为 m 的组合的问题分解成两个子问题,分别求 n-1 个字符串中长度为 m-1 的组合,以及求 n-1 个字符的长度为 m 的组合。这两个子问题都可以用递归的方式解决。

    public static void combination(String str, int index, int number, StringBuilder sb) {
        if (number == -1) {
            System.out.println(sb.toString());
            return;
        }
        if (index == str.length()) return;
        sb.append(str.charAt(index));
        combination(str, index + 1, number - 1, sb);
        sb.deleteCharAt(sb.length() - 1);
        combination(str, index + 1, number, sb);

    }

    public static void combine(String str) {
        if (str == null) return;
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < str.length(); i++) {
            combination(str, 0, i, sb);
        }
    }

    public static void main(String[] args) {
        combine("abc");
        System.out.println("------------");
        combine("a");
        System.out.println("------------");
        combine(null);
        System.out.println("------------");
        combine("");
    }

变型2:输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。
在这里插入图片描述
分析:
  相当于先得到a1、a2、a3、a4、a5、a6、a7和a8这8个数字的全排列,然后判断有没有一个排列符合题目给定的条件,即a1+a2+a3+a4=a5+a6+a7+a8,a1+a3+a5+a7=a2+a4+a6+a8,a1+a2+a5+a6=a3+a4+a7+a8
变型3:在8×8的国际象棋上摆放8个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角线上。请问总共有多少种符合条件的摆法?
  8个皇后的任意两个不能处在同一行,那么肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把数组ColumnIndex的8个数字分别用0~7初始化,接下来就是对数组ColumnIndex做全排列。因为我们是用不同的数字初始化数组,所以任意两个皇后肯定不同列。我们只需判断每一个排列对应的8个皇后是不是在同一对角线上,也就是对于数组的两个下标i和j,是不是i-j=ColumnIndex[i]-ColumnIndex[j]或者j-i=ColumnIndex[i]-ColumnIndex[j]。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值