原题连接
- 第一题:顺时针打印矩阵
- 第二题:包含min函数的栈
- 第三题:栈的压入、弹出序列
- 第四题:从上往下打印二叉树
- 第五题:二叉树的后序遍历序列
- 第六题:二叉树中和为某一值的路径
1.顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
思路
就是循环打印,判断好开始条件和结束条件
public ArrayList<Integer> printMatrix(int[][] matrix) {
if (matrix == null) {
return null;
}
ArrayList<Integer> arrayList = new ArrayList<>();
int rows = matrix.length;
int columns = matrix[0].length;
int left = 0; int top = 0; int right = columns - 1; int bottom = rows -1;
while (left <= right && top <= bottom) {
//从左往右打印
for (int i = left; i <= right; i++) {
arrayList.add(matrix[top][i]);
}
//从上往下打印
for (int i = top + 1; i <= bottom; i++) {
arrayList.add(matrix[i][right]);
}
//从右往左打印
if (top != bottom) {
for (int i = right - 1; i >= left; i--) {
arrayList.add(matrix[bottom][i]);
}
}
//从下往上打印
if (left != right) {
for (int i = bottom - 1; i > top; i--) {
arrayList.add(matrix[i][left]);
}
}
left++;top++;right--; bottom--;
}
return arrayList;
}
2.包含min函数的栈
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路
时间复杂度为O(1),也就是说每次弹出的最小元素都是在栈顶,显然需要一个辅助栈来存储每一次进栈时的最小值,这样当弹出栈的时候,辅助栈的栈顶元素就是当前的最小值
public class Solution {
Stack<Integer> stack = new Stack<Integer>();
Stack<Integer> minStack = new Stack<Integer>();
public void push(int node) {
stack.push(node);
minStack.add(minStack.isEmpty() || minStack.peek() > node ? node:minStack.peek());
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return minStack.peek();
}
}
3.栈的压入、弹出序列
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路
栈是后进先出的,可以模拟序列元素压栈弹出过程:
1.根据压入顺序,进栈
2.判断当前栈顶元素是否与弹出序列的元素相等,相等就弹出,不相等就继续进栈重复,知道遇到不相等的
3.当所有元素都入栈之后,判断栈是否为空,为空就是合法的出栈序列
public boolean IsPopOrder(int [] pushA,int [] popA) {
if (pushA.length == 0 || popA.length == 0){
return false;
}
Stack<Integer> stack = new Stack<>();
for (int i = 0,j=0; i < popA.length; i++) {
stack.push(pushA[i]);
while (j < popA.length && stack.peek() == popA[j]) {
stack.pop();
j++;
}
}
return stack.isEmpty();
}
4.从上往下打印二叉树
题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
思路
本质上来说就是广度优先遍历二叉树,采用队列来实现
遍历的规律是:每打印一个节点,判断这个节点是否有子节点,如果有,就把该节点的子节点放入队列的末尾,然后从队列的头部依次取出节点,重复打印,直到所有节点都打印完毕
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
ArrayList<Integer> list = new ArrayList<>();
if (root == null)
return list;
Queue<TreeNode> queue =new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode node=queue.poll();
list.add(node.val);
if (node.left!=null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
return list;
}
5. 二叉搜索树的后序遍历序列
题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路
二叉搜索树的特点是左子树节点的值,都小于根节点,右子树节点的值都大于根节点,后序遍历的特点就是LRD,也就是最后一个节点是根节点的值。
可以递归判断序列是否满足这两个特性
public boolean VerifySquenceOfBST(int [] sequence) {
if (sequence == null || sequence.length == 0)
return false;
int root = sequence[sequence.length - 1];
int i = 0;
for (; i < sequence.length - 1; ++i) {
if (sequence[i] > root)
break;
}
int j = i;
for (; j < sequence.length - 1; ++j) {
if (sequence[j] < root)
return false;
}
boolean left = true;
boolean right = true;
if (i > 0)
left = VerifySquenceOfBST(Arrays.copyOfRange(sequence, 0, i));
if (i < sequence.length - 1)
right = VerifySquenceOfBST(Arrays.copyOfRange(sequence, i, sequence.length - 1));
return (left && right);
}
上面是递归算法,那么如果是非递归呢,利用右子树的所有节点都大于左子树节点这条特性
public boolean VerifySquenceOfBST2(int[] sequence) {
if (sequence.length == 0)
return false;
int last = sequence.length - 1;
for (int i = 0; last != 0; last--, i = 0) {
for (; sequence[i] < sequence[last]; ++i);
for (; sequence[i] > sequence[last]; ++i);
if (i != last)
return false;
}
return true;
}
6.二叉树中和为某一值的路径
题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
思路
树有三种遍历,而这个题目要求是从根节点开始,也就是前序遍历,用前序遍历访问某一节点时,我们把该节点添加到路径上,并且累计该节点的值,如果该节点是叶子节点,并且路径和等于输入的整数,就打印出来,如果不是叶子节点,则继续访问它的子节点,当访问结束,返回父节点,并且将该节点删除并且减去该节点的值。其实这个路径就是一个栈结构,后进先出
public class Solution {
ArrayList<ArrayList<Integer>> resultList = new ArrayList<>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if (root == null)
return resultList;
Stack<Integer> path = new Stack<>();
FindPath(root, target, path, 0);
return resultList;
}
private void FindPath(TreeNode root, int target, Stack<Integer> path, int currentSum) {
currentSum += root.val;
path.push(root.val);
boolean isLeaf = root.left == null && root.right == null;
//如果当前是叶子节点并且路径是期望值,就打印
if (currentSum == target && isLeaf) {
//放入路径集合
ArrayList<Integer> pathList = new ArrayList<>();
for (int i = 0; i < path.size(); i++) {
pathList.add(path.get(i));
}
resultList.add(pathList);
}
//如果不是叶子节点
if (currentSum < target && root.left!=null){
FindPath(root.left,target,path,currentSum);
}
if (currentSum < target && root.right!=null){
FindPath(root.right,target,path,currentSum);
}
path.pop();
}
}