算法面试题
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
二叉树和堆
写在前面:由于水平有限,有些可能不是最优解,但是我觉得是我自己的能够更好理解的答案~
目录
目录
前言
介绍二叉树和堆的最基本的考点
提示:以下是本篇文章正文内容,下面案例可供参考
一、二叉树
二叉树的查找
public class BinarySearchTree {
private Node tree;
public Node find(int data) {
Node p = tree;
while (p != null) {
if (data < p.data) p = p.left;
else if (data > p.data) p = p.right;
else return p;
}
return null;
}
public static class Node {
private int data;
private Node left;
private Node right;
public Node(int data) {
this.data = data;
}
}
}
二叉树的插入
public void insert(int data) {
if (tree == null) {
tree = new Node(data);
return;
}
Node p = tree;
while (p != null) {
if (data > p.data) {
if (p.right == null) {
p.right = new Node(data);
return;
}
p = p.right;
} else { // data < p.data
if (p.left == null) {
p.left = new Node(data);
return;
}
p = p.left;
}
}
}
二叉树的删除
public void delete(int data) {
Node p = tree; // p指向要删除的节点,初始化指向根节点
Node pp = null; // pp记录的是p的父节点
while (p != null && p.data != data) {
pp = p;
if (data > p.data) p = p.right;
else p = p.left;
}
if (p == null) return; // 没有找到
// 要删除的节点有两个子节点
if (p.left != null && p.right != null) { // 查找右子树中最小节点
Node minP = p.right;
Node minPP = p; // minPP表示minP的父节点
while (minP.left != null) {
minPP = minP;
minP = minP.left;
}
p.data = minP.data; // 将minP的数据替换到p中
p = minP; // 下面就变成了删除minP了
pp = minPP;
}
// 删除节点是叶子节点或者仅有一个子节点
Node child; // p的子节点
if (p.left != null) child = p.left;
else if (p.right != null) child = p.right;
else child = null;
if (pp == null) tree = child; // 删除的是根节点
else if (pp.left == p) pp.left = child;
else pp.right = child;
}
二叉树的遍历
二叉树的广度优先遍历
我们用二元组来存储最终遍历的节点,其中每一层的结果存入到level中,该层遍历完成后将level在存入外层的数组ret中;queue是将遍历到的node存入其中并按照先入先出的原则进行读取
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<Integer>();
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
ret.add(level);
}
return ret;
}
}
二叉树的层序遍历
给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
思路:这个和普通层序遍历的区别是它需要返回的是自底向上的层序(运用list.add(postion,val)即可,在规定位置进行插入节点)
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> listAll = new ArrayList<List<Integer>>();
if(root==null)
return listAll;
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> list = new ArrayList<Integer>();
while(size-- !=0){
TreeNode node = queue.poll();
list.add(node.val);
if(node.left!=null)
queue.offer(node.left);
if(node.right!=null)
queue.offer(node.right);
}
listAll.add(0,list);
}
return listAll;
}
二叉树的深度优先遍历
递归遍历
void preOrder(Node* root) {
if (root == null) return;
print root // 此处为伪代码,表示打印root节点
preOrder(root->left);
preOrder(root->right);
}
void inOrder(Node* root) {
if (root == null) return;
inOrder(root->left);
print root // 此处为伪代码,表示打印root节点
inOrder(root->right);
}
void postOrder(Node* root) {
if (root == null) return;
postOrder(root->left);
postOrder(root->right);
print root // 此处为伪代码,表示打印root节点
}
非递归遍历
非递归先序遍历(申请一个栈,压入头结点,然后弹出栈节点,打印出来,再将弹出节点的右孩子压入,左孩子压入,不断重复这个过程,直到栈为空)
public void preOrderUnRecur(Node head){
if (head!=null){
Stack<Node> stack=new Stack<Node>();
stack.add(head);
while(!stack.isEmpty()){
head=stack.pop();
System.out.printf(head.value+" ");
if (head.right!=null){
stack.push(head.right);
}
if (head.left!=null){
stack.push(head.left);
}
}
}
}
非递归中序遍历
思路:中序是左,根,右,因此考虑将左边界都压入栈,直到节点为空,则从栈中拿出一个打印,当前节点右移,若当前节点不为空,则压入栈,当前节点为左【跟着程序可以走通,但是还是不太理解】
`public void inOrderUnRecur(Node head){
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.println(head.value+" ");
head =head.right;
}
}
}
}
非递归后续遍历(需要建立两个stack,第一个stack的入栈是中、左右、第二个是中右左,保证出栈的时候是左右中)
public void posOrderUnRecur(Node head){
if (head!=null){
Stack<Node> stack1=new Stack<Node>();
Stack<Node> stack2=new Stack<Node>();
stack1.add(head);
while(!stack1.isEmpty()){
head=stack1.pop();
stack2.push(head);
if (head.left!=null){
stack1.push(head.left);
}
if (head.right!=null){
stack1.push(head.right);
}
}
while(!stack2.isEmpty()){
System.out.printf(stack2.pop().value+" ");
}
}
}
二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true
,否则返回 false
。假设输入的数组的任意两个数字都互不相同。
public boolean verifyPostorder(int[] postorder) {
return verify(postorder,0,postorder.length-1);
}
public boolean verify(int[]postorder,int i,int j){
if(i>j)
return t