剑指Offer算法题及答案Java完整版(一)

1、输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

package cn.ctgu.offer;
/*
 * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分
 * 所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
 * 
 * 思路:
 * 1、遍历数组将所有的奇数找出来放在一个新数组的前面
 * 2、再次遍历数组将所有的偶数找出来放在新数组的后面
 * 
 * */
public class AdjustArray {
    public int[] reOrderArray(int [] array) {
        int[]new_array=new int[array.length];
        int j=0;
        //遍历数组先将其中所有的奇数找出来放在新数组的前面
        for(int i=0;i



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

package cn.ctgu.offer;
/*
 * 题目:
 * 求1+2+3+...+n,
 * 要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
 * 
 * 
 * 思路:
 * 1、利用逻辑与的短路特性实现递归终止
 * 2、当n==0时,(n>0)&&((sum+=Sum_Solution(n-1))>0)只执行前面的判断,为false,然后直接返回0;
 * 3、当n>0时,执行sum+=Sum_Solution(n-1),实现递归计算Sum_Solution(n)。
 * 
 * */
public class CalculateSum {
    public int Sum_Solution(int n) {
        int sum=n;
        boolean flag=(sum>0)&&((sum=sum+Sum_Solution(--n))>0);
        return sum;
    }
    public static void main(String[]args) {
        CalculateSum solution=new CalculateSum();
        int s=solution.Sum_Solution(3);
        System.out.println(s);
    }
}



3、求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

package cn.ctgu.offer;
/*
 * 题目:
 * 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?
 * 为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。
 * ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数
 * (从1 到 n 中1出现的次数)。
 * 
 * 
 * 思路:
 * 1、将数字转成字符串数组(因为不知道n多大,只能这样做)
 * 2、从1遍历到n,将所有的数字存储到一个字符缓冲区中
 * 3、将该数字转换成字符串
 * 4、查找其中1的个数
 *
 * */
public class ContainsOne {
    public int NumberOf1Between1AndN_Solution(int n) {
        //1、将数字转成字符数组
        int count=0;
        StringBuffer s=new StringBuffer();
        for(int i=1;i



4、{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和

package cn.ctgu.offer;
/*
 * 题目:
 * {6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。
 * 给一个数组,返回它的最大连续子序列的和
 * 
 * 思路:
 * 使用动态规划
 * 
 * */
public class ContinuousSubArray {
    public int FindGreatestSumOfSubArray(int[] array) {
         int sum=array[0];//记录当前所有子数组的和的最大值
         int max=array[0]; //包含array[i]的连续数组最大值
         for(int i=1;i


5、大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39

package cn.ctgu.offer;
/*
 * 大家都知道斐波那契数列,现在要求输入一个整数n
 * 请你输出斐波那契数列的第n项。n<=39
 * 
 * 
 * */
public class FibonacciSequence {
    public int fib(int n) {
        if(n==1||n==2) {
            return 1;
        }else {
            return fib(n-1)+fib(n-2);
        }
    }
    public static void main(String[]args) {
        FibonacciSequence fibonac=new FibonacciSequence();
        int i=fibonac.fib(28);
        System.out.println(i);
    }
}



6、小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?

package cn.ctgu.offer;

import java.util.ArrayList;
/*
 * 题目:
 * 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。
 * 但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。
 * 没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。
 * 现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
 * 
 * 思路:
 * 双指针解决该问题
 * 
 * 
 * */
public class FindContinuousSeq {
    public ArrayList > FindContinuousSequence(int sum) {
        //存放结果
        ArrayList>result=new ArrayList>();
        //两个起点,相当于动态窗口的两边,根据其窗口内的值的和来确定窗口的位置和大小
        int start=1;
        int end=2;
        while(startlist=new ArrayList();
                for(int i=start;i<=end;i++) {
                    list.add(i);
                }
                result.add(list);
                start++;//end++  都可以,它主要是为了让窗口右移
            }else if(cur


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

package cn.ctgu.offer;

import java.util.ArrayList;
/*
 * 题目:
 * 输入n个整数,找出其中最小的K个数。
 * 例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
 * 
 * 思路:
 * 1、通过快速排序算法将数组排好序存入数组
 * 2、将最小的K个数遍历出来
 * 
 * */
public class FindKMinNumber {
    public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
        quickSort(input,0,input.length-1);
        ArrayListtarget=new ArrayList();
        if(input.length==0||k<=0||k>input.length) {
            return target;
        }
        for(int i=0;i=x) {
                    j--;
                }
                if(itarget=new ArrayList();
        target=solution.GetLeastNumbers_Solution(number, 4);
        for(int i=0;i


8、数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

package cn.ctgu.offer;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/*
 * 题目:
 * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
 * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。
 * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
 * 
 * 
 * 思路:
 * 1、计算数组长度
 * 2、统计每个数字出现的次数
 * 3、将每个数字出现的次数与数组长度比较,如果大于等于数组长度一半,则输出该数,否则输出0
 * */
public class FindNumber {
    public int MoreThanHalfNum_Solution(int [] array) {
        Map number=new HashMap();
        int target=0;
        for(int i=0;i> iter=number.entrySet().iterator();
        while(iter.hasNext()) {
            Map.Entryentry=iter.next();
            if(entry.getValue()>(int)(array.length/2)) {
                target=entry.getKey();
            }
        }
        return target;
    }
    public static void main(String[]args) {
        FindNumber solution=new FindNumber();
        int[] number= {1,2,3,2,2,2,5,4,2};
        int target=solution.MoreThanHalfNum_Solution(number);
        System.out.println(target);
    }

}


9、输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

package cn.ctgu.offer;

import java.util.ArrayList;
/*
 * 题目:
 * 输入一个递增排序的数组和一个数字S,在数组中查找两个数,
 * 使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
 * 
 * 思路:
 *  1、
 * 假设:找到两组满足条件的数组对(x,y)、(x+a,y-a),其中(x+y=S, 0 FindNumbersWithSum(int [] array,int sum) {
        ArrayListlist=new ArrayList();
        if(array==null||array.length<2) {
            return list;
        }
        int i=0;
        int j=array.length-1;
        while(isum){
                j--;
            }else {
                i++;
            }
        }
        return list;
    }
    public static void main(String[]args) {
        FindNumbersAndSum solution=new FindNumbersAndSum();
        int[]num= {1,2,4,7,11,15};
        ArrayListresult=new ArrayList();
        result=solution.FindNumbersWithSum(num, 15);
        System.out.println(result.get(0));
        System.out.println(result.get(1));
    }
}


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

package cn.ctgu.offer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/*
 * 题目:
 * 一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。
 * 请写程序找出这两个只出现一次的数字。
 * 
 * 思路:
 * 1、遍历数组,统计每个数字出现的次数
 * 2、将两个只出现一次的数字分别存储到num1和num2
 * 
 * */
public class FindTwoOneAppear {
     public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
         ArrayList list=new ArrayList();
         Mapmap=new HashMap();   
         for(int i=0;i>iter=map.entrySet().iterator();
         while(iter.hasNext()) {
             Map.Entryentry=iter.next();
             if(entry.getValue()==1) {
                 list.add(entry.getKey());
             }
         }
         num1[0]=list.get(0);
         num2[0]=list.get(1);
      }
}



11、请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。

package cn.ctgu.offer;

import java.util.LinkedHashMap;
import java.util.Map;

/*
 * 题目:
 * 请实现一个函数用来找出字符流中第一个只出现一次的字符。
 * 例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。
 * 当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
 * 
 * 思路:
 * 1、利用LinkedHashMap的有序性
 * 2、字符为key,出现的次数为value
 * 
 * */
public class FirstAppearOnce {
    Mapmap=new LinkedHashMap();
    //Insert one char from stringstream
    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(Map.Entryset:map.entrySet()) {
            if(set.getValue()==1) {
                return set.getKey();
            }
        }
        return '#';
    }
}



12、在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置,如果没有则返回 -1(需要区分大小写).

package cn.ctgu.offer;
/*
 * 题目:
 * 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
 * 如果没有则返回 -1(需要区分大小写).
 * 
 * 思路:
 * 1、将字符串转成字符串数组
 * 2、从前到后遍历每个字符并统计出现的次数,若某个字符只出现一次则返回它的位置
 * 
 * 
 * */
public class FirstNotRepeat {
    public int FirstNotRepeatingChar(String str) {
        char[]strArray=str.toCharArray();
        int index=-1;
        for(int i=0;i


13、我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

package cn.ctgu.offer;
/*
 * 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。
 * 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
 * 
 * 思路:
 * 1、每次填充都有两种方法:横着(两个)、竖着一个
 * 2、由于高已经限制死了,所以横着的时候两个必须是同时出现且都横着,横着的宽度占2
 * 3、竖着宽度占1,高度恰好
 * 4、当target=n时,它始终是在n-1时上面拓展来的,分两种情况拓展:一是在n-1的基础上直接加一块竖着的(1*2)即f(n)=f(n-1)+?
 * ?代表第二种添加方式,即当遇到1*2的时候它将会有两种变形即|| =两种,通过归纳可得出为f(n-2)
 * 
 *  
 * */
public class FixMartix {
    public int RectCover(int target) {

        //如果长度等于1则只有一种排法,即竖着排
        if(target==1) {

            return 1;
        }
        //如果长度等于2,则有两种排法,两个横着或者两个竖着
        if(target==2) {

            return 2;
        }
        else {
            return  RectCover(target-1)+RectCover(target-2);
        }

    }
    public static void main(String[]args) {
        FixMartix fix=new FixMartix();
        System.out.println(fix.RectCover(5));
    }
}


14、如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

package cn.ctgu.offer;

import java.util.ArrayList;
import java.util.Collections;

/*
 * 题目:
 * 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值
 * 那么中位数就是所有数值排序之后位于中间的数值。
 * 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
 * 我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
 * 
 * 思路:
 * 1、将所有的数添加到一个列表中
 * 2、将列表进行排序
 * 3、如果列表长度是奇数则直接用取中间值,如果是偶数,则取中间那个数和前面那个数的平均值
 * 
 * */
public class GetMedium {
    ArrayListlist=new ArrayList();
    public void Insert(Integer num) {
        list.add(num);
        Collections.sort(list);
    }

    public Double GetMedian() {
        int mid=list.size()/2;
        if((list.size()%2)==1) {
            return list.get(mid)/1.0;
        }else {
            return (list.get(mid-1)+list.get(mid))/2.0;
        }
    }
}


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

package cn.ctgu.offer;
/*
 * 题目:
 * 统计一个数字在排序数组中出现的次数。
 * 
 * 思路:
 * 由于数组有序,所以可以使用二分查找方法定位K第一次出现的位置和最后一次出现的位置
 * 
 * 
 * */
public class GetNumberK {
    public int GetNumberOfK(int [] array , int k) {
           int first=getLower(array,k);
           int second=getUpper(array,k);
           return second-first+1;
    }
    //获取k第一次出现的下标
    int getLower(int[] array,int k) {
        int start=0;
        int end=array.length-1;
        int mid=(start+end)/2;
        while(start<=end) {
            if(array[mid]

 

你可能感兴趣的:(java)