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<array.length;i++) {
if(array[i]%2!=0) {
new_array[j]=array[i];
j++;//
}
}
//再次遍历数组将其中的所有偶数找出来放在新数组的后面
for(int i=0;i<array.length;i++) {
if(array[i]%2==0) {
new_array[j]=array[i];//先赋值给j,因为前面的j+1但是没有赋值,所以这个位置不需要先加1
j++;
}
}
return new_array;
}
/*
*
* 类似冒泡算法,前偶后奇数就交换:
*
*
* */
public void reOrderArray1(int [] array) {
for(int i= 0;i<array.length-1;i++){
for(int j=0;j<array.length-1-i;j++){
if(array[j]%2==0&&array[j+1]%2==1){
int t = array[j];
array[j]=array[j+1];
array[j+1]=t;
}
}
}
}
public static void main(String[]args) {
int[]array= {1,2,3,4,5,6,7,8,9};
int[]new_array=new int[array.length];
AdjustArray adjust=new AdjustArray();
new_array=adjust.reOrderArray(array);
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;i1;i++) {
s.append(i);
}
String str=s.toString();
for(int i=0;iif(str.charAt(i)=='1') {
count++;
}
}
return count;
}
public static void main(String[]args) {
ContainsOne solution=new ContainsOne();
int num=solution.NumberOf1Between1AndN_Solution(13);
System.out.println(num);
}
}
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;ireturn sum;
}
public static void main(String[]args) {
ContinuousSubArray solution=new ContinuousSubArray();
int[] number= {6,-3,-2,7,-15,1,2,2};
int sum=solution.FindGreatestSumOfSubArray(number);
System.out.println(sum);
}
}
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<ArrayList<Integer> > FindContinuousSequence(int sum) {
//存放结果
ArrayList<ArrayList<Integer>>result=new ArrayList<ArrayList<Integer>>();
//两个起点,相当于动态窗口的两边,根据其窗口内的值的和来确定窗口的位置和大小
int start=1;
int end=2;
while(start<end) {
//由于是连续的,差为1的一个序列,那么求和公式是(a0+an)*n/2
int cur=(start+end)*(end-start+1)/2;
//相等,那么就将窗口范围所有的数添加进结果集
if(cur==sum) {
ArrayList<Integer>list=new ArrayList<Integer>();
for(int i=start;i<=end;i++) {
list.add(i);
}
result.add(list);
start++;//end++ 都可以,它主要是为了让窗口右移
}else if(cur<sum) {//如果窗口内的值之和小于sum,那么右边窗口右移一下
end++;
}else {
//如果当前窗口内的值之和大于sum,那么左边窗口右移一下
start++;
}
}
return result;
}
}
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;ireturn target;
}
private static void quickSort(int[] array,int l,int r) {
if(lint i=l;
int j=r;
int x=array[l];//基准数
while(i//从右向左找第一个小于x的数
while(i=x) {
j--;
}
if(i//从左向右找第一个大于x的数
while(iif(i//i和j相等的时候结束
//递归调用
quickSort(array,l,i-1);
quickSort(array,i+1,r);
}
}
}
public static void main(String[]args) {
FindKMinNumber solution=new FindKMinNumber();
int[] number= {4,5,1,6,2,7,3,8};
ArrayListtarget=new ArrayList();
target=solution.GetLeastNumbers_Solution(number, 4);
for(int i=0;iout.println(target.get(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;iint key=array[i];
int count=0;
for(int j=0;jif(key==array[j]) {
count=count+1;
}
}
number.put(key, count);
}
Iterator> 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
public class FindNumbersAndSum {
public ArrayList 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(iif (array[i]+array[j]==sum) {
list.add(array[i]);
list.add(array[j]);
return list;
}else if(array[i]+array[j]>sum){
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<array.length;i++) {
int data=array[i];
int count=0;
for(int j=0;j<array.length;j++) {
if(data==array[j]) {
count=count+1;
}
}
map.put(data, count);
}
Iterator>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 {
Map<Character,Integer>map=new LinkedHashMap<Character,Integer>();
//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.Entry<Character, Integer>set: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;ichar s=strArray[i];
int count=0;
for(int j=0;jif(s==strArray[j]) {
count=count+1;
}
}
if(count==1) {
index=i;
return index;
}
}
return index;
}
public static void main(String[]args) {
FirstNotRepeat solution=new FirstNotRepeat();
int index=solution.FirstNotRepeatingChar("abcdaaddcbvhhhj");
System.out.println(index);
}
}
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 {
ArrayList<Integer>list=new ArrayList<Integer>();
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]1;
}else {
end=mid-1;
}
mid=(start+end)/2;
}
return start;
}
//获取k最后一次出现的下标
int getUpper(int[] array,int k) {
int start=0;
int end=array.length-1;
int mid=(start+end)/2;
while(start<=end) {
if(array[mid]<=k) {
start=mid+1;
}else {
end=mid-1;
}
mid=(start+end)/2;
}
return end;
}
}