平面列表
题目描述
给定一个列表,该列表中的每个要素要么是个列表,要么是整数。将其变成一个只包含整数的简单列表。
如果给定的列表中的要素本身也是一个列表,那么它也可以包含列表。
您在真实的面试中是否遇到过这个题?
样例
给定 [1,2,[1,2]],返回 [1,2,1,2]。
给定 [4,[3,[2,[1]]]],返回 [4,3,2,1]。
挑战
请用非递归方法尝试解答这道题。
- 这题的递归解法很简单, 不贴了. 主要写写挑战内容, 用非递归方法解:
用非递归方法解主要是用栈模拟入栈出栈的过程. 根据处理本节点数据的位置可以将此类问题转换为二叉树的前序, 中序, 后序遍历
由于三种方法类型的遍历问题难以记忆, 所以需要依赖一定的规则才能写对
- 处理所有数据,都在出栈时进行处理
- 根节点首先入栈再开启循环
- 使用辅助数据结构管理出栈
二叉树非递归方式的遍历方法与本题的对应
由于本题很特殊,本题的list节点可以认为对本节点的操作为空, 所以本题用三种方法解都可以
public static void preOrderUnRecur(Node head) {
System.out.print("pre-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while (!stack.isEmpty()) {
head = stack.pop();
System.out.print(head.value + " ");
if (head.right != null) {
stack.push(head.right);
}
if (head.left != null) {
stack.push(head.left);
}
}
}
System.out.println();
}
可以看到, 先序的处理最简单
- 从栈中弹出一个, 处理
- 将右子树入栈
- 将左子树入栈
- 循环到栈空
先压右子树, 就可以保证栈顶的是左子树.
用这种思路来处理本题可以写出如下AC代码
public class Solution {
// @param nestedList a list of NestedInteger
// @return a list of integer
public List<Integer> flatten(List<NestedInteger> nestedList) {
// Write your code here
List<Integer> re = new ArrayList<>();
for (int i = 0; i < nestedList.size(); ++i) {
flatternMyself(nestedList.get(i),re);
}
return re;
}
void flatternMyself(NestedInteger integer,List<Integer> container) {
Stack<NestedInteger> nesStack = new Stack<>();
nesStack.push(integer); //根节点入栈
Stack<NestedInteger> helpStack = new Stack<>();
while (!nesStack.empty()) {
//出栈一个节点进行处理
NestedInteger tempInt = nesStack.pop();
if (tempInt != null) {
if (tempInt.isInteger()) {
container.add(tempInt.getInteger());
} else {
// container.add(-1);
}
if (tempInt.isInteger()) {
nesStack.push(null);
} else {
List<NestedInteger> tempList = tempInt.getList();
for (int i = tempList.size() - 1; i >= 0; i--) {
nesStack.add(tempList.get(i));
}
}
}
}
}
}
public static void inOrderUnRecur(Node head) {
System.out.print("in-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
中序遍历的思路主要是, 先一路压左, 对应递归写法一上来直接递归左子树. 压到空, 对应叶子节点, 然后出栈处理本节点, 再压右.
如果不使用上述写法, 使用两层while写法, 一定要把空指针入栈, 不循环压左子树的时候, 无法知道当前节点是第一次遇到, 还是左子树已经压过, 从左子树回来之后遇到的.
如下 :
class Solution {
public:
vector<int> inorderTraversal(TreeNode * root) {
// write your code here
vector<int> ans;
if (root == nullptr) {
return ans;
}
stack<TreeNode *> nes;
nes.push(root);
while (!nes.empty()) {
while (nes.top() != nullptr) {
nes.push(nes.top()->left);
}
nes.pop();
// 如果头节点没有右子树, 可能出现栈中只有一个null的情况, 上面pop以后, 这里可能就会empty, 所以要判断一下
// 但是这里不用判断栈顶, 因为不可能出现连续有两个null的情况
// 因为遇到一个空以后, 就不会push, 然后就将空pop了
if (!nes.empty()) {
TreeNode *pNode = nes.top();
nes.pop();
ans.push_back(pNode->val);
nes.push(pNode->right);
}
}
return ans;
}
};
这种写法的处理对应本题需要在class中增加一个mark以便在压入右子树的时候,找到当前list的下一个应该被压的节点. OJ太傻, 所以本题这种写法暂时不做, 意会就行
public static void posOrderUnRecur1(Node head) {
System.out.print("pos-order: ");
if (head != null) {
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
s1.push(head);
while (!s1.isEmpty()) {
head = s1.pop();
s2.push(head);
if (head.left != null) {
s1.push(head.left);
}
if (head.right != null) {
s1.push(head.right);
}
}
while (!s2.isEmpty()) {
System.out.print(s2.pop().value + " ");
}
}
System.out.println();
}
后序第一种写法, 用一个辅助栈, 将先序的顺序调整为后序, 关键还是在出栈时处理数据
可写出如下AC代码
public class Solution {
// @param nestedList a list of NestedInteger
// @return a list of integer
public List<Integer> flatten(List<NestedInteger> nestedList) {
// Write your code here
List<Integer> re = new ArrayList<>();
for (int i = 0; i < nestedList.size(); ++i) {
flatternMyself(nestedList.get(i),re);
}
return re;
}
void flatternMyself(NestedInteger integer,List<Integer> container) {
Stack<NestedInteger> nesStack = new Stack<>();
nesStack.push(integer); //根节点入栈
Stack<Integer> helpStack = new Stack<>();
while (!nesStack.empty()) {
//出栈一个节点进行处理
NestedInteger tempInt = nesStack.pop();
if (tempInt != null) {
if (tempInt.isInteger()) {
helpStack.push(tempInt.getInteger());
} else {
// container.add(-1);
}
if (tempInt.isInteger()) {
nesStack.push(null);
} else {
List<NestedInteger> tempList = tempInt.getList();
for (int i = 0; i <tempList.size(); i++) {
nesStack.push(tempList.get(i));
}
}
}
}
while (!helpStack.empty()) {
container.add(helpStack.pop());
}
}
}
public static void posOrderUnRecur2(Node h) {
System.out.print("pos-order: ");
if (h != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(h);
Node c = null;
while (!stack.isEmpty()) {
c = stack.peek();
if (c.left != null && h != c.left && h != c.right) {
stack.push(c.left);
} else if (c.right != null && h != c.right) {
stack.push(c.right);
} else {
System.out.print(stack.pop().value + " ");
h = c;
}
}
}
System.out.println();
}
后序第二种