面试题30:包含min函数的栈
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。
- 算法:
- 两个栈:
- 主栈照常出栈入栈
- 最小栈每次入栈小于等于栈顶的元素,出栈照常
class MinStack {
Stack<Integer> main;
Stack<Integer> min;
public MinStack() {
main = new Stack<Integer>();
min = new Stack<Integer>();
}
public void push(int x) {
main.push(x);
if (min.isEmpty() || x < min.peek()) {
min.push(x);
} else {
min.push(min.peek());
}
}
public void pop() {
if (!main.empty()) {
main.pop();
}
if (!min.empty()) {
min.pop();
}
}
public int top() {
if (!main.empty()) {
return main.peek();
} else {
return -1;
}
}
public int getMin() {
if (!min.empty()) {
return min.peek();
} else {
return -1;
}
}
} - 算法:
- 只用一个栈
- 入栈元素小于当前min就入栈两次同时更新min(当前min和x)
- 出栈元素等于当前min就出栈两次同时更新min
class MinStack {
int min;
Stack<Integer> stack;
public MinStack() {
min = Integer.MAX_VALUE;
stack = new Stack<Integer>();
}
public void push(int x) {
// first push the last minimum value
// when the current minimum value changes after pushing the new value x
if(x <= min){
stack.push(min);
min=x;
}
stack.push(x);
}
public void pop() {
// if pop operation could result in the changing of the current minimum value,
// pop twice and change the current minimum value to the last minimum value.
if(stack.pop() == min)
min = stack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
} 面试题31:栈的压入、弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1、2、3、4、5是某栈的压栈序列,序列4、5、3、2、1是该压栈序列对应的一个弹出序列,但4、3、5、1、2就不可能是该压栈序列的弹出序列。
- 算法:push序列不断压栈直到遇到pop序列的出栈元素
// 遍历出栈序列
public boolean validateStackSequences(int[] pushed, int[] popped) {
if (pushed == null || popped == null) {
throw new RuntimeException("Null");
}
if (pushed.length != popped.length) {
return false;
}
if (pushed.length == 0 && popped.length == 0) {
return true;
}
int pushIndex = 0;
int popIndex = 0;
Stack<Integer> stack = new Stack<Integer>();
while (popIndex < popped.length) {
while ((stack.empty() || stack.peek() != popped[popIndex]) && pushIndex < pushed.length) {
stack.push(pushed[pushIndex++]);
}
if (stack.peek() == popped[popIndex]) {
stack.pop();
popIndex++;
} else {
return false;
}
}
return true;
}
// 遍历出栈序列
public boolean validateStackSequences(int[] pushed, int[] popped) {
if (pushed == null || popped == null) {
throw new RuntimeException("Null");
}
if (pushed.length != popped.length) {
return false;
}
if (pushed.length == 0 && popped.length == 0) {
return true;
}
Stack<Integer> stack = new Stack<Integer>();
int index = 0;
for (int p : pushed) {
stack.push(p);
while (!stack.isEmpty() && stack.peek() == popped[index]){
stack.pop();
index++;
}
}
return stack.isEmpty();
} 面试题32:从上到下打印二叉树
题目一:不分行从上到下打印二叉树
题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
public int[] levelOrder(TreeNode root) {
if (root == null) {
return new int[0];
}
List<Integer> result = new ArrayList<Integer>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode temp = queue.poll();
result.add(temp.val);
if (temp.left != null) {
queue.offer(temp.left);
}
if (temp.right != null) {
queue.offer(temp.right);
}
}
int[] array = new int[result.size()];
int i = 0;
for (Integer x : result) {
array[i++] = x;
}
return array;
} 题目二:分行从上到下打印二叉树
题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。
- 算法:分层收集打印
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root == null)
return res;
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelNum = queue.size();
List<Integer> levelList = new ArrayList<Integer>();
for (int i = 0; i < levelNum; i++) {
TreeNode temp = queue.peek();
if (temp.left != null) {
queue.offer(temp.left);
}
if (temp.right != null) {
queue.offer(temp.right);
}
levelList.add(queue.poll().val);
}
res.add(levelList);
}
return res;
} - 算法:分层计数打印
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (root == null) {
return res;
}
int nextLevel = 0;
int currLevel = 1;
ArrayList<Integer> level = new ArrayList<Integer>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode temp = queue.poll();
level.add(temp.val);
currLevel--;
if (temp.left != null) {
queue.offer(temp.left);
nextLevel++;
}
if (temp.right != null) {
queue.offer(temp.right);
nextLevel++;
}
if (currLevel == 0) {
res.add(level);
level = new ArrayList<Integer>();
currLevel = nextLevel;
nextLevel = 0;
}
}
return res;
} 题目三:之字形打印二叉树
题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
- 算法:
- 两个栈:从1开始计算层数
- 栈1收集奇数层先右节点后左子节点,栈2收集偶数层先左子节点后右子节点
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (root == null) {
return res;
}
int curr = 0;
int next = 1;
ArrayList<Integer> levelList = new ArrayList<Integer>();
Stack<TreeNode> stack1 = new Stack<TreeNode>();
Stack<TreeNode> stack2 = new Stack<TreeNode>();
stack1.push(root);
while (!stack1.empty() || !stack2.empty()) {
if (curr == 0) {
TreeNode temp = stack1.pop();
levelList.add(temp.val);
if (temp.left != null) {
stack2.push(temp.left);
}
if (temp.right != null) {
stack2.push(temp.right);
}
if (stack1.empty()) {
res.add(levelList);
levelList = new ArrayList<>();
curr = 1 - curr;
next = 1 - next;
}
} else {
TreeNode temp = stack2.pop();
levelList.add(temp.val);
if (temp.right != null) {
stack1.push(temp.right);
}
if (temp.left != null) {
stack1.push(temp.left);
}
if (stack2.empty()) {
res.add(levelList);
levelList = new ArrayList<>();
curr = 1 - curr;
next = 1 - next;
}
}
}
return res;
} - 算法:
- 双端队列:
- 奇数层和偶数层按规律添加和删除
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root == null) {
return res;
}
Deque<TreeNode> deque = new LinkedList<>();
deque.add(root);
while(!deque.isEmpty()) {
// 奇数层:队尾删除,队首先左后右添加,使得下一个偶数层从右向左打印
List<Integer> levelList = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
TreeNode node = deque.removeLast();
levelList.add(node.val);
if(node.left != null) deque.addFirst(node.left);
if(node.right != null) deque.addFirst(node.right);
}
res.add(levelList);
if (deque.isEmpty()) break;
// 偶数层:队首删除,队尾先右后左添加,使得下一个奇数层从左向右打印
levelList = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
TreeNode node = deque.removeFirst();
levelList.add(node.val);
if(node.right != null) deque.addLast(node.right);
if(node.left != null) deque.addLast(node.left);
}
res.add(levelList);
}
return res;
} 面试题33:二叉搜索树的后序遍历序列
题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。
- 算法:
- 利用最后一个数组元素是树的根节点来分割这个二叉搜索树,递归处理左右子树
public boolean verifyPostorder(int[] postorder) {
if (postorder == null) {
throw new RuntimeException("Array is null");
}
if (postorder.length <= 1) {
return true;
}
return verifyPostorderRecursion(postorder, 0, postorder.length - 1);
}
private boolean verifyPostorderRecursion(int[] postorder, int start, int end) {
if (start == end) {
return true;
}
int root = postorder[end];
int i = start;
for (; i < end; i++) {
if (postorder[i] > root) {
break;
}
}
int j = i;
for (; j < end; j++) {
if (postorder[j] < root) {
return false;
}
}
boolean left = true;
boolean right = true;
if (i > start) {
left = verifyPostorderRecursion(postorder, start, i - 1);
}
if (i < end) {
right = verifyPostorderRecursion(postorder, i, end - 1);
}
return left && right;
} 面试题34:二叉树中和为某一值的路径
题目:输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> result = new LinkedList<List<Integer>>();
if (root == null) {
return result;
}
LinkedList<Integer> path = new LinkedList<Integer>();
findPath(root, result, path, sum, 0);
return result;
}
private void findPath(TreeNode node, List<List<Integer>> result, LinkedList<Integer> path,
int pathSum, int currentSum) {
currentSum += node.val;
path.offer(node.val);
if (node.left == null && node.right == null && currentSum == pathSum) {
LinkedList<Integer> temp = new LinkedList<Integer>();
temp.addAll(path);
result.add(temp);
}
if (node.left != null) {
findPath(node.left, result, path, pathSum, currentSum);
}
if (node.right != null) {
findPath(node.right, result, path, pathSum, currentSum);
}
path.pollLast();
} 

京公网安备 11010502036488号