二叉树实战(五) - 折纸问题
【需求】
请把纸条竖着放在桌⼦上,然后从纸条的下边向上⽅对折,压出折痕后再展 开。此时有1条折痕,突起的⽅向指向纸条的背⾯,这条折痕叫做“下”折痕 ;突起的⽅向指向纸条正⾯的折痕叫做“上”折痕。如果每次都从下边向上⽅ 对折,对折N次。
请从上到下计算出所有折痕的⽅向。
给定折的次数n,请返回从上到下的折痕的数组,若为下折痕则对应元素为"down",若为上折痕则为"up".
例如:
N = 1时,打印:[Down]
N = 2时,打印:[Down、Down、Up]
【分析】
我们把对折后的纸张翻过来,让粉色朝下,这时第一次对折产生的折痕我们可以看做是根节点,那第二次对折产生的下折痕是该结点的左子节点,第二次对折产生的上折痕是该结点的右子节点,这样我们就可以通过树的数据结构来描述对折后产生的折痕。
这棵树有这样的特点:
- 根结点为下折痕
- 每个结点的左子节点为下折痕
- 每个结点的右子结点为上折痕
【思路】
我们可以使用 层序遍历的思想来生成折痕树、使用中序遍历来输出折痕的数组。
import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * ‘折纸问题’实现 */ public class PageFoldingTest { public static void main(String[] args) { Node<String> tree = create(2); printTree(tree); } // 通过模拟对折N次折纸,产生树 public static Node<String> create(int N) { Node<String> root = null; for (int i = 0; i < N; i++) { // 1.当前是第一次对折 if (i == 0) { root = new Node<>("down", null, null); continue; } // 2.当前不是第一次对折 // 定义一个辅助队列,通过层序遍历的思想,找到叶子结点,叶子结点添加子结点。 Queue<Node> queue = new ConcurrentLinkedQueue<>(); queue.add(root); while (!queue.isEmpty()) { // 从队列中弹出一个结点。 Node tmp = queue.poll(); // 如果有左子节点,把左子节点放入队列中 if (tmp.left != null) { queue.add(tmp.left); } // 如果有右子节点,把右子节点放入队列中 if (tmp.right != null) { queue.add(tmp.right); } // 如果同时没有左&右子节点,则证明该结点是叶子结点,只需要对此结点添加左&右子结点即可 if (tmp.left == null && tmp.right == null) { tmp.left = new Node<String>("down", null, null); tmp.right = new Node<String>("up", null, null); } } } return root; } // 打印树中每个结点到控制台 public static void printTree(Node<String> root) { midErgodic(root); } private static void midErgodic(Node x) { if (x == null) { return; } // 递归遍历x结点的左子树 if (x.left != null) { midErgodic(x.left); } // 把x结点的key放入到keys中 System.out.print(x.item + " "); // 递归遍历x结点的右子树 if (x.right != null) { midErgodic(x.right); } } // 结点类 private static class Node<T> { public T item; //存储元素 public Node left; public Node right; public Node(T item, Node left, Node right) { this.item = item; this.left = left; this.right = right; } } }

浙公网安备 33010602011771号