JAVA
排序
冒泡排序
public static void bubbleSort(int[] arr)
{
for(int i=0;i<arr.length-1;i++)
{
for(int j=0;j<arr.length-1-i;j++)
{
if(arr[j]>arr[j+1])
{
int temp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
}
}
}
}
快速排序
1
void quickSort(int[] arr,int left,int right)
{
if(left>=right)
return ;
int key=arr[left];
int i=left;
int j=right;
while(i<j)
{
while(i<j && arr[j]>key)
{
j--;
}
while(i<j && arr[i] <= key)
{
i++;
}
swap(arr,i,j);
}
swap(arr,i,left);
quickSort(arr,left,i-1);
quickSort(arr,i+1,right);
}
void swap(int[] arr,int i,int j)
{
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
2
public static void quickSort(int[]arr,int left,int right){
int l=left;//左下标,最初在最左边
int r=right;//右下标,最初在最右边
int midValue=arr[(left+right)/2];//中轴值
int temp;
while (l<r){
while (arr[l]<midValue)//这里一定不要写<=,在midValue的左边一直找,找到一个>=midValue的值才退出while
l+=1;
while (arr[r]>midValue)//在midValue的右边一直找,找到一个<=midValue的值才退出while
r-=1;
if(l>=r)//说明midValue的左边已经全部<=midValue,右边全部>=midValue,跳出结束while循环
break;
//出了这两个while循环,说明arr[l]>=midValue,arr[r]<=midValue,需要进行交换
//交换,midValue左边大于midValue值的数与右边的小于midValue值的数的交换
temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
//交换完后,发现arr[l]=midValue,r--,发现arr[r]=midValue,l++
if(arr[l]==midValue)
r-=1;
if(arr[r]==midValue)
l+=1;
}
// 如果 l == r, 必须l++, r--, 否则为出现栈溢出
if (l == r) {
l += 1;
r -= 1;
}
//向左递归
if(left < r)
quickSort(arr, left, r);
//向右递归
if(right > l)
quickSort(arr, l, right);
}
归并排序
//分解
void mergesort(int[] arr,int left,int right,int[] temp)
{
if(left<right)
{
int mid=(left+right)/2;
mergesort(arr,left,mid,temp);
mergesort(arr,mid+1,right,temp);
//
merge(arr,left,mid,right,temp);
}
}
//合并
void merge(int[] arr,int left,int mid,int right,int[] temp)
{
int i=left;
int j=mid+1;
int t=0; //
//
while(i<=mid && j<=right)
{
if(arr[i]<=arr[j]){
temp[t]=arr[i];
t+=1;
i+=1;
}else{
temp[t]=arr[j];
t+=1;
j+=1;
}
}
//
while(i<=mid)
{
temp[t]=arr[i];
t++;
i++;
}
while(j<=right)
{
temp[t]=arr[j];
t++;
j++;
}
//
t=0;
int templeft=left;
while(templeft<=right)
{
arr[templeft]=temp[t];
t++;
templeft++;
}
}
希尔排序
public static void shellsort2(int[] arr)
{
for(int gap=arr.length/2;gap>0;gap/=2)
{
for(int i=gap;i<arr.length;i++)
{
int j=i;
int temp=arr[j];
if(arr[j]<arr[j-gap])
{
while(j-gap>=0 && temp<arr[j-gap])
{
arr[j]=arr[j-gap];
j-=gap;
}
arr[j]=temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
插入排序
public static int[] insertSort(int[]arr){
int insertData=0;//待插入的数
int insertIndex=0;//要插入的位置
for (int i = 0; i < arr.length - 1; i++) {//第i次插入,把arr[i+1]插入到arr[0]~arr[i]这个有序列表,有序列表扩大为arr[0]~arr[i+1]
insertData=arr[i+1];//第i次要插入的数为arr[i+1],第i次待插入数的位置是i+1
insertIndex=i;//先初始定义第i次插入的位置
//先让有序表找那个该移动的元素右移
//找待插入数insertData要插入的位置,将insertData和左边的有序表中的每个元素从右到左比较(因为左边有序表已经有序),如果insertData比有序表中的这个元素小,则把这个元素右移一位,继续与下一个元素比较
while ( insertIndex>=0 && arr[insertIndex]>insertData ){
arr[insertIndex+1]=arr[insertIndex];//有序表中当前元素大于待插入值了,有序表中该值需要右移
insertIndex--;//插入位置索引向左移动,以便继续与待插入数比较
}//获得待插入数要插入的位置insertIndex+1
//移动完后,再把待插入值放进有序表,把待插入数赋值给要插入到的位置
if(insertIndex+1!=i+1){//当要插入的位置insertIndex+1刚好是待插入数所在的位置,则不用动
arr[insertIndex+1]=insertData;//把待插入的数插到指定的位置
}
}
return arr;
}
选择排序
public static int[] selectSort(int[] arr){
int temp=0;//用于两元素的交换
for (int i = 0; i <arr.length-1; i++) {//第i次选择,从arr[i+1]~arr[length-1]里选取最小值,
// 并记录最小值所在位置索引,然后与arr[i]交换
int min=arr[i];
int minIndex=i;
boolean flag =false;
for (int j = i+1; j <= arr.length-1; j++) {
if(arr[j]<min){
min=arr[j];//最小值更新
minIndex=j;//你要知道更新的min的所在位置,因为你还要和a[i]交换呢,不然a[i]不知道换到哪
flag=true;//flag=true则说明min更新了
}
}
//把选出来的最小值min=arr[minIndex]与arr[i]交换
if(flag){//min更新了,需要和a[i]交换
temp=arr[i];
//arr[i]=arr[minIndex];
arr[i]=min;
arr[minIndex]=temp;//要知名min的位置
}//如果a[i]就是min,不用交换
}
return arr;
}
查找
二分查找(非递归)
public static int binarySearch(int[] arr,int target)
{
int left=0;
int right=arr.length-1;
while(left<=right)
{
int mid=(left+right)/2;
if(arr[mid]==target)
{
return mid;
}
else if(arr[mid]>target)
{
right=mid-1;
}
else
{
left=mid+1;
}
}
return -1;
}
搜索
矩阵中的路径
判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
public class Solution {
public boolean hasPath (char[][] matrix, String word) {
// write code here
for(int i=0;i<matrix.length;i++)
{
for(int j=0;j<matrix[0].length;j++)
{
if(matrix[i][j]==word.charAt(0))
{
boolean vis[][]=new boolean[matrix.length][matrix[0].length];
if(dfs(i,j,vis,matrix,0,word)==true)
return true;
}
}
}
return false;
}
boolean dfs(int i,int j,boolean[][] vis,char[][] matrix,int k,String word)
{
if(i<0 || j<0 || i>=matrix.length || j>=matrix[0].length || vis[i][j]==true)
{
return false;
}
if(word.charAt(word.length()-1) == matrix[i][j] && (k==word.length()-1))
{
return true;
}
if(word.charAt(k)==matrix[i][j])
{
vis[i][j]=true;
if(dfs(i+1,j,vis,matrix,k+1,word) || dfs(i,j+1,vis,matrix,k+1,word) || dfs(i-1,j,vis,matrix,k+1,word) || dfs(i,j-1,vis,matrix,k+1,word))
{
return true;
}else{
vis[i][j]=false;
return false;
}
}else{
vis[i][j]=false;
return false;
}
}
}
机器人的运动范围
public class Solution {
public int movingCount(int threshold, int rows, int cols) {
if(rows<0 || cols<0 || threshold<0)
{
return 0;
}
boolean[][] isvisited=new boolean[rows][cols];
int x=0;
int y=0;
int count=count(threshold,x,y,rows,cols,isvisited);
return count;
}
private int count(int threshold,int x,int y,int rows,int cols,boolean[][] isvisited)
{
//判断下标和是否访问过
if(x<0 || y<0 || x>=rows || y>=cols || isvisited[x][y])
{
return 0;
}
//判断是否满足条件
if(numsum(x)+numsum(y)>threshold)
{
return 0;
}
//条件都满足时,进行下一步递归
isvisited[x][y]=true;
return 1+count(threshold,x+1,y,rows,cols,isvisited)
+count(threshold,x-1,y,rows,cols,isvisited)
+count(threshold,x,y+1,rows,cols,isvisited)
+count(threshold,x,y-1,rows,cols,isvisited);
}
private int numsum(int num)
{
int sum=0;
while(num>0)
{
sum=sum+num%10;
num/=10;
}
return sum;
}
}
数组与矩阵
数组中重复的数字
class Solution {
public int findRepeatNumber(int[] nums) {
int result=-1;
Set<Integer> set=new HashSet<Integer>();
for(int num:nums){
if(!set.add(num)){//如果num给set里没添加成功,说明num已经存在于set了,num就是一个重复的数字
result=num;
break;
}
}
return result;
}
}
有序二维数组的查找
在一个 n * m 的二维数组中,每一行都从左到右递增的顺序排序,每一列都从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix==null||matrix.length==0||matrix[0].length==0){
return false;
}
int rowNum=matrix.length;
int colNum=matrix[0].length;
int i=0,j=colNum-1;//右上角第一个元素索引
while (i < rowNum && j >= 0) {
int data = matrix[i][j];
if (target==data) {//找到了
return true;
} else if (target<data) {//小了向左
j--;
} else {//大了向下
i++;
}
}
return false;//没找到
}
替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
class Solution {
public String replaceSpace(String s) {
int length=s.length();
char[] charArray=new char[length*3];
int size=0;
for(int i=0;i<length;i++){
if(s.charAt(i)==' '){//注意是单引号
charArray[size++]='%';
charArray[size++]='2';
charArray[size++]='0';
}else{
charArray[size++]=s.charAt(i);
}
}
String newString=new String(charArray,0,size);//char[] --> String:调用String的构造器
return newString;
}
}
顺逆时针打印矩阵
/*解析:
顺时针旋转,要正确判断你的一次循环到底是什么?
while大循环(for四个内循环遍历:从左向右、从上向下、从右向左、从下向上)
在每个内循环for中要考虑的问题:
1、定义上下左右四个边界
2、我们要打印哪行或哪列数据?
3、这四个边界怎么收缩?
4、判断是否到头了,走不下去了,打印完了的条件?
*/
class Solution {
public int[] spiralOrder(int[][] matrix) {
//先处理异常情况:空矩阵则返回一个空数组
if(matrix==null||matrix.length==0||matrix[0].length==0) return new int[0];
//先得到矩阵的尺寸
int rowNum=matrix.length;
int colNum=matrix[0].length;
//定义一个一维数组resArray
int length=rowNum*colNum;
int[] resArray=new int[length];
//顺时针旋转输出,要正确判断你的一次循环到底是什么:(从左向右、从上向下、从右向左、从下向上)
int left=0,right=colNum-1,top=0,bottom=rowNum-1; //1、定义 左右上下 四个边界,并初始化
int x=0;
while(true) {
//1、从左向右
for(int i = left; i <= right; i++)
resArray[x++] = matrix[top][i];// 从左向右,打印top边界所在行
if(++top > bottom) //是否打印完毕top>bottom(从左向右遍历完了要进行从上向下,发现下去不了) 这里的打印完是指整个打印完了,而不是这行或这列打印完了
//边界向内收缩top+1(因为从左到右经过了一行,所以上边界要+1向下移动)
break;
//2、从上向下
for(int i = top; i <= bottom; i++) //从上向下,打印right边界所在列
resArray[x++] = matrix[i][right];
if(left > --right) //是否打印完毕left>right,边界向内收缩right-1
break;
//3、从右向左
for(int i = right; i >= left; i--) //从右向左,打印bottom边界所在行
resArray[x++] = matrix[bottom][i];
if(top > --bottom) //是否打印完毕top>bottom,边界向内收缩bottom-1
break;
//3、从下向上
for(int i = bottom; i >= top; i--) //从下向上,打印left边界所在列
resArray[x++] = matrix[i][left];
if(++left > right) //是否打印完毕left>right,边界向内收缩left+1
break;
}
//返回一维数组
return resArray;
}
}
//这个题也可以改成后++ ,只不过要把>换成>= 把<换成<=
字符串中第一个不重复的字符
public int FirstNotRepeatingChar(String str) {
Map<Character,Integer> map=new HashMap<>();
for(int i=0;i<str.length();i++)
{
if(map.containsKey(str.charAt(i)))
{
map.put(str.charAt(i),map.get(str.charAt(i))+1);
}
else{
map.put(str.charAt(i),1);
}
}
for(int i=0;i<str.length();i++)
{
if(map.get(str.charAt(i))==1)
{
return i; //返回位置
}
}
return -1;
}
}
字符流中第一个不重复的字符
public class Solution {
//Insert one char from stringstream
Map<Character,Integer> map=new HashMap<>();
public void Insert(char ch)
{
if(map.containsKey(ch))
{
map.put(ch,map.get(ch)+1);
}else{
map.put(ch,1);
}
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
for(char ch:map.keySet())
{
if(map.get(ch)==1)
{
return ch;
}
}
return '#';
}
}
字符串的全排列
public ArrayList<String> Permutation(String str) {
ArrayList<String> ret=new ArrayList<String> ();
if(str==null)
{
return ret;
}
char[] arr=str.toCharArray();
dfs(0,arr,ret);
return ret;
}
void dfs(int pos,char[] arr,ArrayList<String> ret)
{
if(pos == arr.length-1)
{
ret.add(new String(arr));
return;
}
for(int i=pos;i<arr.length;i++)
{
if(arr[i]==arr[pos] && i!=pos)
{
continue;
}
swap(arr,i,pos);
dfs(pos+1,arr,ret);
swap(arr,i,pos);
}
翻转单词序列
public String ReverseSentence(String str) {
if(str==null || "".equals(str.trim()))
{
return "";
}
str=str.trim();
String[] strsplit=str.split(" ");
String ret=new String();
for(int i=strsplit.length-1;i>=0;i--)
{
ret=ret+strsplit[i]+" ";
//ret=ret.append(strsplit[i]+" ");
}
return ret.trim();
}
把字符串换成整数
public int StrToInt(String str) {
if(str==null || "".equals(str.trim())) //trim 去除空格
return 0;
str=str.trim();
char[] arr=str.toCharArray(); //转换成char数组
int i=0;
int flag=1; //符号为正
int res=0;
if(arr[i]=='-')
{
flag=-1;
}
if(arr[i]=='+' || arr[i]=='-')
{
i++;
}
while(i<arr.length)
{
if(isNum(arr[i]))
{
int cur=arr[i]-'0';
if(flag==1 && (res>Integer.MAX_VALUE/10 || res==Integer.MAX_VALUE/10 && cur>7))
{
return 0;
}
if(flag==-1 && (res>Integer.MAX_VALUE/10 || res==Integer.MAX_VALUE/10 && cur>8))
{
return 0;
}
res=res*10+cur;
i++;
}else{ //不是数字
return 0;
}
}
return res*flag;
}
public static boolean isNum(char c)
{
if(c>='0' && c<='9')
{
return true;
}
else{
return false;
}
}
合并两个有序数组?
字符串的字符集合?
顺时针旋转矩阵?
最长不重复子数组?
栈
先入后出
使用栈完成表达式的计算思路
1、是数字直接入数栈
2、是符号:
2.1、若当前符号栈为空,则直接入栈
2.2、如果符号栈有操作符,就进行比较:1)如果当前操作符的优先级小于或者等于栈中的操作符,就需从数栈中pop出两个数,在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈。2)若当前操作符优先级大于栈中的符号的优先级,就直接入符号栈
3、当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数和符号,并运行。
4、最后在数栈只有一个数字,就是结果
链表(Linked Liet)
单链表
1、单链表的反转
//先定义一个节点reversehead=head.next
//从头到尾遍历,每遍历一个节点,将其取出,并放在新链表的前端
//原来的链表head.next=reversehead.next;
public static void reversehead(HeroNode head)
{
if(head.next==null || head.next.next==null)
{
return ;
}
HeroNode cur=head.next;
HeroNode next=null; //指向当前节点[cur]的下一节点
HeroNode reversehead=new HeroNode(0,"","");
//遍历
while(cur!=null)
{
next=cur.next; //当前节点的下一节点
cur.next=reversehead.next; //将cur的下一节点指向新的链表的最前端
reversehead.next=cur;//
cur=next; //cur后移
}
//
head.next=reversehead.next;
}
2、查找单链表中的倒数第k个节点
// index 表示倒数第index个节点
// 从头到尾,得到链表的总长度getlength
// 得到size,然后从第一恶开始遍历(size-index)个
public static HeroNode findlastindexnode(HeroNode heronode,int index)
{
if(heronode.next==null)
{
return null;
}
int size=getlength(heronode);
if(index<0 || index>size)
{
return null;
}
HeroNode temp=heronode.next;
for(int i=0;i<size-index;i++)
{
temp=temp.next;
}
return temp;
}
3、获取单链表的节点个数(不包括头结点)
public static int getlength(HeroNode heronode)
{
if(heronode==null)
{
return 0;
}
int len=0;
HeroNode temp=heronode;
if(temp.next!=null)
{
len++;
temp=temp.next;
}
return len;
}
4、从尾到头打印单链表
//利用栈的先进后出
//
public static void reverseprint(HeroNode head)
{
if(head==null)
{
return ;
}
Stack<HeroNode> stack=new Stack();
HeroNode cur=head;
while(cur!=null)
{
stack.push(cur);
cur=cur.next;
}
while(stack.size()>0)
{
System.out.println(stack.pop());
}
}
双链表
添加
temp.next=newhead;
newhead.pre=temp;
删除
直接找到这个节点temp
temp.pre.next=temp.next;
if(temp.next1=null){
temp.next.pre=temp.pre;}
修改和单链表一样
合并两个有序的链表
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null)
return list2;
if(list2==null)
return list1;
ListNode ret=new ListNode(-1);
ListNode temp=ret;
while(list1!=null && list2!=null)
{
if(list1.val < list2.val)
{
temp.next=list1;
list1=list1.next;
}
else{
temp.next=list2;
list2=list2.next;
}
temp=temp.next;
}
if(list1==null)
{
temp.next=list2;
}
if(list2==null)
{
temp.next=list1;
}
return ret.next;
}
}
单向环形链表(约瑟夫问题)?
哈希表
缓存产品:Redis ; Memcache
例:使用哈希表管理雇员信息
思路:
package com.limei.hashtab;
import java.util.Scanner;
public class HashTabTest {
public static void main(String[] args) {
//
Hashtab hashtab=new Hashtab(7);
String key="";
Scanner scanner=new Scanner(System.in);
while(true)
{
System.out.println("add:添加");
System.out.println("list:显示");
System.out.println("find:查找");
System.out.println("exit:退出");
key=scanner.next();
switch(key)
{
case "add":
System.out.println("输入id:");
int id=scanner.nextInt();
System.out.println("输入name:");
String name=scanner.next();
Emp emp=new Emp(id,name);
hashtab.add(emp);
break;
case "list":
hashtab.list();
case "find":
System.out.println("请输入id:");
id=scanner.nextInt();
hashtab.findempbyid(id);
break;
case "exit":
scanner.close();
System.exit(0);
default:
break;
}
}
}
}
class Hashtab{
private EmpLinkedList[] emplinkedlistarray;
private int size;
public Hashtab(int size) {
this.size=size;
emplinkedlistarray = new EmpLinkedList[size];
//
for(int i=0;i<size;i++)
{
emplinkedlistarray[i]=new EmpLinkedList();
}
}
public void add(Emp emp)
{
int emplinkedlistno=hashfun(emp.id);
emplinkedlistarray[emplinkedlistno].add(emp);
}
public void list()
{
for(int i=0;i<size;i++)
{
emplinkedlistarray[i].list(i);
}
}
public int hashfun(int id)
{
return id % size;
}
//
public void findempbyid(int id)
{
int emplinkedlistno=hashfun(id);
Emp emp=emplinkedlistarray[emplinkedlistno].findempbyid(id);
if(emp==null)
{
System.out.println("没找到");
}else {
System.out.println("在第"+(id+1)+"条找到");
}
}
}
class EmpLinkedList{
//头指针
private Emp head;
//添加,
public void add(Emp emp){
//id自增,直接加到最后
if(head==null){
head=emp;
return;
}
Emp curtemp=head;
while(true){
if(curtemp.next==null)
break;
}
curtemp=curtemp.next;
}
// 遍历
public void list(int no)
{
if(head==null)
{
System.out.println("第"+(no+1)+"链表为空");
return;
}
System.out.println("第"+(no+1)+"链表");
Emp cur=head;
while(true)
{
System.out.printf("id="+cur.id+",naem="+cur.name);
if(cur.next==null)
{
break;
}
cur=cur.next;
}
System.out.println();
}
//查找
public Emp findempbyid(int id)
{
if(head==null)
{
System.out.println("链表为空");
return null;
}
Emp cur=head;
while(true)
{
if(cur.id==id)
{
System.out.println();
break;
}
if(cur.next==null)
{
cur=null;
}
cur=cur.next;
}
return cur;
}
}
class Emp{ //表示一个雇员
public int id;
public String name;
public Emp next; //next默认为null
public Emp(int id,String name){
this.id=id;
this.name=name;
}
}
二叉树
二叉树遍历
前中后遍历
根据输出当前节点的顺序判断前中后
1、前序遍历
步骤
1、创建一颗二叉树
2、先输出当前节点
3、若左子节点不为空,则递归继续前序遍历
4、若右子节点不为空,则递归继续前序遍历
2、中序遍历
步骤
1、创建一颗二叉树
3、若左子节点不为空,则递归继续中序遍历
4、输出当前节点
5、若右子节点不为空,则递归继续中序遍历
3、 后序遍历
步骤
1、创建一颗二叉树
3、若左子节点不为空,则递归继续后序遍历
4、若右子节点不为空,则递归继续后序遍历
5、输出当前节点
层序遍历:
从上往下 、
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
ArrayList<Integer> list=new ArrayList<Integer>();
ArrayList<TreeNode> queue=new ArrayList<>(); //存放二叉树的节点
if(root==null)
{
return list;
}
queue.add(root);
//宽度搜索
while(!queue.isEmpty())
{
TreeNode temp=queue.remove(0);
if(temp.left!=null)
{
queue.add(temp.left);
}
if(temp.right!=null)
{
queue.add(temp.right);
}
list.add(temp.val);
}
return list;
打印成多行
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> ret=new ArrayList<ArrayList<Integer> >();
if(pRoot==null)
{
return ret;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(pRoot);
return print(pRoot,queue);
}
public static ArrayList<ArrayList<Integer>> print(TreeNode root,Queue<TreeNode> queue)
{
ArrayList<ArrayList<Integer>> ret=new ArrayList<ArrayList<Integer> >();
while(!queue.isEmpty())
{
int size=queue.size();
ArrayList<Integer> list=new ArrayList<>();
for(int i=0;i<size;i++)
{
TreeNode node=queue.poll();
list.add(node.val);
if(node.left!=null)
{
queue.add(node.left);
}
if(node.right!=null)
{
queue.add(node.right);
}
}
ret.add(list);
}
return ret;
}
之字形打印
public ArrayList<ArrayList<Integer> > Print(TreeNode root) {
ArrayList<TreeNode> queue =new ArrayList<>();
ArrayList<ArrayList<Integer>> ret=new ArrayList<ArrayList<Integer>>();
if(root==null)
{
return ret;
}
queue.add(root);
int depth=1;
while(!queue.isEmpty())
{
int len=queue.size();
ArrayList<Integer> list =new ArrayList<Integer>();
for(int i=0;i<len;i++)
{
TreeNode temp=queue.remove(len-1-i);
list.add(temp.val);
if(depth%2==1)
{
if(temp.left!=null)
{
queue.add(temp.left);
}
if(temp.right!=null)
{
queue.add(temp.right);
}
}else{
if(temp.right!=null)
{
queue.add(temp.right);
}
if(temp.left!=null)
{
queue.add(temp.left);
}
}
}
depth++;
ret.add(list);
}
return ret;
}
序列化二叉树?
二叉树的深度
public int TreeDepth(TreeNode root) {
if(root==null)
{
return 0;
}
int l=TreeDepth(root.left);
int r=TreeDepth(root.right);
return Math.max(l,r)+1;
}
二叉搜索树
后序遍历序列
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence==null || sequence.length==0)
{
return false;
}
int len=sequence.length;
int root=sequence[len-1]; //根节点
//找左子树
int i=0;
for(;i<len-1;i++)
{
if(sequence[i]>root)
break;
}
//找右子树
int j=i;
for(;j<len-1;j++)
{
if(sequence[j]<root)
return false;
}
//初始化
boolean left=true;
boolean right=true;
if(i>0)
{
//取左子树,递归
left=VerifySquenceOfBST(Arrays.copyOfRange(sequence,0,i));
}
if(i<len-1)
{
//取右子树,递归
right=VerifySquenceOfBST(Arrays.copyOfRange(sequence,i,len-1));
}
return left && right;
}
第k大节点
public int kthLargest(TreeNode root, int k) {
ArrayList<Integer> list=new ArrayList<>();
midprint(root,list);
return list.get(list.size()-k);
}
public void midprint(TreeNode root,ArrayList<Integer> list)
{
if(root != null)
{
midprint(root.left,list);
list.add(root.val);
midprint(root.right,list);
}
}
最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
{
return null;
}
if(root.val>p.val && root.val>q.val)
{
return lowestCommonAncestor(root.left,p,q);
}
if(root.val<p.val && root.val<q.val)
{
return lowestCommonAncestor(root.right,p,q);
}
return root;
}
二叉树的最近公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
{
return root;
}
if(root==p || root==q)
{
return root;
}
TreeNode left=lowestCommonAncestor(root.left,p,q);
TreeNode right=lowestCommonAncestor(root.right,p,q);
if(left != null && right !=null)
{ // 表示左子树有一个目标节点,右子树也有一个目标节点
return root;
}
else if(left != null && right == null)
{
return left;
}
else if(right != null && left == null)
{
return right;
}
else{
return null;
}
}
二叉树查找
根据判断当前节点是不是的顺序判断前中后
1、前序查找
先判断当前节点的是否等于要查找的
如果相等,则返回当前节点
如果不等,则判断当前节点的左子节点是否为空,如果不为空,则递归前序查找
如果左递归前序查找找到节点,则返回,否则继续判断当前节点的右子节点是否为空,如果不空,继续向右递归前序查找
2、中序查找
先判断当前节点的左子节点是否为空,如果不为空,则递归中序查找
如果相等,则返回
如果不等,则和当前节点比较,如果是,则返回当前节点
否则继续向右递归中序查找,找到就返回,否则返回null
3、后序查找
先判断当前节点的左子节点是否为空,如果不为空,则递归后序查找
如果找到则返回,否则判断右子节点是否为空,不为空就继续向右递归中序查找,找到就返回,
如果找不到则和当前节点比较,如果是,则返回当前节点
和为某一值的路径
public class Solution {
ArrayList<Integer> list=new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> ret=new ArrayList<ArrayList<Integer>>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if(root==null)
{
return ret;
}
list.add(root.val);
if(target==root.val && root.left==null && root.right==null)
{
ret.add(new ArrayList<>(list));
}
if(target>root.val)
{
if(root.left!=null)
{
FindPath(root.left,target-root.val);
list.remove(list.size()-1); //??????
}
if(root.right != null)
{
FindPath(root.right,target-root.val);
list.remove(list.size()-1);
}
}
return ret;
}
}
二叉树删除
第一种:
如果是叶子节点,则直接删除该节点,
若删除的是非叶子结点,则删除该子树思路:
先考虑是否是空树,如果只有一个root节点,等价置空
如果当前节点的左子节点不为空,并且左子节点就是要删除的点,就this.left=null,并返回
如果当前节点的右子节点不为空,并且右子节点就是要删除的点,就this.right=null,并返回
如果都不是,则向左子树进行递归删除
再向右子树递归删除
判断
二叉树的镜像
1、
public TreeNode Mirror (TreeNode pRoot) {
// write code here
if(pRoot==null)
{
return null;
}
TreeNode temp=pRoot.left;
pRoot.left=Mirror(pRoot.right);
pRoot.right=Mirror(temp);
return pRoot;
}
2、
public TreeNode Mirror (TreeNode pRoot) {
// write code here
if(pRoot==null)
{
return null;
}
Stack<TreeNode> stack=new Stack<TreeNode>();
stack.add(pRoot);
while(!stack.isEmpty())
{
TreeNode root=stack.pop();
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
if(root.left!=null)
{
stack.add(root.left);
}
if(root.right!=null)
{
stack.add(root.right);
}
}
return pRoot;
}
对称的二叉树
public class Solution {
boolean isSymmetrical(TreeNode pRoot) {
if(pRoot==null)
{
return true;
}
TreeNode a=pRoot.left;
TreeNode b=pRoot.right;
return compare(a,b);
}
boolean compare(TreeNode a,TreeNode b)
{
if(a==null && b==null)
{
return true;
}
if(a==null || b==null)
{
return false;
}
if(a.val!=b.val)
{
return false;
}
return compare(a.left,b.right) && compare(a.right,b.left);
}
}
平衡的二叉树
class Solution {
public boolean isBalanced(TreeNode root) {
return depth(root)!=-1;
}
public int depth(TreeNode root)
{
if(root==null)
{
return 0;
}
int left=depth(root.left);
if(left==-1)
{
return -1;
}
int right=depth(root.right);
if(right==-1)
{
return -1;
}
if(left-right<(-1) || left-right>1)
{
return -1;
}else{
return 1+(left>right ? left:right);
}
}
}
数的子结构
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root1==null || root2==null)
{
return false;
}
if(root1.val==root2.val && (compareifsame(root1.left,root2.left) && compareifsame(root1.right,root2.right)))
{
return true;
}
return HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2);
}
public boolean compareifsame(TreeNode root1,TreeNode root2)
{
if(root2==null)
{
return true;
}
if(root1==null)
{
return false;
}
if(root1.val==root2.val)
{
return compareifsame(root1.left,root2.left) && compareifsame(root1.right,root2.right);
}else{
return false;
}
}
}
重建二叉树
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0)
{
return null;
}
TreeNode root=new TreeNode(preorder[0]);
rebuild(root,preorder,inorder,0,preorder.length,0,inorder.length );
return root;
}
public void rebuild(TreeNode root,int[] preorder,int[] inorder,int prel,int prer,int inl,int inr)
{
int i;
for(i=inl;i<inr;i++)
{
if(root.val==inorder[i])
{
break;
}
}
int leftlen=i-inl;
if(leftlen>0)
{
root.left=new TreeNode(preorder[prel+1]);
rebuild(root.left,preorder,inorder,prel+1,prel+1+leftlen,inl,i);
}
if(prer-prel-1-leftlen>0)
{
root.right=new TreeNode(preorder[prel+1+leftlen]);
rebuild(root.right,preorder,inorder,prel+1+leftlen,prer,i+1,inr);
}
}
}
合并二叉树?
中序遍历的下一个节点
public class Solution {
static ArrayList<Integer> list=new ArrayList<Integer>();
public TreeLinkNode GetNext(TreeLinkNode pNode) {
if(pNode==null)
{
return null;
}
TreeLinkNode ret=pNode;
while(ret.next!=null)
{
ret=ret.next;
}
midorder(ret);
for(int i=0;i<list.size();i++)
{
if(pNode.val == list.get(i))
{
if(i==list.size()-1)
{
return null;
}else{
TreeLinkNode ans=new TreeLinkNode(list.get(i+1));
return ans;
}
// return i==list.size()-1?null:list.get(i+1);
}
}
return null;
}
void midorder(TreeLinkNode node)
{
if(node != null)
{
midorder(node.left);
list.add(node.val);
midorder(node.right);
}
}
}
顺序存储二叉树
将二叉树存放成数组,但又可以以前序遍历、中序遍历、后序遍历的方式遍历
第n个元素的左子节点为:2n+1
第n个元素的右子节点为:2n+2
第n个元素的父节点为:(n-1)/2
从0开始编号
线索化二叉树
n个节点的二叉树有n+1个空指针域
当线索化二叉树后,不能在使用原来的遍历方法
堆
大顶堆:每个节点的值都大于或等于其左孩子的值
小顶堆:每个节点的值都小于或等于右孩子的值
常用算法
分治算法
三步:
分解:
解决:
合并:
汉诺塔问题
动态规划
背包问题
1、当v[i][0]=v[0][j]=0;//表示填入表的第一行和第一列是0;
2、当w[i]>j时,v[i][j]=v[i-1][j] ; //当准备加入新增的商品容量大于当前背包的容量时,就直接使用上一个单元格的装入策略
3、当w[i]<=j时,v[i][j]=max{v[i-1][j],v[i]+v[i-1][j-w[i]]};//当准备加入的新增的商品的容量小于等于当前背包的容量,
-------v[i-1][j]:上一个单元格的装入的最大值
-------v[i]:表示当前商品的价值
-------v[i-1][j-w[i]]:装入i-1商品,到剩余空间j-w[i]的最大值
最长公共子串
public String LCS (String str1, String str2) {
// write code here
if(str1.length()==0 || str2.length()==0)
{
return null;
}
int maxlen=0;
int index=0;
for(int i=0;i<str2.length();i++)
{
for(int j=i+1;j<=str2.length();j++)
{
if(str1.contains(str2.substring(i,j)))
{
if(maxlen < j-i){
maxlen=j-i;
index=i;
}
}
else break;
}
}
if(maxlen==0)
{
return "-1";
}
return str2.substring(index,index+maxlen);
}
字符串的全排列
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> ret=new ArrayList<String> ();
if(str==null)
{
return ret;
}
char[] arr=str.toCharArray();
dfs(0,arr,ret);
return ret;
}
void dfs(int pos,char[] arr,ArrayList<String> ret)
{
if(pos == arr.length-1)
{
ret.add(new String(arr));
return;
}
for(int i=pos;i<arr.length;i++)
{
if(arr[i]==arr[pos] && i!=pos)
{
continue;
}
swap(arr,i,pos);
dfs(pos+1,arr,ret);
swap(arr,i,pos);
}
}
void swap(char[] arr,int i,int j)
{
char temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
public class Solution {
public int jumpFloor(int target) {
if(target<=2)
{
return target;
}
else{
return jumpFloor(target-1)+jumpFloor(target-2);
}
}
}
扩展
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法。
public class Solution {
public int jumpFloorII(int target) {
if(target<=2)
{
return target;
}
else{
return 2*jumpFloorII(target-1);
}
}
}
连续子数组的最大和
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int dp=array[0];
int ret=array[0];
for(int i=1;i<array.length;i++)
{
dp=Math.max(dp+array[i],array[i]);
ret=Math.max(dp,ret);
}
return ret;
}
}
礼物的最大价值
class Solution {
public int maxValue(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
int[][] dp=new int[m][n];
dp[0][0]=grid[0][0];
for(int i=1;i<m;i++)
{
dp[i][0]=dp[i-1][0]+grid[i][0];
}
for(int i=1;i<n;i++)
{
dp[0][i]=dp[0][i-1]+grid[0][i];
}
for(int i=1;i<m;i++)
{
for(int j=1;j<n;j++)
{
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[m-1][n-1];
}
}
构建乘积数组?
股票的最大利润
class Solution {
public int maxProfit(int[] prices) {
if(prices==null || prices.length<=1)
{
return 0;
}
int ret=0;
int min=prices[0];
for(int i=1;i<prices.length;i++)
{
if(prices[i]<min)
{
min=prices[i];
}else{
ret=Math.max(ret,prices[i]-min);
}
}
return ret;
}
}
丑数
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index<=6)
{
return index;
}
int[] res=new int[index];
int t2=0;
int t3=0;
int t5=0;
res[0]=1; //第一个丑数为1
for(int i=1;i<index;i++)
{
res[i]=Math.min(res[t2]*2,Math.min(res[t3]*3,res[t5]*5));
if(res[i]==res[t2]*2)
t2++;
if(res[i]==res[t3]*3)
t3++;
if(res[i]==res[t5]*5)
t5++;
}
return res[index-1];
}
}
最长不含重复字符的字符串?
n个骰子的点数?
正则表达式匹配?
暴力匹配 & KMP算法
字符串匹配问题
哈希表
面试题
LRU?
最大重复子字符串
一个字符串的重复子串的最长长度只能小于等于length/2; 所以从length/2开始递减循环,每次取出理论最长子串,在判断剩下的字符串里面有没有理论串,有就找到结果
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
String str=scanner.nextLine();
String result=findMaxRepeat(str);
System.out.println(result);
}
public static String findMaxRepeat(String str){
int len=str.length();
String sample, left; //sample就是理论串, left就是剩下的字符串
for (int i = len/2; i>0; i--) {
for (int j = 0; j < len-i; j+=i) {
sample=str.substring(j,i);
left=str.substring(i);
if (left.indexOf(sample)!=-1) {
return sample;
}
}
}
return null;
}
}
计算x的平方根
向下取整
/**
* 根据平方数的性质——连续n个奇数相加的结果一定是平方数。
* 如:9=1+3+5;
* 16=1+3+5+7;
* 所以,不断的进行奇数相加,并判断x大小即可 有几个奇数 结果就是几 但是当==0的时候 会多循环一次 所以结果要-1
*/
public int sqrt (int x) {
//奇数的个数初始为0
int count = 0;
//奇数初始为1
int startVal = 1;
while(x>=0){
x = x-startVal;
count++;
startVal = startVal + 2;
}
return count-1;
}
返回双精度类型
public static double sqrt(double a)
{
double x = 1.0;
while( x * x -a > 0.00001 || x *x -a < -0.00001)
{
double y = (x + a/x) / 2;
x = y;
}
return x;
}