剑指offer程序题设计相关的知识点(Java语言)
7.斐波那契数列
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39。【知识点:递归】
注意:
1.斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)
,当前的数字等于前两项的和。考虑以下三种情况。
public class Solution {
public int Fibonacci(int n) {
if(n<0){
return 0;
}else if(n < 2){
return n;
}else{
int sum = 0;
int n1 = 0;
int n2 = 1;
for(int i=2;i<=n;i++){
sum = n1 + n2;
n1 = n2;
n2 = sum;
}
return sum;
}
}
}
9.跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。【知识点:递归】
注意:
1.该问题实质是斐波那契数列求和,递推公式为 f(n)=f(n-1)+f(n-2)
。假设,一级台阶,有f(1)种方法,二级有f(2)种,以此类推,n级有f(n)种方法。显然,f(1)=1;f(2)=2
。假设n级台阶,第一步就有两种情况,跳一步或跳两步。如果跳一步,剩下的就是f(n-1);如果跳两步,剩下的就是f(n-2)。所以总数是f(n)=f(n-1)+f(n-2)。
public class Solution {
public int JumpFloor(int C) {
if(C<=0){
return 0;
}
if(C==1||C==2){
return C;
}else{
return JumpFloor(C-1)+JumpFloor(C-2);
}
}
}
8.变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。【知识点:贪心】
注意:
1.非递归:如果有n级阶梯,对于第n级,青蛙一定会停留,但是对于中间的n-1级阶梯,青蛙有可能停或者不停,两种情况,于是,结果就有2^(n-1)
种可能。
public class Solution {
public int JumpFloorII(int target) {
if(target<=0){
return 0;
}else{
//int a = 1; //实现一个递归求2的次方
//for(int i=1;i<target;i++){
//a = a*2;
//}
//return a;
return (int)Math.pow(2,target-1);
}
}
}
2.斐波那契:到达1级台阶只有一种可能,到达2级台阶有两种可能,所以f(1)=1,f(2)=2
。要达到3级台阶,可以在1级起跳,也可以在2级起跳,所以需要到达1级台阶的可能情况+到达2级台阶的可能情况+f(0),所以f(3)=f(2)+f(1)+1
。同理,到达n级台阶,可以在n-1、n-2、n-3…级起跳,f(n)=f(n-1)+f(n-2)+f(n-3)+...+1
。如果:
f(n)=f(n-1)+f(n-2)+f(n-3)...+f(n-n)=f(0)+f(1)+f(2)+...+f(n-1)
f(n-1)=f(0)+f(1)+..f(n-2)
上式-下式=f(n)-f(n-1)=f(n-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;
}else{
return 2*JumpFloorII(target-1);
}
}
}
9.矩形覆盖
我们可以用2x1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2x1的小矩形无重叠地覆盖一个2xn的大矩形,总共有多少种方法?【知识点:递归】
注意:
1.依然是斐波那契的应用: 如果n=1,只有一种竖着的摆放方式;如果n=2,则有两个竖着、两个横着(上下)两种方式;如果n>2,(1).第一个竖着放,剩下的有f(n-1)种方式;(2).第一个横着放,则下面的的那个也要横着放,已经是确定的,所以还剩下f(n-1)种方式。
public class Solution {
public int RectCover(int target) {
if(target<=0){
return 0;
}
if(target==1||target==2){
return target;
}else{
return RectCover(target-1)+RectCover(target-2);
}
}
}
10.二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。【知识点:进制转化、补码反码原码】
注意:
1.用方法将整数转为二进制数,统计其中1的个数。(更快,内存占用更少)
public class Solution {
public int NumberOf1(int n) {
int num = 0;
String str = Integer.toBinaryString(n);
char[] chars = str.toCharArray();
int i = 0;
for(;i<str.length();i++){
if(chars[i] == '1'){
num++;
}
}
return num;
}
}
2.用位运算,将1每次左移,和数字进行&运算,如果成功,则返回1.。
public class Solution {
public int NumberOf1(int n) {
int index = 1;
int num = 0;
while(index!=0){
if((n&index)!=0){
num++;
}
index = index<<1;
}
return num;
}
}
11.数值的整数次方
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0。【知识点:数学】
注意:
1.直接调用数学方法。
public class Solution {
public double Power(double base, int exponent) {
if(base==0&&exponent==0){
return 0;
}else{
return Math.pow(base, exponent);
}
}
}
12.调整数组顺序使奇数位于偶数的前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。【知识点:数组】
注意:
1.。第一种方法,创建一个和原数组长度一样的新数组,第一次遍历原数组,将奇数存入新数组,第二次遍历原数组,将偶数存入原数组,在将新数组的值赋值给原数组。在赋值的时候,如果使用array = newarr
;并不是正确赋值,这会改变array的内存地址,但是在主函数中操作的是原array,在方法中使用以上语句赋值,在主函数中没有作用,导致array并不会发生变化。所以应该用循环赋值,仅仅将新数组的值赋值给原数组,地址不参与其中,这样,改变的就是原来的数组,在主函数中输出的就是排序的数组。(更快,内存占用更少)
public class Jz_12_sortarraybasejo {
public void reOrderArray(int [] array) {
int[] newarr = new int[array.length];
int j = 0;
for(int i =0;i<array.length;i++){
if(array[i]%2!=0){
newarr[j] = array[i];
j++;
}
}
for(int i =0;i<array.length;i++){
if(array[i]%2==0){
newarr[j] = array[i];
j++;
}
}
// array = newarr;
for(int i=0;i<array.length;i++) {
array[i] = newarr[i];
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Jz_12_sortarraybasejo jz = new Jz_12_sortarraybasejo();
int[] array = {1,2,3,4,5,6,7};
for(int i=0;i<array.length;i++) {
System.out.print(array[i]);
}
System.out.println('\n');
jz.reOrderArray(array);
System.out.println('\n');
for(int i=0;i<array.length;i++) {
System.out.print(array[i]);
}
}
2.第二种方法,参考冒泡排序的思想,从头遍历数组,只要是遇到偶数在奇数前面的情况,就交换两个数。
public class Solution {
public void reOrderArray(int [] array) {
for(int i =0;i<array.length;i++){ //大循环
//每次都从头开始 针对前面有连续偶数的情况
for(int j=0;j<array.length-1;j++){
if(array[j]%2==0&&array[j+1]%2!=0){
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}
}
3.第三种方法。
用两个下标odd,even,even遍历数组,遇到偶数继续往后走,遇到奇数就将该奇数赋给odd对应位置,然后odd往后移动(先将从odd开始的位置的所有元素往后挪动一个,这样做的目的是能够保持偶数相对位置不变)。这个思路也就是使得odd前面的都是奇数,而且相对位置不变,而odd与even之间的都是偶数,然后even遇到奇数停下来,并将其放到odd位置,并且前提是将odd位置上的偶数向后挪动保证偶数相对位置不变,这样当even走到最后时,就使得odd之前的都是奇数,odd与even之间的都是偶数。
———————————————— 版权声明:本文为CSDN博主「lyl194458」的原创文章,遵循CC 4.0
by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lyl194458/article/details/89714872
public class Solution {
public void reOrderArray(int [] array) {
int len = array.length;
int odd = 0;
int even = 0;
while(even<len){
if(array[even]%2!=0){
int temp = array[even];
for(int i=even;i>odd;i--){
array[i] = array[i-1];
}
array[odd] = temp;
even++;
odd++;
}else{
even++;
}
}
}
}