您的位置:首页 > 理论基础 > 数据结构算法

Java 数据结构与算法-08——面试题解析(二叉树、二叉搜索树)

2019-05-20 19:57 441 查看

借参加过的多场Java开发面试,应聘岗位均为Java开发方向,在不断的面试中,又仔细对Java知识点进行复习和总结,也算是重新学习一下Java吧。

推荐收藏链接:Java 面试知识点解析

Java数据结构与算法知识点

1.二叉树的中序遍历


我的答案:(1ms)

public List<Integer> inorderTraversal(TreeNode root) {
List result = new ArrayList();
if (null != root) {
result.addAll(inorderTraversal(root.left));
result.add(root.val);
result.addAll(inorderTraversal(root.right));
}
return result;
}

参考答案:(0ms)

public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList<>();
traversal(root, list);
return list;
}

public void traversal(TreeNode root,List<Integer> list) {
if(root!=null){
traversal(root.left, list);
list.add(root.val);
traversal(root.right, list);
}
}
2. 验证二叉搜索树


我的答案:(53ms)

private static int INT_MIN = Integer.MIN_VALUE;
private static int INT_MAX = Integer.MAX_VALUE;

public boolean isValidBST(TreeNode root) {
// 如果节点为空则满足二叉搜索树条件
if (null == root) {
return true;
}
// 如果左孩子结点大于了根节点则返回false
if (null != root.left && findMax(root.left) > root.val) {
return false;
}
// 如果右孩子结点小于了根节点则返回false
if (null != root.right && findMin(root.right) < root.val) {
return false;
}
// 递归判断左子树和右子树,若其中有一颗不是BST树,则返回false
if (!isValidBST(root.left) || !isValidBST(root.right)) {
return false;
}
// 通过所有判断则是一颗BST树
return true;
}

/**
* 找到一颗非空树中的最大值
*
* @param root
* @return
*/
private int findMax(TreeNode root) {
int maxVal = INT_MIN;
int leftMaxVal = INT_MIN;
int rightMaxVal = INT_MIN;
if (null != root) {
// 最大值默认等于当前节点值
maxVal = root.val;
leftMaxVal = findMax(root.left);
rightMaxVal = findMax(root.right);
// maxVal等于当前maxVal与leftMaxVal中较大的一个
maxVal = maxVal > leftMaxVal ? maxVal : leftMaxVal;
// maxVal等于当前maxVal与rightMaxVal中较大的一个
maxVal = maxVal > rightMaxVal ? maxVal : rightMaxVal;
}
return maxVal;
}

/**
* 找到一颗非空树的最小值
*
* @param root
* @return
*/
private int findMin(TreeNode root) {
int minVal = INT_MAX;
int leftMinVal = INT_MAX;
int rightMinVal = INT_MAX;
if (null != root) {
// 最小值默认为当前节点值
minVal = root.val;
leftMinVal = findMin(root.left);
rightMinVal = findMin(root.right);
// minVal等于当前minVal与leftMinVal中较小的一个
minVal = minVal < leftMinVal ? minVal : leftMinVal;
// minVal等于当前minVal与rightMinVal中较小的一个
minVal = minVal < rightMinVal ? minVal : rightMinVal;
}
return minVal;
}

参考答案:(2ms)

public boolean isValidBST(TreeNode root) {
if (root == null) return true;
return valid(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean valid(TreeNode root, long low, long high) {
if (root == null) return true;
if (root.val <= low || root.val >= high) return false;
return valid(root.left, low, root.val) && valid(root.right, root.val, high);
}

这答案写得我服了…真服…

3. 对称二叉树


参考答案:(12ms)

public boolean isSymmetric(TreeNode root) {
return isSymmetric(root, root);
}

public boolean isSymmetric(TreeNode root1, TreeNode root2) {
if (null == root1 && null == root2) {
return true;
}
if (null == root1 || null == root2) {
return false;
}
if (root1.val != root2.val) {
return false;
}
return isSymmetric(root1.left, root2.right) && isSymmetric(root1.right, root2.left);
}
4. 二叉树的最大深度


我的答案:(3ms)

public int maxDepth(TreeNode root) {
int leftHeight, rightHeight;
if (null == root) {
return 0;
} else { // 计算每个子树的高度
leftHeight = maxDepth(root.left);
rightHeight = maxDepth(root.right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
}

参考答案:(0ms)

public int maxDepth(TreeNode root) {
if(root==null)
return 0;
return Math.max(maxDepth(root.left)+1,maxDepth(root.right)+1);
}
5. 从前序与中序遍历序列构造二叉树


参考答案:(2ms)

public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length == 0) {
return null;
}
return buildTree(preorder, inorder, 0, 0, inorder.length - 1);
}

private TreeNode buildTree(int[] preorder, int[] inorder, int ps, int is, int ie) {
int val = preorder[ps];
TreeNode node = new TreeNode(val);
int iRoot = ie;
while (iRoot > is) {
if (val == inorder[iRoot]) {
break;
}
iRoot--;
}

if (iRoot > is) {
node.left = buildTree(preorder, inorder, ps + 1, is, iRoot - 1);
}

if (iRoot < ie) {
node.right = buildTree(preorder, inorder, ps + 1 + (iRoot - is), iRoot + 1, ie);
}
return node;
}

思路是这样的:在二叉树的前序遍历序列中,第一个数字总是树的根节点的值,但在中序遍历序列中,根节点的值保存在序列的中间,左子树的节点的值位于根节点的值的左边,而右子树则相反,然后既然找到了左右子树我们又可以使用同样的方法在前序和中序中分别构建左右子树,这样我们就能够使用递归的方法完成;(上面算法中的ps、is、ie分别表示前序的开始位置,中序的开始位置和中序的结束位置;)

6. 路径总和


参考答案:(3ms)

public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<Integer> nodeList = new ArrayList<Integer>();
List<List<Integer>> sumList = new ArrayList<List<Integer>>();

if (root == null) {
return sumList;
}
pathSum2(root, sum, sumList, nodeList);

return sumList;
}

public void pathSum2(TreeNode root, int target,
List<List<Integer>> sumList, List<Integer> nodeList) {
if (root.left == null && root.right == null) {
nodeList.add(root.val);
int sum = 0;
for (Integer integer : nodeList) {
sum += integer;
}
if (sum == target) {
sumList.add(new ArrayList<Integer>(nodeList));
}
return;
}
nodeList.add(root.val);
if (root.left != null) {
pathSum2(root.left, target, sumList, nodeList);
nodeList.remove(nodeList.size() - 1);
}
if (root.right != null) {
pathSum2(root.right, target, sumList, nodeList);
nodeList.remove(nodeList.size() - 1);
}
}
7. 二叉搜索树中第K小的元素


我的答案:(23ms)

public int kthSmallest(TreeNode root, int k) {
// 正确性判断
if (null == root || k < 1) {
return -1;
}
List<Integer> result = preOrder(root);
// 从小到大排序
Collections.sort(result);
return result.get(k - 1);
}

/**
* 遍历整棵树并返回一个List
*
* @param root
* @return
*/
private List<Integer> preOrder(TreeNode root) {
List result = new ArrayList();
if (null != root) {
result.add(root.val);
result.addAll(preOrder(root.left));
result.addAll(preOrder(root.right));
}
return result;
}

参考答案:(1ms)

public int kthSmallest(TreeNode root, int k) {
int count = countNodes(root.left);

if (k <= count) {
return kthSmallest(root.left, k);
} else if (k > count + 1) {
return kthSmallest(root.right, k - 1 - count);
}
return root.val;
}

public int countNodes(TreeNode n) {
if (n == null) return 0;
return 1 + countNodes(n.left) + countNodes(n.right);
}
8. 序列化二叉搜索树


参考答案:(12ms)

// Encodes a tree to a single string.
public String serialize(TreeNode root) {
StringBuffer sb = new StringBuffer();
preOrder(root,sb);
return sb.toString();
}
private static void preOrder(TreeNode root, StringBuffer sb){
if(root==null)
return;
sb.append(root.val).append('#');
preOrder(root.left,sb);
preOrder(root.right,sb);
}

// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data==null)
return null;
int val =0;
TreeNode root = null;
for(int i=0;i<data.length();i++){
if(data.charAt(i)!='#'){
val = val*10+(data.charAt(i)-'0');
}else{
root = insert(root,val);
val=0;
}
}
return root;
}
private static TreeNode insert(TreeNode root,int val){
if(root==null)
return new TreeNode(val);
if(root.val<val)
root.right = insert(root.right,val);
else
root.left = insert(root.left,val);
return root;
}
9. 另一个树的子树


参考答案:(15ms)

public boolean isSubtree(TreeNode s, TreeNode t) {
// Write your code here
if (s == null) {
return t == null;
}

if (s.val == t.val && isSametree(s, t)) {
return true;
}

return isSubtree(s.left, t) | isSubtree(s.right, t);
}

private boolean isSametree(TreeNode s, TreeNode t) {
if (s == null) {
return t == null;
}
if (t == null) {
return false;
}

if (s.val != t.val) {
return false;
}

return isSametree(s.left, t.left) & isSametree(s.right, t.right);
}

我的第一个反应还是去把两棵树的前序遍历的数组弄出来然后判断是否为子集,但是树这样的天然递归结构这样写很自然…

我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫描二维码加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: