2021-06-18_JAVA_数据结构和常用算法

JAVA

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个元素的右子节点为:2
n+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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值