良心总结:https://www.jianshu.com/p/3f0cd7af370d
1.二分查找
/***
* 参考资料:https://blog.csdn.net/v_july_v/article/details/7093204
*/
public class Search{
public static BinarySearch(int nums[],int target){
int left = 0;
int right = nums.length-1;
while(left<=right){
int middle = left + (right-left)>>1;
if(nums[middle]<target){
left = middle+1;
}
else if(nums[middle]>target){
right = middle-1;
}
else{
return middle;
}
}
return -1;
}
}
2.归并排序
/***
* 参考资料:https://blog.csdn.net/jianyuerensheng/article/details/51262984
*/
public class Mergesort{
public static Merge(int arr[],int low,int mid,int high){
int [] tmp = new int[high-low+1];
int i = low;//左边部分的游标
int j = mid+1;//右边部分的游标
int k = 0;
//逻辑很简单,谁小谁先上
while (i<=mid&&j<=high) {
if(arr[i]<=arr[j]){
tmp[k++] = arr[i++];
}else{
tmp[k++] = arr[j++];
}
}
//处理尾巴
while(i<=mid){
tmp[k++] = arr[i++];
}
//处理尾巴
while(j<= high){
tmp[k++] = arr[j++];
}
//覆盖原数组,使其局部有序
for(int k2=0;k2<tmp.length;k2++){
arr[low+k2] = tmp[k2];
}
}
public static Sort(int arr[],int low,int high){
int mid = low + (high - low)/2;
if(low<high){
sort(arr,low,mid);
sort(arr,mid+1,high);
Merge(arr,low,mid,high);
}
return;
}
}
3. 快速排序
/**
* 参考资料:https://www.jianshu.com/p/3f0cd7af370d
*/
public static void quickSort(int[] arr) {
qsort(arr, 0, arr.length - 1);
}
private static void qsort(int[] arr, int low, int high) {
if (low < high) {
int pivot = partition(arr, low, high); // 将数组分为两部分
qsort(arr, low, pivot - 1); // 递归排序左子数组
qsort(arr, pivot + 1, high); // 递归排序右子数组
}
}
//这种方法没有借助tmp,所以在最终落pivot之前,low处的元素有重复,相当于原数组中的pivot处的值被覆盖掉了
private static int partition(int[] arr, int low, int high) {
int pivot = arr[low]; // 枢轴记录
while (low < high) {
while (low < high && arr[high] >= pivot) --high;
arr[low] = arr[high]; // 交换比枢轴小的记录到左端
while (low < high && arr[low] <= pivot) ++low;
arr[high] = arr[low]; // 交换比枢轴大的记录到右端
}
// 扫描完成,枢轴到位
arr[low] = pivot;
// 返回的是枢轴的位置
return low;
}
4. 冒泡排序(优化版)
/***
* 参考资料:https://blog.csdn.net/yanxiaolx/article/details/51622286
*/
public static void BubbleSort(int Arr[]){
for(int i=0;i<Arr.length;i++){
int flag = 0;
int k = Arr.length -1;
int pos = 0;
for(int j=i;j<k;j++){
if(Arr[j]>Arr[j+1]){//大的往右边走
int tmp = Arr[j];
Arr[j] = Arr[j+1];
Arr[j+1] = tmp;
flag = 1;
pos = j;//记住最后交换的位置
}
}
k = pos;
if(flag == 0)
return;
}
}
5.拓扑排序
/**
* 参考资料:https://www.cnblogs.com/hapjin/p/5432996.html
* */
import java.util.*;
public class Vertex{
int out;
int in;
Edge adjoinedges[];
}
public class Edge{
Vertex start;
Vertex end;
}
public class Graph{
Vertex [] vertexs;
Edge [] edges;
}
public class Solution{
public static void topoSort(Graph graph){
Queue<Vertex> q = new Queue<>();
int count = 0;
for(Vertex v:graph.vertexs){//将当前拓扑图中入度为0的节点找出来并入栈
if(v.in==0)
q.offer(v);
}
while(!q.isEmpty()){
Vertex v = q.poll();
count++;//统计出队列的节点个数
for(Edge e : v.adjoinedges){
if(e.end.in==0){
q.offer(e.end);
}
}
}
if(count!=graph.vertexs.length)//如果所有节点没有出栈则存在环
System.out.println("circle");
}
}
6. 堆排序
/**参考资料:https://zhuanlan.zhihu.com/p/52884590
*/
/***
*
* @param arr: 用来存放堆的数组
* @param n: 堆的最右下角的元素下标
* @param i:堆的根节点的下标
*/
public static void heapify(int arr[],int n,int i){
int largest = i;// 将最大元素设置为堆顶元素
int l = 2*i +1;// left = 2*i + 1
int r = 2*i+2;// right = 2*i + 2
if(l<n&&arr[l]>arr[largest]){//n在这里起到边界判定的作用
largest = l;
}
if(r<n&&arr[r]>arr[largest]){//n在这里起到边界判定的作用
largest= r;
}
if(largest!=i){
swap(arr,i,largest);//将左右子树大的一个和堆顶交换
heapify(arr, n,largest);//递归构建堆
}
}
public static void heapifySort(int arr[],int n){
/** 初始建堆,i为啥从n/2-1开始呢?假设n=3,那么根节点是啥,
是0吧,这个是为了和heapify()函数下标规律保持一致*/
for(int i=n/2-1;i>=0;i--)
heapify(arr,n,i);
//一个个从堆顶取出元素
for(int i=n-1;i>=0;i--){
swap(arr,0,i);//堆顶元素的下标是0,交换即是把堆顶元素放到屁股后面
heapify(arr, i, 0);//堆调整的过程
}
}
/**注意交换不能按值传递*/
public static void swap(int arr[],int a,int b){
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
7.树的遍历
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
/**define the tree node with the class */
class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){val =x;}
}
public void visit(int x){
System.out.println("%d ",x);
}
/***Traverse with recusion */
public void preOrderTraverse(TreeNode root){
if (root==null) {
return;
}
visit(root.val);
preOrderTraverse(root.left);
preOrderTraverse(root.right);
}
public void inOrderTraverse(TreeNode root){
if (root==null) {
return;
}
inOrderTraverse(root.left);
visit(root.val);
inOrderTraverse(root.right);
}
public void postOrderTraverse(TreeNode root){
if (root==null) {
return;
}
postOrderTraverse(root.left);
postOrderTraverse(root.right);
visit(root.val);
}
/***Traverse without recusion */
public void preOrderTraverseNoRes(TreeNode root){
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty()||root!=null) {
if(root!=null){
visit(root.val);
stack.push(root);
root=root.left;
}else{
root = stack.pop();
root = root.right;
}
}
}
public void inOrderTraverseNoRes(TreeNode root){
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty()||root!=null) {
if(root!=null){//将左子树压栈到底
stack.push(root);
root=root.left;
}else{
root = stack.pop();//弹出即访问
visit(root.val);
root = root.right;//转右子树
}
}
}
public void postOrderTraverseNoRes(TreeNode root){
Stack<TreeNode> stack = new Stack<>();
List<Integer> ret = new ArrayList<>();
while (!stack.isEmpty()||root!=null) {
if(root!=null){
visit(root.val);
stack.push(root);
root=root.left;
}else{
root = stack.pop();
root = root.right;
}
}
Collections.reverse(ret);
return ret;
}
//层序遍历
public void levelTraverse(TreeNode root){
if(root == null){
return;
}
linkedList<TreeNode> queue = new linkedList<>();
queue.offer(root);//将根节点入队列
//
while(!queue.isEmpty()){
TreeNode node = queue.poll();//出队列
visit(node.val);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null)
{
queue.offer(node.right);
}
}
}
}
8.全排列
/**
参考资料:https://blog.csdn.net/u013309870/article/details/68941284
*/
public void Permutation(char chs[],int start )
{
if(start==chs.length-1)
{
Arrays.toString(chs);
//如果已经到了数组的最后一个元素,前面的元素已经排好,输出。
}
for(int i=start;i<=chs.length-1;i++)
{
//把第一个元素分别与后面的元素进行交换,递归的调用其子数组进行排序
if(i==start||chs[i]!=chs[start])
{
Swap(chs,i,start);
Permutation(chs,start+1);
Swap(chs,i,start);
}
//子数组排序返回后要将第一个元素交换回来。
//如果不交换回来会出错,比如说第一次1、2交换,第一个位置为2,子数组排序返回后如果不将1、2
//交换回来第二次交换的时候就会将2、3交换,因此必须将1、2交换使1还是在第一个位置
}
}
public void Swap(char chs[],int i,int j)
{
char temp;
temp=chs[i];
chs[i]=chs[j];
chs[j]=temp;
}
9. 反转链表
/**参考资料:https://www.jianshu.com/p/3f0cd7af370d*/
public ListNode ReverseList(ListNode head) {
ListNode pre = null;
while(head!=null){
ListNode tmp = head;//暂存当前头节点
head = head.next;//head后移
tmp.next = pre;//当前头节点指向前一个节点
pre = tmp;//前一个节点后移
}
return pre;
}
10. 寻找链表的第一个公共节点
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1 = pHead1;
ListNode p2 = pHead2;
//可以理解为操场上跑步,由于两个人速度不一样,总可能相遇。
while(p1!=p2){
p1=(p1==null?pHead1:p1.next);//循环遍历链表
p2=(p2==null?pHead2:p2.next);//循环遍历链表
}
return p1;
}
11. 合并有序链表
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode head = new ListNode(0);//用来记录头节点
ListNode cur = head;//游标,谁小指向谁
//list1和list2也分别用来进行移动
while(list1!=null&&list2!=null){
if(list1.val<=list2.val){
cur.next = list1;//更新游标链接新节点
cur = cur.next;//更新游标
list1 = list1.next;//更新列表
}else{
cur.next = list2;
cur = cur.next;
list2 = list2.next;
}
}
if(list1!=null)
cur.next = list1;
if(list2!=null)
cur.next = list2;
return head.next;
}
12. 洗牌算法
/**
参考资料:https://www.jianshu.com/p/0071c8c4014e
*/
public static void Shuffle(int [] arr){
Random random = new Random();
int length = arr.length;
for(int i = length;i >1;i--){
Swap(arr, i-1, random.nextInt(i));//保证已经交换的不影响,可以出现不交换的情况
}
}
public static void Swap(int [] arr,int i,int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
13. 二叉树的宽度
/**
参考资料:https://blog.csdn.net/not_in_mountain/article/details/78198478
*/
public static int getMaxWidth(TreeNode root){
Queue<TreeNode> q = new LinkedList<>();
if(root!=null) q.offer(root);
int max = 0;
while(!q.isEmpty()||root!=null){
int len = q.size();//获取当前层节点个数
max = len>max?len:max;//遍历完一层节点
while(len>0){
TreeNode node = q.poll();
len--;
if(node.left!=null) q.offer(node.left);
if(node.right!=null) q.offer(node.right);
}
}
return max;
}
14. 链表中找环的入口
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead==null||pHead.next==null)
return null;
ListNode fastP = pHead;
ListNode slowP = pHead;
while(slowP!=null&&fastP!=null){
slowP=slowP.next;//慢指针
fastP=fastP.next.next;//快指针
if(slowP==fastP){
fastP=pHead;
while(fastP!=slowP){
fastP=fastP.next;
slowP=slowP.next;
}
if(slowP==fastP)
return slowP;
}
}
return null;
}
}
15.合并两个二叉树
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return null;
int val = (t1 == null ? 0 : t1.val) + (t2 == null ? 0 : t2.val);
TreeNode newNode = new TreeNode(val);
newNode.left = mergeTrees(t1 == null ? null : t1.left, t2 == null ? null : t2.left);
newNode.right = mergeTrees(t1 == null ? null : t1.right, t2 == null ? null : t2.right);
return newNode;
}
16. 希尔排序
/**
参考资料:https://mp.weixin.qq.com/s/vn3KiV-ez79FmbZ36SX9lg
*/
public static void ShellSort(int arr[]){
int n = arr.length;
int gap = n/2;
while(gap>0){
for(int i=1;i<n;i++){
int tmp = arr[i];
int j = i-gap;
while(j>0&&tmp<arr[j]){
arr[j+gap] = arr[j];
j-= gap;
}
arr[j+gap] = tmp;
}
gap = gap/2;
}
}
18.求一个子树是否是另一棵树的子树?
这道题本质上是一个回溯问题,题解采用了递归里面套递归的手法**/
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2){
boolean result = false;
if(root1==null||root2==null)
return false;
if(root1.val==root2.val){//相等则继续往下探寻
result = IsContain(root1,root2);
}
if(!result){//往左探寻
result = HasSubtree(root1.left,root2);
}
if(!result){//往右探寻
result = HasSubtree(root1.right,root2);
}
return result;
}
public boolean IsContain(TreeNode root1,TreeNode root2){//递归探寻
if(root2==null) return true;
if(root1==null) return false;
if(root1.val!=root2.val) return false;
return IsContain(root1.left,root2.left) && IsContain(root1.right,root2.right);
}
}