面试题19:二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:
源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public void Mirror(TreeNode root) {
if(root==null){
return;
}
//如果根节点只有一个节点,不符合要求
if(root.left==null&&root.right==null){
return;
}
//交换左右子树
TreeNode tempNode = root.left;
root.left = root.right;
root.right = tempNode;
if(root.left != null){
Mirror(root.left);
}
if(root.right != null){
Mirror(root.right);
}
}
}
面试题20:顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 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.
import java.util.ArrayList;
public class Demo20 {
public static ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> arrayList = new ArrayList<>();
int rows = matrix.length;//行数
int cols = matrix[0].length;//列数
int lowrow = 0;
int lowcol = 0;
int highrow = rows-1;
int highcol = cols-1;
while(highrow-lowrow>=0&&highcol-lowcol>=0){
for (int i = lowcol; i <=highcol; i++) {
arrayList.add(matrix[lowrow][i]);
System.out.print(matrix[lowrow][i]+" ");
}
for (int i = lowrow+1; i <=highrow-1; i++) {
arrayList.add(matrix[i][highcol]);
System.out.print(matrix[i][highcol]+" ");
}
if(highrow>lowrow){
for (int i =highcol ; i >= lowcol; i--) {
arrayList.add(matrix[highrow][i]);
System.out.print(matrix[highrow][i]+" ");
}
}
if(highcol>lowcol){
for (int i = highrow-1; i >= lowrow+1; i--) {
arrayList.add(matrix[i][lowcol]);
System.out.print(matrix[i][lowcol]+" ");
}
}
lowcol++;
lowrow++;
highcol--;
highrow--;
}
return arrayList;
}
public static void main(String[] args) {
int[][] a = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}
};
printMatrix(a);
}
}
面试题21:包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
import java.util.Stack;
public class Solution {
Stack<Integer> data_stack = new Stack<>();//数据栈
Stack<Integer> min_stack = new Stack<>();//辅助栈 存放最小值
public void push(int node) {
data_stack.push(node);//压入栈
if(min_stack.size()==0||node<min_stack.peek()){//查看是否比栈顶元素小
min_stack.push(node);
}
else{
min_stack.push(min_stack.peek());
}
}
public void pop() {
if(data_stack.size()>0&&min_stack.size()>0){
min_stack.pop();
data_stack.pop();
}
else {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int top() {
if(data_stack.size()==0&&min_stack.size()==0){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
return data_stack.peek();
}
public int min() {
if(data_stack.size()==0&&min_stack.size()==0){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
return min_stack.peek();
}
}
面试题22:栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
//假设为假
boolean isPossible = false;
//辅助栈,把输入的第一个序列中的数字依次压入辅助栈,并按照第二个序列的顺序弹出序列
Stack<Integer> stack = new Stack<>();
int indexPushA = 0;
int indexPopA = 0;
//判断两个数组是否为空,并且数组长度是否相等
if(pushA!=null&&popA!=null&&pushA.length!=0&&pushA.length==popA.length){
while(indexPopA-0 < popA.length){//判断popA数组是否遍历完了
//如果栈为空或者popA数组indexPopA所指的值与栈顶不相等,压入栈
while(stack.empty()||stack.peek()!=popA[indexPopA]){
//如果PushA已经越界了,跳出循环
if (indexPushA-0 == pushA.length) {
break;
}
//压入栈
stack.push(pushA[indexPushA]);
indexPushA++;
}
//确保栈顶元素与popA数组indexPopA所指的值相等
if (stack.peek() != popA[indexPopA]) {
break;
}
//出栈
stack.pop();
indexPopA++;
}
//栈为空,并且数组PopA已经遍历完毕
if(stack.empty()&&indexPopA-0==popA.length){
isPossible = true;
}
}
return isPossible;
}
}
面试题23:从上往下打印二叉树
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
//辅助队列
Queue<TreeNode> queue = new ArrayDeque<>();
ArrayList<Integer> arraylist = new ArrayList<>();
if(root==null){//如果为空,直接返回容器
return arraylist;
}
queue.add(root);//将根节点加入队列
while(queue.size()>0){//确保队列里面的元素个数大于0
arraylist.add((Integer) queue.peek().val);//加入ArrayList
if(queue.peek().left!=null)
queue.add(queue.peek().left);//增加左孩子到队列
if(queue.peek().right!=null)
queue.add(queue.peek().right);//增加右孩子到队列
queue.poll();//弹出
}
return arraylist;
}
}
面试题24:二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
boolean flag = false;
if(sequence==null||sequence.length==0){
return false;
}
flag = SquenceOfBST(sequence,0,sequence.length-1);
return flag;
}
public boolean SquenceOfBST(int [] sequence,int low,int high){
//二叉搜索树后序遍历,最后一个节点为根节点。
int root = sequence[high];
int i = low;
//确保左子树都比根节点小
for (; i < high-1; i++) {
if (sequence[i]>root) {
break;
}
}
//确保右子树都比根节点大
for (int j = i; j < high-1; j++) {
if (sequence[j]<root) {
return false;
}
}
//判断左子树是不是二叉搜索树
boolean leftflag = true;//先假设可以
if (i>low) {
leftflag = SquenceOfBST(sequence,low,i-1);
}
//判断右子树是不是二叉搜索树
boolean rightflag = true;
if (i<high) {
rightflag = SquenceOfBST(sequence,i,high-1);
}
return leftflag&&rightflag;
}
}
面试题25:二叉树中和为某一值的路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
//用于保存多条路径
ArrayList<ArrayList<Integer>> arrayLists = new ArrayList<>();
//双向队列
Deque<TreeNode> deque = new ArrayDeque<>();
//当前总和
int currentSum=0;
if (root==null) {
return arrayLists;
}
findPath(root, target, deque, currentSum, arrayLists);
return arrayLists;
}
/**
* @param root 二叉树
* @param target 目标总和
* @param stack 用于保存路径
* @param currentSum 当前路径总和
* @param arrayLists 用于保存多条路径
*/
public void findPath(TreeNode root,int target,Deque<TreeNode> deque,
int currentSum,ArrayList<ArrayList<Integer>> arrayLists){
currentSum += root.val;//先将根节点的值相加
deque.addFirst(root);//作为栈,压入队列第一个。
boolean isLeaf = (root.left==null) && (root.right==null);//判断是不是叶节点
//如果是叶节点,并且路径上的节点的和等于输入的值,打印这条路径
if (currentSum==target&&isLeaf) {
ArrayList<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < deque.size(); i++) {
TreeNode temp = deque.pollLast();
arrayList.add(temp.val);//作为队列,从队列最后一个,依次取出。
deque.addFirst(temp);//查看到数据之后,将节点放回队列。
}
arrayLists.add(arrayList);
}
//如果不是叶节点,则遍历他的子节点
if(root.left!=null){
findPath(root.left, target, deque, currentSum, arrayLists);
}
if (root.right!=null) {
findPath(root.right, target, deque, currentSum, arrayLists);
}
//返回父节点之前,在路径上删除当前节点,取出队列第一个。
deque.removeFirst();
}
}
面试题26:复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
/**
* 分解让复杂问题简单化
* @param pHead
*/
public RandomListNode Clone(RandomListNode pHead){
if(pHead==null)
return null;
CloneNodes(pHead);
ConnectRandomNodes(pHead);
return ReconnectNodes(pHead);
}
//原始链表的每个节点N创建对应的N`,然后将N`链接到N的后面。
public void CloneNodes(RandomListNode pHead) {
RandomListNode pNode = pHead;
while (pNode != null) {//注意:不能用pNode.next!=null作为判断条件,最后一个节点不能到达
//新增节点
RandomListNode pCloned = new RandomListNode(pNode.label);
pCloned.next = pNode.next;
pCloned.random = null;
pNode.next = pCloned;
pNode = pCloned.next;
}
}
//设置复制出来的N`的random。
public void ConnectRandomNodes(RandomListNode pHead){
RandomListNode pNode = pHead;
while (pNode != null) {
RandomListNode pCloned = pNode.next;
if(pNode.random!=null){
pCloned.random = pNode.random.next;
}
pNode = pCloned.next;
}
}
//将长链表拆分成两个链表,奇数位置的节点链接起来就是原始链表,
//偶数节点的链表链接起来就是复制出来的链表
public RandomListNode ReconnectNodes(RandomListNode pHead){
RandomListNode pNode = pHead;
RandomListNode pClonedHead = null;//头结点
RandomListNode pClonedNode = null;//移动节点
if (pNode != null) {
pClonedHead = pNode.next;
pClonedNode = pNode.next;
pNode.next = pClonedNode.next;
pNode = pNode.next;
}
while (pNode != null) {
pClonedNode.next = pNode.next;
pClonedNode = pClonedNode.next;
pNode.next = pClonedNode.next;
pNode = pNode.next;
}
return pClonedHead;
}
}
面试题27:二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
/**
* 将二叉搜索数的指向左子树的指针指向链表的前一个节点
* 将二叉搜索数的指向右子树的指针指向链表的后一个节点
* @param pRootOfTree
* @return
*/
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree==null) {
return null;
}
//我们需要返回链表头结点
TreeNode pHead0fLast = pRootOfTree;
//递归遍历二叉搜索树进行转换
ConvertNode(pRootOfTree, null);
while (pHead0fLast.left !=null) {
pHead0fLast = pHead0fLast.left;
}
return pHead0fLast;
}
/**
*
* @param pRoot 根节点
* @param pLastNodeInList 双向链表的尾节点
*/
public TreeNode ConvertNode(TreeNode pCurrentNode,TreeNode pLastNodeInList){
//递归左子树
if (pCurrentNode.left != null) {//判断左节点是否为空,如果不是遍历左节点。
pLastNodeInList = ConvertNode(pCurrentNode.left,pLastNodeInList);
}
//-------------------
//根节点的前一个节点
pCurrentNode.left = pLastNodeInList;
if (pLastNodeInList!=null) {//左子树的最大的节点后一节点指向根节点
pLastNodeInList.right = pCurrentNode;
}
//移动pLastNodeInList让其指向最后一个节点
pLastNodeInList = pCurrentNode;
//------------------
//递归右子树
if (pCurrentNode.right != null) {
return ConvertNode(pCurrentNode.right,pLastNodeInList);
}
return pLastNodeInList;
}
}
面试题28:字符串的排列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<String> Permutation(String str) {
//用于存储各种字符串排列
ArrayList<String> arrayList = new ArrayList<>();
if(str == null||str.length()==0||str.length()>9){
return arrayList;
}
char[] chs = str.toCharArray();
PermutationChar(chs,0,arrayList);
ArrayList<String> arryListNew= new ArrayList<>();
for (int i = 0; i < arrayList.size(); i++)
{
if (!arryListNew.contains(arrayList.get(i)))
{
arryListNew.add(arrayList.get(i));
}
}
Collections.sort(arryListNew);
return arryListNew;
}
public void PermutationChar(char[] chs,int index,ArrayList<String> arrayList){
if(index==chs.length){
arrayList.add(new String(chs));
}
else {
// abc 0 a //a与a交换
// abc 1 b //b与b交换
// abc 2 c //c与c交换
// abc 3 -->
// abc 2 c //c与c交换 退出函数
// abc 1 b //b与b交换 i++ i=2
// abc 2 c //b与c交换 acb
// abc 3 -->
// abc 2 c //b与c交换 还原回来 i++ i=3退出函数
// abc 0 a //a与a交换 还原回来 i++ i=1 index=0
// abc 0 a //a与b交换 bac
for (int i = index; i < chs.length; i++) {
char temp = chs[i];
chs[i] = chs[index];
chs[index] = temp;
PermutationChar(chs,index+1,arrayList);
//需要将前面交换了的字母还原
temp = chs[i];
chs[i] = chs[index];
chs[index] = temp;
}
}
}
}