文章目录
前言
恍恍惚惚的过了秋招,但是没有拿到理想的offer,这篇便是记边复习遍记录面试中比较高频的算法题,为接下来的春招做准备,冲鸭<( ̄︶ ̄)↗[GO!]
树
树的最基本遍历,用递归的方式是必须要掌握的,面试的时候基本是会让你用迭代的方式写出来,所以都得掌握
后序遍历
递归:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// 递归处理
List<Integer> res=new ArrayList<>();
postorderTraversalHelper(root,res);
return res;
}
public void postorderTraversalHelper(TreeNode node,List<Integer> res){
if(node!=null){
postorderTraversalHelper(node.left,res);
postorderTraversalHelper(node.right,res);
res.add(node.val);
}
}
}
迭代:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// 迭代处理
// 方向来做
// 后序遍历是左-》右-》中,那么反过来中-》右-》左,按照后面的顺序,把最后得到的结果反向过来就行
List<Integer>res= new ArrayList<>();
// 节点用栈来存储
Stack<TreeNode> stack=new Stack<>();
while(!stack.isEmpty() || root!=null){
// 从中节点开始遍历完
while(root!=null){
res.add(root.val);
stack.push(root);
root=root.right;
}
root=stack.pop();
root=root.left;
}
Collections.reverse(res);
return res;
}
}
前序遍历
递归:
class Solution{
List<Integer> res=new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root){
// 前序遍历是中-》左-》右
// 递归的方式完成
if(root!=null){
res.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
}
return res;
}
}
迭代:
class Solution{
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> res=new ArrayList<>();
// 用stack来保存结点
Stack<TreeNode> stack=new Stack<>();
while(!stack.isEmpty() || root!=null){
while(root!=null){
res.add(root.val);
stack.push(root);
root=root.left;
}
root=stack.pop();
root=root.right;
}
return res;
}
}
中序遍历
- LeetCode 94
递归:
class Solution{
List<Integer> res=new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root){
// 递归就是左-》中-》右
if(root!=null){
inorderTraversal(root.left);
res.add(root.val);
inorderTraversal(root.right);
}
return res;
}
}
迭代:
class Solution{
public List<Integer> inorderTraversal(TreeNode root){
List<Integer> res=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
while(!stack.isEmpty() || root!=null){
while(root!=null){
stack.push(root);
root=root.left;
}
root=stack.pop();
res.add(root.val);
root=root.right;
}
return res;
}
}
二叉树的层次遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new ArrayList<>();
if(root == null){
return res;
}
// 用两个队列分别记录不同层含有的结点,然后依次遍历
Queue<TreeNode> A=new LinkedList<>();
Queue<TreeNode> B= new LinkedList<>();
A.offer(root);
while(!A.isEmpty()){
List<Integer> temp=new ArrayList<>();
while(!A.isEmpty()){
TreeNode node=A.poll();
temp.add(node.val);
if(node.left != null){
B.offer(node.left);
}
if(node.right !=null){
B.offer(node.right);
}
}
res.add(temp);
Queue<TreeNode> trans =A;
A=B;
B=trans;
}
return res;
}
}
构建二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
Map<Integer,Integer> map=new HashMap<>();
int [] preorder;
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 前序:中-》左-》右
// 中序:左-》中-》右
// 递归中,需要再每一层确定左右子树的范围
// 查找的时候,用 map 会更快
int length=inorder.length;
this.preorder = preorder;
for(int i=0;i<length;i++){
map.put(inorder[i],i);// 记录在中序遍历中每个数字的位置,用 map 查找更快
}
return buildTreeHelper(0,0,length-1);
}
public TreeNode buildTreeHelper(int p_root,int i_left,int i_right){
if(i_left>i_right){
return null;
}
// 第一个便是根节点
TreeNode root=new TreeNode(preorder[p_root]);
// 找到左子树的范围
// 定位根节点在中序遍历的位置
int position=map.get(preorder[p_root]);
root.left=buildTreeHelper(p_root+1,i_left,position-1);
root.right=buildTreeHelper(position-i_left+p_root+1,position+1,i_right);
return root;
}
}
二叉搜索树中的插入操作
递归:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution{
public TreeNode insertIntoBST(TreeNode root,int val){
// 使用递归
// 为空比较特殊
if(root==null){
TreeNode node=new TreeNode(val);
return node;
}else if(root.val<val){
root.right=insertIntoBST(root.right,val);
}else {
root.left=insertIntoBST(root.left,val);
}
return root;
}
}
迭代:
class Solution{
public TreeNode insertIntoBST(TreeNode root,int val){
// 使用迭代
// 为空比较特殊
if(root ==null){
return new TreeNode(val);
}
TreeNode temp=root;
while(true){
if(temp.val>val){
if(temp.left==null){
temp.left=new TreeNode(val);
break;
}
temp=temp.left;
}else{
if(temp.right==null){
temp.right=new TreeNode(val);
break;
}
temp=temp.right;
}
}
return root;
}
}
排序算法
1.冒泡排序
import java.util.*;
public class Main{
public static void main(String [] args){
// 冒泡排序
int [] test =new int[]{3,5,6,23,67,1,35,67,90,5,6};
int length=test.length;
for(int i=0;i<length;++i){
for(int j=0;j<length-i-1;j++){
if(test[j]>test[j+1]){
int temp=test[j];
test[j]=test[j+1];
test[j+1]=temp;
}
}
}
System.out.println(Arrays.toString(test));
}
}
2.快速排序
import java.util.Arrays;
public class Main{
public static void main(String [] args){
// 快速排序
int [] test =new int[]{3,5,6,23,67,1,35,67,90,5,6};
quicksort(test,0,test.length-1);
System.out.println(Arrays.toString(test));
}
public static void quicksort(int [] num,int left,int right){
if(left<right){
int temp= num[left];
int l=left;
int r=right;
while(l<r){
while(l<r && num[r]>temp){
r--;
}
if (l<r){
num[l]=num[r];
l++;
}
while(l<r && num[l]<temp){
l++;
}
if (l<r){
num[r]=num[l];
r--;
}
}
num[l]=temp;
quicksort(num,left,l-1);
quicksort(num,l+1,right);
}
}
}
3.堆排序
import java.util.*;
public class Main{
public static void main(String [] args){
// 堆排序
int [] test =new int[]{3,5,6,23,67,1,35,67,90,5,6};
int length=test.length;
for(int i=length/2-1;i>=0;--i){
// 从最大的一个叶子节点的父节点开始
heapsort(test,length,i);
}
for(int i=0;i<length;++i){
int temp=test[0];
test[0]=test[length-1-i];
test[length-1-i]=temp;
heapsort(test,length-1-i,0);
}
System.out.println(Arrays.toString(test));
}
public static void heapsort(int [] nums,int length,int position){
// 先把要重新定位的数字保存起来
int temp=nums[position];
for(int k=2*position+1;k<length;k=2*k+1){
if(k+1<length && nums[k+1]>nums[k]){
k=k+1;
}
if(nums[k]>temp){
nums[position]=nums[k];
position=k;
}else{
break;
}
}
nums[position]=temp;
}
}
查找
二分查找(基本)
import java.util.*;
public class Main {
public static void main(String [] args){
int [] test=new int[] {2,3,4,5,6,7,9,10,15};
// 二分查找
System.out.print(search(test,11));
}
public static boolean search(int [] nums ,int target){
int length=nums.length;
int left=0;
int right=length-1;
while(left<=right){
int mid=left + (right-left)/2;
if(nums[mid]== target){
return true;
}else if(nums[mid] >target){
right=mid-1;
}else{
left=mid+1;
}
}
return false;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int length;
if(nums==null || (length=nums.length)==0){
return 0;
}
if(nums[length-1]<target){
return length;
}
int left=0;
int right=length-1;
while(left<right){
int mid=left + (right-left)/2;
if(nums[mid]<target){
left=mid+1;
}else{
right=mid;
}
}
return left;
}
}
Java单例模式
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton() {
if(singleton == null){
synchronized(Singleton.class){
if (singleton ==null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
翻转链表
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre =null; //前一个
ListNode cur =head; //当前
ListNode next = null; // 指向下一个
while (cur!=null) {
next=cur.next;//保存下一个
cur.next =pre; //翻转
pre = cur;// 位置转移
cur =next ;//位置转移
}
return pre;
}
}
环形链表
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
// 没有结点和只有一个结点的时候为空
if(head == null || head.next==null){
return false;
}
// 快慢指针来检测
ListNode quick=head.next;
ListNode slow =head;
while(quick != null && quick.next !=null){
if(quick ==slow ){
return true;
}
quick =quick.next.next;
slow= slow.next;
}
return false;
}
}
环形链表 II
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode quick=head,slow=head;
while(quick!=null && quick.next!=null){
quick=quick.next.next;
slow=slow.next;
// 第一次相遇
if(quick==slow){
quick=head;
// 第二次相遇
while(quick !=slow){
slow=slow.next;
quick=quick.next;
}
return slow;
}
}
return null;
}
}
LRU缓存机制
class LRUCache {
class Node{
int key;
int value;
Node next;
Node pre;
public Node(int key,int value){
this.value=value;
this.key=key;
}
}
int capacity;
Map<Integer,Node> map=new HashMap<>();
Node head,tail;
public LRUCache(int capacity) {
// 初始化
this.capacity=capacity;
head=new Node(-1,-1);
tail=new Node(-1,-1);
head.next=tail;
tail.pre=head;
}
public int get(int key) {
int res=-1;
Node node;
if(map.containsKey(key)){
node =map.get(key);
res=node.value;
// 移动到队首
deleteNode(node);
putFirst(node);
}
return res;
}
public void put(int key, int value) {
// 生成一个新的结点
Node newNode=new Node(key,value);
// 如果有相同的值,则覆盖
if(map.containsKey(key)){
Node node=deleteNode(map.get(key));
map.remove(key);
}else if(map.size()==capacity){
// 删除链表中最后一个节点
Node node=deleteNode(tail.pre);
map.remove(node.key);
}
map.put(key,newNode);
// 放到队列头部
putFirst(newNode);
}
public void putFirst(Node node){
node.next=head.next;
node.pre=head;
head.next=node;
node.next.pre=node;
}
public Node deleteNode(Node node){
node.next.pre=node.pre;
node.pre.next=node.next;
return node;
}
}