剑指offer66

1---数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。

也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},

那么对应的输出是第一个重复的数字2。

public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null || numbers.length==0){
            return false;
        }
     
        for(int i=0; i<numbers.length; i++){
            if(numbers[i]<0 || numbers[i]>numbers.length-1){
                return false;
            }
        }
         
        for(int j=0; j<numbers.length; j++){
            if(numbers[j] != j){
                if(numbers[j] == numbers[numbers[j]]){
                    duplication[0]=numbers[j];
                    return true;
                }
                 
                swap(numbers, j, numbers[j]);
            }
        }
         
        return false;
         
    }
     
     
    public static void swap(int[] numbers, int i, int j){
        int t=numbers[i];
        numbers[i]=numbers[j];
        numbers[j]=t;
    }
}


2---数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。

由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
       if(array == null || array.length == 0){
           return 0;
       }
         
        int num=array[0];
        int times=1;
        for(int j=0; j<array.length; j++){
            if(array[j] == num){
                times++;
            }else{
                if(times>0){
                    times--;
                }else{
                    num=array[j];
                    times=1;
                }
            }
        }
         
        times=0;
        for(int i=0; i<array.length; i++){
            if(array[i]==num){
                times++;
            }
        }
         
        if(times>array.length/2){
            return num;
        }
         
         
         
         
        return 0;
    }
}


3--数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.*;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
       if(array == null||array.length ==0){
           return;
       }
         
        List<Integer> list=new ArrayList<Integer>();
        for(int i=0; i<array.length; i++){
            if(!list.contains(array[i])){
                list.add(array[i]);
            }else{
                list.remove(new Integer(array[i]));
            }
        }
         
        if(list.size()==2){
            num1[0]=list.get(0);
            num2[0]=list.get(1);
        }
         
    }
}
添加笔记





4--- 数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
         
        if(array==null || array.length==0){
            return 0;
        }
         
         int left=left(array, 0, array.length-1, k);
         
        if(left==-1 ){
            return 0;
        }
         
        int right=right(array,left, array.length-1, k);
        return right-left+1;
         
        
    }
     
    public static int left(int[] array,int low, int high, int k){
        if(array[low]==k){
            return low;
        }
         
        while(low<=high){
            int mid=low+(high-low)/2;
            if(mid>=1&&array[mid-1]!=k && array[mid]==k ){
                return mid;
            }
             
            if(array[mid]>=k){
                high=mid-1;
            }else{
                low=mid+1;
            }
        }
         
        return -1;
    }
     
    public static int right(int[] array, int low, int high, int k){
        if(array[high]==k){
            return high;
        }
         
        while(low<=high){
               int mid=low+(high-low)/2;
             
            if(mid<array.length-1&&array[mid+1]!=k && array[mid]==k){
                return mid;
            }
             
            if(array[mid]>k){
                high=mid-1;
            }else{
                low=mid+1;
            }
             
        }
          return -1;
    }
}


5--- 把数组排成最小的数


输入一个正整数数组,把数组里所有数字拼接起来排成一个数,

打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

import java.util.ArrayList;
 
public class Solution {
    public String PrintMinNumber(int [] numbers) {
 
 
String str = "";
        for (int i=0; i<numbers.length; i++){
            for (int j=i+1; j<numbers.length; j++){
                int a = Integer.valueOf(numbers[i]+""+numbers[j]);
                int b = Integer.valueOf(numbers[j]+""+numbers[i]);
                if (a > b){
                    int t = numbers[i];
                    numbers[i] = numbers[j];
                    numbers[j] = t;
                }
                  
            }
        }
        for (int i = 0; i < numbers.length; i++) {
            str += String.valueOf(numbers[i]);
        }
        return str;
         
    }
}



6---旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,

输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,

若数组大小为0,请返回0。

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
     
        if(array==null || array.length==0){
            return 0;
        }
         
        if(array.length==1){
            return array[0];
        }
         
        for(int i=0; i<array.length-1; i++){
            if(array[i]>array[i+1]){
                return array[i+1];
            }
        }
         
        return array[0];
         
    }
}


方法二

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
         
         if(array == null || array.length ==0)
            return 0;
        if(array.length == 1)// 一个元素情况
            return array[0];
 
        int left = 0;
        int right = array.length - 1;
        while(left <= right){
            int mid = left + ( right - left)/2;// 中间id
            if(array[mid] > array[right]){ // 中间元素> 右侧数组的最大值
                left = mid + 1;
            }else {//  中间元素<= 右侧数组的最大值
                if(mid-1>=0 && array[mid-1]>array[mid]){ //左大 右大,中间是最小
                    return array[mid];
                }else
                    right = mid -1;
            }
        }
        return array[0];// 完全升序情况,上面一直运行 right = mid -1
     
    }
}



7---调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,

所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

public class Solution {
    public void reOrderArray(int [] array) {
        if(array == null || array.length == 0){
            return;
        }
         
        for(int i=1; i<array.length; i++){
            if(array[i]%2 == 1){
                int k=i-1;
                int temp=array[i];
                while(k>=0 && array[k]%2 ==0){
                    array[k+1]=array[k];
                    k--;
                }
                array[k+1]=temp;
            }
        }
         
    }
}


8--最小的K个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
        ArrayList<Integer> list = new ArrayList<>();
        if(k > input.length) return list;
        Arrays.sort(input);
        for (int i = 0; i < k; i ++) {
            list.add(input[i]);
        }
        return list;
    }
}

9--   丑数


public class Solution {
 
 
public int GetUglyNumber_Solution(int index) {
       if(index<=0) return 0;
       int[] a = new int[index];
       int ugly2 = 0;
       int ugly3 = 0;
       int ugly5 = 0;
       a[0] = 1;
       int i = 1;
       while(i<index) {
          int minValue = min(a[ugly2]*2,a[ugly3]*3,a[ugly5]*5);
          a[i++] = minValue;
          while(a[ugly2]*2<=minValue) ugly2++;
          while(a[ugly3]*3<=minValue) ugly3++;
          while(a[ugly5]*5<=minValue) ugly5++;
       }
       return a[index-1];
             
    }
      
    public int min(int a,int b,int c) {
        int minValue = a > b ? b : a;
        return  minValue = minValue> c ? c : minValue;
    }
     
}




10-- 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,

则这两个数字组成一个逆序对。输入一个数组,求出这个数组中

的逆序对的总数P。并将P对1000000007取模的结果输出。 

即输出P%1000000007

public class Solution {
    public int InversePairs(int [] array) {
         if(array.length<=0)
             return 0;
         return (int)(mergeSort(array,0,array.length-1)%1000000007);
     }
     public long  mergeSort(int[] array,int l,int r){
         if(l>=r){
             return 0;
         }
         int mid=(l+r)/2;
         long lnums=mergeSort(array,l,mid)%1000000007 ;
         long rnums=mergeSort(array,mid+1,r)%1000000007 ;
        return  lnums+rnums+merge(array,l,mid,r);
     }
     public long merge(int[] array,int l,int mid,int r){
        int [] temp = new int[r-l+1];
  
        long count=0;
        int i=l;
        int j=mid+1;
        int t=0;
        while(i<=mid && j<=r){
  
            if(array[i]>array[j]){ // 说明:i - mid 内的数都大于 array[j]
              //  temp[t++]=array[j];
                count+=mid-i+1// 计算逆序对个数
                temp[t++]=array[j++];
              //  j++;
            }else {
                temp[t++]=array[i];
                i++;
            }
        }
        while(i>mid&&j<=r){
             temp[t++]=array[j];
             j++;
        }
        while(i<=mid&&j>r){
            temp[t++]=array[i];
            i++;
        }
  
        for(i=l;i<=r;i++){
            array[i]=temp[i-l];
        }
        return count%1000000007;
     }
}

11----连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,

常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,

并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。

你会不会被他忽悠住?(子向量的长度至少是1)

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
         
        if(array == null || array.length == 0){
            return 0;
        }
         
        if(array.length == 1){
            return array[0];
        }
         
        int res=array[0];
        int sum=array[0];
        for(int i=1; i<array.length; i++){
               res=Math.max(res+array[i], array[i]);
               sum=Math.max(res, sum);
        }
         
        return sum;
         
    }
}



12----翻转单词顺序列

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。

同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。

例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,

正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

public class Solution {
    public String ReverseSentence(String str) {
        if( str == null || str.length()<=0)
            return str;
        char[] chs = str.toCharArray();
        int len = chs.length;
        int low = 0;
        int high = len - 1;
        Reverse(chs,low,high);
        low = 0;// 默认单词起始下标
        high = 1; // 默认单词结束下标
        while(high < len){
            // 找到单词结束下标,找到第一个空格,结束后是空格下标
            while(high< len && chs[high]!=' ')
                high++;
            Reverse(chs,low,high-1); // 区间内的单词进行选择
            while(high<len && chs[high]==' ') // 过滤掉多余的空格,结束后是非空格下标
                high++;
            low = high; // 更新起始下标
        }
        return String.valueOf(chs);
    }
    public void Reverse(char[] chs,int low ,int high){
        while(low < high){
            char tmp = chs[low];
            chs[low] = chs[high];
            chs[high] = tmp;
            low++;
            high--;
        }
 
         
    }
}


13---求1+2+3+...+n

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。


public class Solution {
    public int Sum_Solution(int n) {
        int sum=n;
        boolean bool=(n>0) && ((sum+=Sum_Solution(n-1))>0);
         
        return sum;
    }
}


14---不用加减乘除做加法


写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

public class Solution {
    public int Add(int num1,int num2) {
        int a=num1&num2;
        int b=num1^num2;
        if(a!=0){
            return Add(a<<1,b);
        }
         
        return b;
         
    }
}

15--- 整数中1出现的次数(从1到n整数中1出现的次数)

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13

因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。


public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int count=0;
        for(int i=1; i<=n; i++){
            count+=Count(i);
        }
        return count;
        
    }
     
    public static int Count(int num){
        int count=0;
        while(num>0){
            if(num%10 ==1){
                count++;
            }
            num/=10;
        }
         
        return count;
    }
}


16--左旋转字符串

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。

对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,

即“XYZdefabc”。是不是很简单?OK,搞定它!

public class Solution {
         
    public String LeftRotateString(String str,int n) {
        if(str == null || str.length() <=1)
            return str;
        int len= str.length();
        n = n%len;
        char[] A = str.toCharArray();
        reverse(A,0,len-1);
        reverse(A,0,len-n-1);
        reverse(A,len-n,len-1);
        return String.valueOf(A);
    }
    // 旋转
    public void reverse(char[] A,int left, int right){
        int i = left;
        int j = right;
        while(i<j){
            swap(A,i,j);
            i++;
            j--;
        }
    }
    // 交换
    public void swap(char[] A,int i,int j){
        char ch = A[i];
        A[i] = A[j];
        A[j] = ch;
    }
 
}



17--   字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c

所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

import java.util.ArrayList;
import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> result = new ArrayList<String>();
 
       if(str == null || str.length()==0){
           return result;
       }
        Set<String> set = new TreeSet<String>();
        char array[] = str.toCharArray();
 
        Permutation(array,0,set);
 
        result.addAll(set);
        return result;
        
    }
     
     public void Permutation(char[] chars,int start,Set<String> set){
 
        if(start == chars.length -1 ){
            String p = String.valueOf(chars);
            set.add(p);
            return;
        }
        for(int i = start;i<chars.length;i++){
            // 交换
            swap(chars,start,i);
            // 递归
            Permutation(chars,start+1,set);
            // 换回去
            swap(chars,start,i);
        }
 
    }
 
    public void swap(char[] array,int i,int j){
        char tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
}

18---- 把字符串转换成整数

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

public class Solution {
    public int StrToInt(String str) {
        char[] chs = str.toCharArray();
        if( !isDigit(chs))
            return 0;
        int digit = 0;
        int k = 0;
        boolean flag = true;
        if(chs[0]=='+' ) k=1;
        if(chs[0]=='-' ){
            k = 1;
            flag = false;
        }
        for(int i = k;i<=  chs.length -1;i++){
            digit = digit * 10 + (chs[i] - '0');
        }
        if(!flag)
            digit = - digit;
        return digit;
         
    }
     
    public boolean isDigit(char[] chs){
        if(chs == null || chs.length == 0)
            return false;
        int k = 0;
        if(chs[0]=='+' || chs[0] =='-') k=1;
        for(int i = k;i< chs.length ;i++)
            if(!( '0'<= chs[i] && chs[i] <= '9'))
                return false;
        return true;
    }
}
添加笔记

19--- 第一个只出现一次的字符

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str == null || str.length() ==0)
            return -1;
        int[] A = new int[256];
        for(int i=0;i<str.length();i++){
            char ch = str.charAt(i);
            A[ch]++;
        }
        for(int i=0;i<str.length();i++){
            char ch = str.charAt(i);
            if(A[ch] == 1)
                return i;
        }
        return -1;
    }
}

20--- 字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,

第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

import java.util.*;
 
public class Solution {
    //Insert one char from stringstream
    // map记录次数,list记录顺序
    HashMap<Character,Integer> map = new HashMap<Character,Integer>();
    ArrayList<Character> list = new ArrayList<Character>();
    public void Insert(char ch)
    {
         // map 记录个数 2表示多个
        if(map.containsKey(ch)){
            map.put(ch,2);
        }else{
            map.put(ch,1);
        }
        // ArrayList 记录顺序
        list.add(ch);
         
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
         for(int i = 0;i<list.size();i++){
            if(map.get(list.get(i)) == 1)
                return list.get(i);
        }
        return '#';
     
    }
}


21--- 表示数值的字符串


请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,

字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。


public class Solution {
    public boolean isNumeric(char[] str) {
 
  //匹配 带eE的字符串:-1E-16,+123.45e8 。只需要eE后面为整数,eE前是正负整数小数均可
        String ePattern = "[+-]?[0-9]*\\.?[0-9]+[eE][+-]?[0-9]+";
        // 匹配 不带eE的。 如+123 ,-123,+123.45,-123.45,-0.34
        //注:-.123也算数值
        String pattern2 = "[+-]?[0-9]*\\.?[0-9]+";
        String sss = String.valueOf(str);
        return sss.matches(ePattern)
               || sss.matches(pattern2) ;
         
    }
}


22---正则表达式匹配

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,

而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。

例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配


import java.util.Scanner;
 
public class Solution {
     public boolean match(char[] str, char[] pattern){
        if(str==null||pattern==null)
            return false;
        return isMatch(str,0,pattern,0);
    }
    ///三种可能:
    //1、模式串当前字符出现0次,即*表示当前字符出现0次,则str=str,pattern=pattern+2;
    //2、模式串当前字符出现1次,即*表示当前字符出现1次,则str=str+1,pattern=pattern+2;
    //3、模式串当前字符出现2次或2次以上,即*表示当前字符出现2次或以上,则str=str+1,pattern=pattern;
    public boolean isMatch(char[] str, int sIndex,char[] pattern,int pIndex){
        if(sIndex==str.length&&pIndex==pattern.length)
            return true;
        if(sIndex!=str.length&&pIndex==pattern.length)
            return false;
        //排除特例:a和a*a    
        //由于后面还有一个a所以前面a*需要当作 "0",就算str[]和pattern[]相等,也得舍去,看作不相同
        //所以isMatch(str,sIndex,pattern,pIndex+2)这句也需要加上
        if(pIndex+1<pattern.length&&pattern[pIndex+1]=='*'){
            if(sIndex<str.length&&(str[sIndex]==pattern[pIndex]||pattern[pIndex]=='.'))
                return isMatch(str,sIndex,pattern,pIndex+2)|| // 匹配0 个
                isMatch(str,sIndex+1,pattern,pIndex+2)|| // 匹配 1 个
                isMatch(str,sIndex+1,pattern,pIndex); // 匹配多个,pIndex不变可以继续匹配
            else{
                return isMatch(str,sIndex,pattern,pIndex+2);// 匹配0 个
            }
 
        }
        if(sIndex<str.length&&(str[sIndex]==pattern[pIndex]||pattern[pIndex]=='.'))
            return isMatch(str,sIndex+1,pattern,pIndex+1);
        return false;
 
    }
}




23---从尾到头打印链表

输入一个链表,从尾到头打印链表每个节点的值。

import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        Stack<Integer> stack = new Stack<Integer>();
        while(listNode!=null){
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.isEmpty()){
            result.add(stack.pop());
        }
        return result;
    }
     
}

24---- 合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
 
if(list1 == null){
           return list2;
       }
       if(list2 == null){
           return list1;
       }
       if(list1.val <= list2.val){
           list1.next = Merge(list1.next, list2);
           return list1;
       }else{
           list2.next = Merge(list1, list2.next);
           return list2;
       }     
    }
}


25--   删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
 
         if( pHead == null || pHead.next == null)
            return pHead;
        ListNode head = new ListNode(-1);
        head.next = pHead;
        ListNode pre = head;
        ListNode cur = head;
        while( cur!=null){
            while(cur.next!=null && cur.val == cur.next.val){
                cur = cur.next;
            }
            if(pre.next == cur) // 开始节点情况
                pre = pre.next;
            else
                pre.next = cur.next;
            cur = cur.next;
        }
        return head.next;
         
    }
}




方法二

public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null){
            return null;
        }
        ListNode tmpRoot = new ListNode(-1);
        tmpRoot.next = pHead;
        ListNode prevNode = tmpRoot;
        ListNode curNode = pHead;
        while(curNode != null && curNode.next != null){
            if(curNode.val == curNode.next.val){
                while(curNode.next != null && curNode.next.val == curNode.val){
                    curNode = curNode.next;
                }
                prevNode.next = curNode.next;
            }else{
                prevNode.next = curNode;
                prevNode = prevNode.next;
            }
            curNode = curNode.next;
        }
        return tmpRoot.next ;
        

    }
}

26--   反转链表

输入一个链表,反转链表后,输出链表的所有元素。


public class Solution {
    public ListNode ReverseList(ListNode head) {
 
 
ListNode ReverseHead = null ;//反转之后的头指针
        ListNode Node = head;//当前指针
        ListNode PreNode = null;//当前指针的前一指针
        //处理链表为空以及只有一个结点的情况
        if(head == null || head.next == null)
            return head;
  
        while(Node != null) {
            ListNode nextNode = Node.next;//保存当前结点的下一结点,防止链表截断
            if(nextNode == null)
                ReverseHead = Node;
            Node.next = PreNode ;//将当前链表的next指向前一结点
            //后移Node、NextNode,将后面的结点也反转
            PreNode = Node;
            Node = nextNode ;
        }
        return ReverseHead;
         
    }
}



27---链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
 
        ListNode fast = head;
        ListNode slow = head;
        if(k<=0)
            return null;
        // fast 向前走k步
        while(k>=1){
            if(fast == null){
                return null;
            }
            fast = fast.next;
            k--;
        }
 
        // 空的时候说明是第一个结点
        if(fast == null ){
            return slow;
        }
        // 一起走
        while(fast.next!=null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow.next;
         
         
    }
}




28----复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指

向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链

表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)



不用辅助空间的情况下实现On)的时间效率。分为三步:第一步复制原始链表上的每一个结点N创建对应的N’,并把N’放在N之后。如下图:

第二步:设置每个结点的random 指针。如果原始链表上的结点Nrandom指向S,则对应的复制结点N’random指向S’

第三步:把长链表分为两个链表:把奇数位置的结点用next连接起来就是原始链表,把偶数位置的结点用next连接起来就是复制出来的链表。

public class Solution {
    
 
 
 public RandomListNode Clone(RandomListNode pHead) {
        if(pHead == null) {
            return null;
        }
          
        RandomListNode currentNode = pHead;
        //1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
        while(currentNode != null){
            RandomListNode cloneNode = new RandomListNode(currentNode.label);
            RandomListNode nextNode = currentNode.next;
            currentNode.next = cloneNode;
            cloneNode.next = nextNode;
            currentNode = nextNode;
        }
          
        currentNode = pHead;
        //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
        while(currentNode != null) {
            currentNode.next.random = currentNode.random==null?null:currentNode.random.next;
            currentNode = currentNode.next.next;
        }
          
        //3、拆分链表,将链表拆分为原链表和复制后的链表
        currentNode = pHead;
        RandomListNode pCloneHead = pHead.next;
        while(currentNode != null) {
            RandomListNode cloneNode = currentNode.next;
            currentNode.next = cloneNode.next;
            cloneNode.next = cloneNode.next==null?null:cloneNode.next.next;
            currentNode = currentNode.next;
        }
          
        return pCloneHead;
    }
     
}




29--- 链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。


//左神讲的
//先说个定理:两个指针一个fast、一个slow同时从一个链表的头部出发
//fast一次走2步,slow一次走一步,如果该链表有环,两个指针必然在环内相遇
//此时只需要把其中的一个指针重新指向链表头部,另一个不变(还在环内),
//这次两个指针一次走一步,相遇的地方就是入口节点。
//这个定理可以自己去网上看看证明。
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead){
        ListNode fast = pHead;
        ListNode slow = pHead;
        while(fast != null && fast.next !=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow)
                break;
        }
        if(fast == null || fast.next == null)
            return null;
        fast = pHead;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }
}
添加笔记




30--两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。


/*
public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
 
ListNode current1 = pHead1;// 链表1
        ListNode current2 = pHead2;// 链表2
        if (pHead1 == null || pHead2 == null)
            return null;
        int length1 = getLength(current1);
        int length2 = getLength(current2);
        // 两连表的长度差
          
        // 如果链表1的长度大于链表2的长度
        if (length1 >= length2) {
            int len = length1 - length2;
            // 先遍历链表1,遍历的长度就是两链表的长度差
            while (len > 0) {
                current1 = current1.next;
                len--;
            }
  
        }
        // 如果链表2的长度大于链表1的长度
        else if (length1 < length2) {
            int len = length2 - length1;
            // 先遍历链表1,遍历的长度就是两链表的长度差
            while (len > 0) {
                current2 = current2.next;
                len--;
            }
  
        }
        //开始齐头并进,直到找到第一个公共结点
        while(current1!=current2){
            current1=current1.next;
            current2=current2.next;
        }
        return current1;
  
    }
  
    // 求指定链表的长度
    public static int getLength(ListNode pHead) {
        int length = 0;
  
        ListNode current = pHead;
        while (current != null) {
            length++;
            current = current.next;
        }
        return length;
    }
}



31---从上往下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

import java.util.ArrayList;
import java.util.LinkedList;
public class Solution {
        public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        ArrayList<Integer> result = new ArrayList<Integer>();
        if(root == null)
            return result;
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            result.add(node.val);
            if(node.left!=null){
                queue.add(node.left);
            }
            if(node.right!=null){
                queue.add(node.right);
            }
        }
        return result;
    }
     
}




32--二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的

结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个

数字都互不相同。

public class Solution {
 
public boolean VerifySquenceOfBST(int [] sequence) {
    if ( sequence==null || sequence.length<=0 ) return false;
    return VerifySquenceOfBST(sequence, 0, sequence.length-1);
}
  
private boolean VerifySquenceOfBST(int [] sequence, int start, int end){
    if ( start>=end )
        return true;
      
    int root = sequence[end];
      
    int i=start;
    while( sequence[i] < root ){
        i++;
    }
      
    int j=i;
    while( j<end ){
        if ( sequence[j]<root ) {
            return false;
        }
        j++;
    }
      
    boolean left = VerifySquenceOfBST(sequence, start, i-1);
    boolean right = VerifySquenceOfBST(sequence, i, end-1);
    return left && right;
}
}
添加笔记


33---二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

public class Solution {
   public int TreeDepth(TreeNode pRoot){
        if(pRoot ==null)
            return 0;
        int nLeft=TreeDepth(pRoot.left);
        int nRight=TreeDepth(pRoot.right);
 
        return nLeft>nRight?(nLeft+1):(nRight+1);
    }
}

非递归

方法二:非递归
求树的高度,换句话就是求树有多少层,可以参考层次遍历算法,我们只需要记录层数
利用队列
每次队列中保存一层的结点
输出一层元素,加入到下一层元素,深度+1
*
 
*/
import java.util.*;
public class Solution {
   public int TreeDepth(TreeNode pRoot){
       if(pRoot ==null)
            return 0;
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(pRoot);
        int depth = 0;
        while(!queue.isEmpty()){
            int size = queue.size();
            depth++;
            while(size-- >0){
                TreeNode node = queue.poll();
                if(node.left!=null)
                    queue.add(node.left);
                if(node.right!=null)
                    queue.add(node.right);
            }
        }
        return depth;
    }
}


34---二叉树中和为某一值的路径

输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点

形成一条路径。

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
 
    public TreeNode(int val) {
        this.val = val;
 
    }
 
}
*/
public class Solution {
 
 
  ArrayList<ArrayList<Integer>>  rt = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> ls = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
         if (root==null) return rt;
        ls.add(root.val);
        if (root.left==null&&root.right==null){
            if (root.val==target)
            rt.add(new ArrayList<Integer>(ls));
            return rt;
        }
        if (root.left!=null){
        FindPath(root.left,target-root.val);
        ls.remove(ls.size()-1);}
        if (root.right!=null){
        FindPath(root.right,target-root.val);
        ls.remove(ls.size()-1);}
        return rt;
    }
}

方法二

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
 
    public TreeNode(int val) {
        this.val = val;
 
    }
 
}
*/
public class Solution {
 
 
  private ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
private ArrayList<Integer> path = new ArrayList<Integer>();
     
private void dfsFind(TreeNode root, int target){
    path.add(root.val);     //进入
    if(target-root.val == 0 && root.left == null && root.right == null){
        result.add(new ArrayList<Integer>(path)); //复制此时的path,并加入到结果路径中
    }else {
        if(root.left != null)   dfsFind(root.left, target-root.val);
        if(root.right != null)  dfsFind(root.right, target-root.val);
    }
    path.remove(path.size() - 1);   //每次调用函数,有往链表中加入元素,就应该再让他出来,不能影响到其他路径的结果
}
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
    if(root != null){
        dfsFind(root, target);
    }
    return result;
}
}
添加笔记



35----平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

public class Solution {
 
 
 //后续遍历时,遍历到一个节点,其左右子树已经遍历  依次自底向上判断,每个节点只需要遍历一次
      
    private boolean isBalanced=true;
    public boolean IsBalanced_Solution(TreeNode root) {
          
        getDepth(root);
        return isBalanced;
    }
    public int getDepth(TreeNode root){
        if(root==null)
            return 0;
        int left=getDepth(root.left);
        int right=getDepth(root.right);
          
        if(Math.abs(left-right)>1){
            isBalanced=false;
        }
        return right>left ?right+1:left+1;
          
    }
     
}


36---树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

public class Solution {
    public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
        boolean result = false;
        //当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
        if (root2 != null && root1 != null) {
            //如果找到了对应Tree2的根节点的点
            if(root1.val == root2.val){
                //以这个根节点为为起点判断是否包含Tree2
                result = doesTree1HaveTree2(root1,root2);
            }
            //如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2
            if (!result) {
                result = HasSubtree(root1.left,root2);
            }
              
            //如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2
            if (!result) {
                result = HasSubtree(root1.right,root2);
               }
            }
            //返回结果
        return result;
    }
  
    public static boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) {
        //如果Tree2已经遍历完了都能对应的上,返回true
        if (node2 == null) {
            return true;
        }
        //如果Tree2还没有遍历完,Tree1却遍历完了。返回false
        if (node1 == null) {
            return false;
        }
        //如果其中有一个点没有对应上,返回false
        if (node1.val != node2.val) {  
                return false;
        }
          
        //如果根节点对应的上,那么就分别去子节点里面匹配
        return doesTree1HaveTree2(node1.left,node2.left) && doesTree1HaveTree2(node1.right,node2.right);
    }
}



37---重建二叉树


输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。


public class Solution {
 
 
  public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
        return root;
    }
    //前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
    private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
          
        if(startPre>endPre||startIn>endIn)
            return null;
        TreeNode root=new TreeNode(pre[startPre]);
          
        for(int i=startIn;i<=endIn;i++)
            if(in[i]==pre[startPre]){
                root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
                root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
            }
                  
        return root;
    }
     
}


38--二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。
public class Solution {
   public void Mirror(TreeNode root) {
        if(root == null)
            return;
 
        TreeNode left = root.left;
        TreeNode right = root.right;
 
        Mirror(left);
        Mirror(right);
 
        root.left = right;
        root.right = left;
    }
}


39--二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向
public class Solution {
   public TreeNode Convert(TreeNode root) {
      if(root==null)
            return null;
        if(root.left==null&&root.right==null)
            return root;
        // 1.将左子树构造成双链表,并返回链表头节点
        TreeNode left = Convert(root.left);
        TreeNode p = left;
        // 2.定位至左子树双链表最后一个节点
        while(p!=null&&p.right!=null){
            p = p.right;
        }
        // 3.如果左子树链表不为空的话,将当前root追加到左子树链表
        if(left!=null){
            p.right = root;
            root.left = p;
        }
        // 4.将右子树构造成双链表,并返回链表头节点
        TreeNode right = Convert(root.right);
        // 5.如果右子树链表不为空的话,将该链表追加到root节点之后
        if(right!=null){
            right.left = root;
            root.right = right;
        }
        return left!=null?left:root; 
    }
 
 
}

40--- 对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
public class Solution {
   boolean isSymmetrical(TreeNode pRoot)
    {
        return isSymmetrical(pRoot,pRoot);
    }
    boolean isSymmetrical(TreeNode root1,TreeNode root2){
        if(root1==null && root2==null)
            return true;
        if(root1==null || root2==null)
            return false;
        if(root1.val!=root2.val)
            return false;
        return isSymmetrical(root1.left,root2.right)
            && isSymmetrical(root1.right,root2.left);
    }
}

41--- 按之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
import java.util.ArrayList;
import java.util.*;
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
 
    public TreeNode(int val) {
        this.val = val;
 
    }
 
}
*/
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
 
 
        ArrayList<Integer> row = new ArrayList<Integer>();
        ArrayList<ArrayList<Integer> > result = new  ArrayList<ArrayList<Integer> >();
        if(pRoot == null)
            return result;
        Stack<TreeNode> stack1 = new Stack<TreeNode>();
        Stack<TreeNode> stack2 = new Stack<TreeNode>();
 
        boolean flag = true;
        stack1.push(pRoot);
        while(!stack1.isEmpty() || !stack2.isEmpty()){
            row = new ArrayList<Integer>();
            if(flag){
                int size = stack1.size();
                while((size--) >0){
                    TreeNode node = stack1.pop();
                    row.add(node.val);
                    if(node.left!=null)
                        stack2.push(node.left);
                    if(node.right!=null)
                        stack2.push(node.right);
                }
                flag = false;
            }else{
                int size = stack2.size();
                while((size--) >0){
                    TreeNode node = stack2.pop();
                    row.add(node.val);
                    if(node.right!=null)
                        stack1.push(node.right);
                    if(node.left!=null)
                        stack1.push(node.left);
 
                }
                flag = true;
            }
            result.add(row);
        }
        return result;
         
         
    }
 
}


42---- 把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
import java.util.ArrayList;
 
 
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
 
    public TreeNode(int val) {
        this.val = val;
 
    }
 
}
*/
import java.util.*;
 
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<Integer> row = new ArrayList<Integer>();
         ArrayList<ArrayList<Integer> > result = new  ArrayList<ArrayList<Integer> >();
        if(pRoot == null)
            return result;
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(pRoot);
        while(!queue.isEmpty()){
            int size = queue.size();
            row = new ArrayList<Integer>();
            while((size--)>0){
                TreeNode node = queue.poll();
                row.add(node.val);
                if(node.left!=null)
                    queue.offer(node.left);
                if(node.right!=null)
                    queue.offer(node.right);
            }
            result.add(row);
 
 
        }
        return result;
    }
 
}


43--- 二叉搜索树的第k个结点
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
import java.util.ArrayList;
public class Solution {
    ArrayList<TreeNode> list = new ArrayList<TreeNode>();
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        inorder(pRoot);
        if(k<=0 || k> list.size())
            return null;
        return list.get(k-1);
 
    }
    public void inorder(TreeNode root){
        if(root == null)
            return;
        inorder(root.left);
        list.add(root);
        inorder(root.right);
    }
 
 
 
}

44---二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
/*
 
思路:
(1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B )
(2) 若该节点不存在右子树:这时分两种情况:
2.1 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D )
2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,知道找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 I ,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点)。
*/
 
public class Solution {
 
 
public TreeLinkNode GetNext(TreeLinkNode pNode) {
        if (pNode == null)
            return pNode;
        if (pNode.right != null) { // 节点有右子树
            pNode = pNode.right;
            while (pNode.left != null) {
                pNode = pNode.left;
            }
            return pNode;
        } else if ( pNode.next != null && pNode.next.left == pNode) { // 节点无右子树且该节点为父节点的左子节点
            return pNode.next;
        } else if (pNode.next != null && pNode.next .right == pNode) { // 节点无右子树且该节点为父节点的右子节点
            while(pNode.next != null && pNode .next .left != pNode){
                pNode = pNode.next ;
            }
            return pNode.next ;
        }else{
            return pNode.next ;//节点无父节点 ,即节点为根节点
        }
    }
         
         
     
}

45--- 序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
/*
 
算法思想:根据前序遍历规则完成序列化与反序列化。所谓序列化指的是遍历二叉树为字符串;所谓反序列化指的是依据字符串重新构造成二叉树。
    依据前序遍历序列来序列化二叉树,因为前序遍历序列是从根结点开始的。当在遍历二叉树时碰到Null指针时,这些Null指针被序列化为一个特殊的字符“#”。
    另外,结点之间的数值用逗号隔开。
 
*/
public class Solution {
         
    int index = -1;   //计数变量
    String Serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        if(root == null){
            sb.append("#,");
            return sb.toString();
        }
        sb.append(root.val + ",");
        sb.append(Serialize(root.left));
        sb.append(Serialize(root.right));
        return sb.toString();
         
  }
    TreeNode Deserialize(String str) {
 
 
        index++;
        //int len = str.length();
        //if(index >= len){
        //    return null;
       // }
        String[] strr = str.split(",");
        TreeNode node = null;
        if(!strr[index].equals("#")){
            node = new TreeNode(Integer.valueOf(strr[index]));
            node.left = Deserialize(str);
            node.right = Deserialize(str);
        }
        return node;
         
  }
}

46---   二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,
每一列都按照从上到下递增的顺序排序。请完成一个函数,
输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
public class Solution {
 
 
 
 public boolean Find(int target, int [][] array) {
         if(array == null || array.length == 0 || array[0].length == 0){
            return false;
        }
        int row = array.length;
        int col = array[0].length;
        int i=0; // 行
        int j = col - 1; // 列  从右上开始比较
        while(i<row && j>= 0){
            while(i<row && j>=0){
                if(array[i][j] == target){ // 找到
                    return true;
                }else if(array[i][j] >target){// i j 位置元素比较大,应该向小的方向走
                    j = j - 1;
                }else{
                    i = i + 1;
                }
            }
        }
        return false;
    }
     
}


47---替换空格
请实现一个函数,将一个字符串中的空格替换成“%20”。
例如,当字符串为We Are Happy.
则经过替换之后的字符串为We%20Are%20Happy。
public class Solution {
    public String replaceSpace(StringBuffer str) {
        int len = str.length();
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<len;i++){
            char ch = str.charAt(i);
            if(ch == ' '){
                sb.append("%20");
            }else{
                sb.append(ch);
            }
        }
        return sb.toString();
    }
}



方法二替换空格
public class Solution {
    public String replaceSpace(StringBuffer str) {
        return str.toString().replaceAll("\\s","%20");
    }
}




48--数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数
个数值,那么中位数就是所有数值排序之后位于中间的数值。
如果从数据流中读出偶数个数值,
那么中位数就是所有数值排序之后中间两个数的平均值。
import java.util.*;
 
public class Solution {
 
    ArrayList<Integer> list = new ArrayList<Integer>();
    public void Insert(Integer num) {
        list.add(num);
    }
 
    public Double GetMedian() {
        int size = list.size();
        Collections.sort(list);
        if(size%2==1){
            return 1.0*list.get(size/2);
        }else{
            return (list.get(size/2) + list.get(size/2-1))/2.0;
        }
 
    }
}



49---- 二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。
其中负数用补码表示。
举个例子:一个二进制数1100,从右边数起第三位是处于
最右边的一个1。减去1后,第三位变成0,
它后面的两位0变成了1,而前面的1保持不变,
因此得到的结果是1011.
我们发现减1的结果是把最右边的一个1开始的所有位都取反了
。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,
从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,
把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作

public class Solution {
    public int NumberOf1(int n) {
 
        int count = 0;
      while(n!=0){
         count ++;
         n &=(n-1);
      }
      return count;
     }
         
     
}



50---斐波那契数列  f(n) = f(n-1) + f(n-2)
大家都知道斐波那契数列,现在要求输入一个整数n,
请你输出斐波那契数列的第n项。

n<=39

public class Solution {
         
        public int Fibonacci(int n) {
        int f0 = 0;
        int f1 = 1;
        int f2 = 1;
        if(n <=0)
            return f0;
        if(n==1)
            return f1;
        while(n>=2){
            f2 = f0 + f1;
            f0 = f1;
            f1 = f2;
            n--;
        }
        return f1;
    }
}



51---跳台阶  f(n) = f(n-1) + f(n-2)
一只青蛙一次可以跳上1级台阶,也可以跳上2级。
求该青蛙跳上一个n级的台阶总共有多少种跳法。
public class Solution {
    public int JumpFloor(int target) {
        int f0 = 1;
        int f1 = 1;
        int f2 = 2;
        if(target <=0)
            return f0;
        if(target==1)
            return f1;
        while(target>=2){
            f2 = f0 + f1;
            f0 = f1;
            f1 = f2;
            target--;
        }
        return f1;
 
    }
}


52---- 变态跳台阶f(n)=2*f(n-1)
一只青蛙一次可以跳上1级台阶,也可以跳上2级……
它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种
跳法。
因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+...+f(1)
因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
所以f(n)=2*f(n-1)
public class Solution {
    public int JumpFloorII(int target) {
       if (target <= 0) return 0;
       if (target == 1) return 1;
        int a = 1;
        int b = 2;
        for (int i = 2; i <= target; i++) {
            b = 2 * a;
            a = b;
        }
        return b;
}
}


方法二
public class Solution {
   public int JumpFloorII(int target) {
        int result = pow(2,target - 1);
        return result;
    }
    public int pow(int a,int b){
        if(b<=0)
            return 1;
        if(b==1)
            return a;
        int result = pow(a,b/2);
        result *=result;
        if(b%2==1){
            result *=a;
        }
        return result;
    }
}


53----矩形覆盖
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。
请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,
总共有多少种方法?
链接:https://www.nowcoder.com/questionTerminal/72a5a919508a4251859fb2cfb987a0e6
来源:牛客网

逆向分析
应为可以横着放或竖着放,多以f(n)可以是2*(n-1)的矩形加一个竖着放的2*1的矩形或2*(n-2)的矩形加2横着放的,即f(n)=f(n-1)+f(n-2)
当到了最后,f(1)=1,f(2)=2

public class Solution {
    public int RectCover(int target) {
        if(target<=0)
            return 0;
        int[] A = new int[target + 1];
        A[0] = 1;
        A[1] = 1;
        for(int i=2;i<=target;i++){
            A[i] = A[i-1] + A[i-2];
        }
        return A[target];
 
    }
}


方法二
public class Solution {
    public int RectCover(int target) {
        if (target < 1) {
            return 0;
        } else if (target == 1 || target == 2) {
            return target;
        } else {
            return RectCover(target-1) + RectCover(target-2);
        }
    }
}


54----数值的整数次方
给定一个double类型的浮点数base和int类型的整数exponent。
求base的exponent次方。
public class Solution {
    public double Power(double base, int exponent) {
        // 指数是 0
        if(exponent==0)
            return 1.0;
        // 底数是 0
        if(base ==0)
            return 0;
        // 指数是 1
        if(exponent == 1)
            return base;
        // 指数为 负
        if(exponent <0)
            return 1.0/Power(base,-exponent);
        //指数是最小值得时候要单独考虑
//        if(exponent == Integer.MIN_VALUE){
 //           return Power(base,exponent+1)/base;
//        }
 
        double result = Power(base,exponent/2);
        result =result * result;
        // 奇数
        if((exponent&0x01)==1)
            result = result * base;
        return result;
  }
}


55-----用两个栈实现队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。
 队列中的元素为int类型。
import java.util.Stack;
 
public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
     
    public void push(int node) {
        stack1.push(node);
    }
 
    public int pop() {
        if(!stack2.isEmpty()){
            return stack2.pop();
        }
        while(!stack1.isEmpty()){
            stack2.push(stack1.pop());
        }
        return stack2.pop();
    }
}
添加笔记


56----栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,
请判断第二个序列是否为该栈的弹出顺序
。假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,
序列4,5,3,2,1是该压栈序列对应的一个弹出序列,
但4,3,5,1,2就不可能是该压栈序列的弹出序列。
(注意:这两个序列的长度是相等

import java.util.ArrayList;
 
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
      if(pushA.length == 0 || popA.length == 0)
           return false;
 
        if(pushA.length != popA.length)
            return false;
        ArrayList<Integer> list = new ArrayList<Integer>();
        int len = pushA.length;
        int j=0;
        for(int i=0;i<len;i++){
           list.add(pushA[i]);
           int k = list.size()-1;
            while(k>=0 && j<len && list.get(k) == popA[j]){
                list.remove(k);
                k--;
                j++;
            }
        }
        return j==len;
          
          
    }
}
添加笔记


57----滑动窗口的最大值
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的
最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小
3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5};
 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1},
 {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
     ArrayList<Integer> result = new ArrayList<Integer>();
     int len = num.length;
     if(size<=0 || size> len)
         return result;
 
 
      for(int i=0;i<len;i++){
          int max = Integer.MIN_VALUE;
          for(int k=0;k+i < len && k<size;k++){
              max = max>num[i+k]?max:num[i+k];
          }
 
          result.add(max);
          if(i+size==len)
              break;
      }
     return result;
    }
}
方法二
import java.util.ArrayList;
import java.util.*;
 
 
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> result = new ArrayList<Integer>();
        if(num == null || size < 1 || num.length < size)return result;
        Deque<Integer> Deque = new LinkedList<>();        //双向队列,用于保存滑动窗口中的数字
        //滑动窗口内部,用于判断窗口中的最大值
        for(int i = 0; i < size - 1; i++){ 
            while(!Deque.isEmpty() && num[i] > num[Deque.getLast()]){ //getLast为插入端
                Deque.removeLast();    //将前面小的直接移除队列,因为不可能成为滑动窗口的最大值 
            } 
            Deque.addLast(i);          //将当前最大数字存入滑动窗口中 
        }
          
        //滑动整个窗口
        for(int i = size - 1; i < num.length; i++){ 
            while(!Deque.isEmpty() && num[i] > num[Deque.getLast()]){ //getLast为插入端,队尾 
                Deque.removeLast();  
            } 
            Deque.addLast(i);   
            if(i - Deque.getFirst() + 1 > size){  //getFirst为允许删除端,队头
                Deque.removeFirst(); 
            } 
            result.add(num[Deque.getFirst()]); //每次添加的是num[Deque.getFirst()],而不是Deque.getFirst(). 
        } 
        return result; 
    } 
}

58----   矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字 符串所有字符的路径。路径可以从矩阵中的任意一个格子开始, 每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入 该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条 字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,
因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后 ,路径不能再次进入该格子。
public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
     
        if(matrix == null || rows < 1 || cols < 1 || str == null){//参数校验 
            return false; 
        } 
        boolean[] visit = new boolean[rows*cols];//标记访问过的矩阵坐标位置,初始化为false 
        for(int i = 0; i < rows; i ++){ 
            for(int j = 0 ;j < cols; j ++){ 
                if(hasPathCore(matrix,rows,cols,i,j,str,0,visit)){ 
                    return true; 
                } 
            } 
        } 
        return false; 
    }
     
     
     private boolean hasPathCore(char[] matrix, int rows, int cols, int row, 
            int col, char[] str, int current, boolean[] visit) { 
        int index = row*cols + col; 
        if(row >= rows || col >= cols || row < 0 || col < 0 || visit[index] || matrix[index] != str[current]){ 
            return false; 
        } 
        visit[index] = true;//当前k下标的字符匹配成功 
        if(current == str.length-1){ 
            return true; 
        } 
        current ++;//准备匹配下一个字符 
        if(hasPathCore(matrix, rows, cols, row-1, col, str, current, visit)||//试探当前字符的上方字符 
           hasPathCore(matrix, rows, cols, row+1, col, str, current, visit)||//试探当前字符的下方字符 
           hasPathCore(matrix, rows, cols, row, col-1, str, current, visit)||//试探当前字符的左方字符 
           hasPathCore(matrix, rows, cols, row, col+1, str, current, visit)//试探当前字符的右方字符 
           ){ 
            return true; 
        } 
        current --;//如果四个方向的都不对,表明上一个字符匹配不对,回退 
        visit[index] = false; 
        return false; 
    } 
     
    public static void main(String[] args) { 
        char[] matrix = {'a','b','c','e', 
                         's','f','c','s', 
                         'a','d','e','e'}; 
        String str = "abceseecfdas"; 
        Solution offer_66 = new Solution(); 
        System.out.println(offer_66.hasPath(matrix, 3, 4, str.toCharArray())); 
    } 
     
 
 
}

59---- 机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,
但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),
因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public class Solution {
    int count=0;
    public int movingCount(int threshold, int rows, int cols)
    {
        if(0>threshold || rows<=0 || cols<=0)
            return count;
        if(threshold ==0)
            return 1;
        int[][] A = new int[rows][cols]; // 默认是 0
        movingCount(A,threshold,0,0,rows,cols);
        return count;
    }
    public void movingCount(int[][] A,int k,int i,int j, int rows, int cols){
        if(i<0 || i>= rows || j<0 || j>=cols)
            return;
        int s = getDigitSum(i,j);
        if(s<=k){
            if(A[i][j] ==0){
                count++;
                A[i][j] = 1;
                movingCount(A,k,i,j+1,rows,cols);
                movingCount(A,k,i,j-1,rows,cols);
                movingCount(A,k,i-1,j,rows,cols);
                movingCount(A,k,i+1,j,rows,cols);
            }
        }
    }
    public int getDigitSum(int a,int b){
        return getDigitSum(a) + getDigitSum(b);
    }
    public int getDigitSum(int num){
        int sum = 0;
        while(num >0){
            sum +=num%10;
            num/=10;
        }
        return sum;
    }
}
添加笔记

60-----扑克牌顺子
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)... 他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!
“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字, 并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。
LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。
import java.util.*;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers == null || numbers.length!=5)
            return false;
        Arrays.sort(numbers);
        int flag = 0;
        int i = 0;
        while(flag<numbers.length && numbers[flag] ==0){
            flag++;
        }
 
        // falg 就是0 的个数
        // 判断剩余数中
        // 判断是否有相等元素,有相等则返回false
        for(int k = flag;k<numbers.length - 1;k++){
            if(numbers[k] == numbers[k+1])
                return false;
        }
        // 判断区间内有几个数
        int num = numbers[4] - numbers[flag] ;
        return num<=4;
    }
}

61---   孩子们的游戏(圆圈中最后剩下的数)
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友 ,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。
其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。
每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,
继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。
请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n == 0 || m == 0)
            return -1;
        //先构造循环链表
        ListNode head = new ListNode(0);//头结点, 值为0
        ListNode temp = head;
        for(int i = 1; i < n; i++){
            temp.next = new ListNode(i);  //这里等价head.next = new ListNode(1)
            temp = temp.next;   //pre不是new出来的,所以pre赋值只是指针改变
        }
        temp.next = head;//将第n-1个结点(也就是尾结点)指向头结点
          
        temp = head;//temp指向头结点
        while(n != 1){
            //先找到第m个结点的前驱
            for(int i = 1; i < m - 1; i++)//注意从1开始到m-1,注意下标
                temp = temp.next;
            temp.next = temp.next.next;
            temp = temp.next;//更新头结点
            n--;
        }
        return temp.value;
    }
}
class ListNode{
    int value;
    ListNode next = null;
    public ListNode(int val){
        this.value = val;
    }
}
方法二
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n<1||m<1)
            return -1;
        int[] array=new int[n];
        for(int i=0;i<n;i++)
            array[i]=i;
        int i=-1;//用来记录报数的小朋友
        int step=0;//用来记录是否报到m
        int count=n;//用来记录还剩下多少小朋友
        while(count>0){
            i++;//小朋友开始报数
            if(i==n)    i=0;
            if(array[i]==-1)    continue;//出去已经报过的
            step++; //是否到达m
            if(step==m){
                step=0;
                array[i]=-1;
                count--;
            }
        }
        return i;
    }
}

62---- 顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个 数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
import java.util.ArrayList;
public class Solution {
 
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        int col = matrix[0].length;
        int row = matrix.length;
        printMatrix(matrix,col,row,result);
        return result;
    }
    public void printMatrix(int[][] matrix,int col,int row,ArrayList<Integer> result){
        //left to right
        int startI = 0;
        int endI = row - 1;
        int startJ = 0;
        int endJ = col - 1;
        int limit = col>row?col:row;
        while(limit-->0){
            // 左上 -> 右上
            if(startI<=endI && startJ<=endJ){
                for(int k = startJ;k<=endJ;k++){
                    result.add(matrix[startI][k]);  
                }
                startI++;
            }
            // 右上 -> 右下
            if(startI<=endI && startJ<=endJ){
                for(int k= startI;k<=endI;k++){
                    result.add(matrix[k][endJ]);
                }
                endJ--;
            }
            // 右下 -> 左下
            if(startI<=endI && startJ<=endJ){
                for(int k=endJ;k>=startJ;k--){
                    result.add(matrix[endI][k]);
                }
                endI--;
 
            }
            // 左下 -> 右上
            if(startI<=endI && startJ<=endJ){
                for(int k=endI;k>=startI;k--){
                    result.add(matrix[k][startJ]);
                }
                startJ++;
            }
            //if(startI>endI || startJ>endJ){
              //  break;
            //}
        }
 
    }
 
}

63----   包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
import java.util.Stack;
 
public class Solution {
    Stack<Integer> stack = new Stack<Integer>();
    Stack<Integer> minStack = new Stack<Integer>();
 
    public void push(int node) {
        stack.push(node);
        if(minStack.isEmpty()){
            minStack.push(node);
        }else{
            int top = minStack.peek();
            int min = Math.min(top,node);
            minStack.push(min);
        }
    }
 
    public void pop() {
        if(!stack.isEmpty()){
            stack.pop();
            minStack.pop();
        }
    }
 
    public int top() {
        if(!stack.isEmpty())
            return stack.peek();
        return -1;
    }
 
    public int min() {
        if(!minStack.isEmpty())
            return minStack.peek();
        return -1;
    }
}
64--- 和为S的连续正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
import java.util.ArrayList;
/*
*初始化small=1,big=2;
*small到big序列和小于sum,big++;大于sum,small++;
*当small增加到(1+sum)/2是停止
*/
public class Solution {
    public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> lists=new ArrayList<ArrayList<Integer>>();
        if(sum<=1){return lists;}
        int small=1;
        int big=2;
        while(small!=(1+sum)/2){          //当small==(1+sum)/2的时候停止
            int curSum=sumOfList(small,big);
            if(curSum==sum){
                ArrayList<Integer> list=new ArrayList<Integer>();
                for(int i=small;i<=big;i++){
                    list.add(i);
                }
                lists.add(list);
                small++;big++;
            }else if(curSum<sum){
                big++;
            }else{
                small++;
            }
        }
        return lists;
    }
      
    public int sumOfList(int head,int leap){        //计算当前序列的和
        int sum=head;
        for(int i=head+1;i<=leap;i++){
            sum+=i;
        }
        return sum;
    }
}


65---和为S的两个数字
输入一个递增排序的数组和一个数字S,在数组中查找两个数, 是的他们的和正好是S,如果有多对数字的和等于S,
输出两个数的乘积最小的。
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        int left = 0;
        ArrayList<Integer> result = new ArrayList<Integer>();
        int right = array.length - 1;
        while(left < right){
            int s = array[left] + array[right];
            if( s== sum){
                result.add(array[left]);
                result.add(array[right]);
                break;
            }else if(s<sum){
                left++;
            }else{
                right--;
            }
        }
        return result;
    }
}


66---构建乘积数组
给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],
其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。
不能使用除法。
import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        if(A==null || A.length <=1)
            return A;
        int n = A.length;
        int[] B = new int[n];
        B[0] = 1;
        int[] C = new int[n];
        C[n-1] = 1;
        int[] D = new int[n];
        for(int i=0;i< n-1;i++){
            B[i+1] = B[i] * A[i];
        }
        for(int i= n-1;i>=1;i--){
            C[i-1] = C[i] *A[i];
        }
        for(int i=0;i<n;i++){
            D[i] = B[i] * C[i];
        }
        return D;
    }
}
添加笔记







 
 















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值