剑指offer 6-10

6旋转数组的最小数字

  把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

分析:二分查找变种,没有具体的值用来比较。那么用中间值和高低位进行比较,看处于递增还是递减序列,进行操作缩小范围。

    • 处于递增:low上移

    • 处于递减:high下移(如果是high-1,则可能会错过最小值,因为找的就是最小值)

    • 其余情况:low++缩小范围

public class RotateArray {

    public static void main(String[] args) {
        RotateArray roatearray = new RotateArray();
        int[] array = {3,4,5,2,3};
        int min = roatearray.minNumberInRotateArray(array);
        System.out.println(min);
    }
     public int minNumberInRotateArray(int [] array) {
         int low = 0;
         int high = array.length-1;
         int mid = 0;
         while(low < high) {
             if(array[low] < array[high]) {
                 return array[low];
             }
             mid = low + (high -low) / 2;
             if(array[low] < array[mid]) {
                 low = mid + 1;
             }else if(array[mid] < array[high]) {
                 high = mid;
             }else
                 low++;
         }
         return array[low];
     }

}

7Fibonacci数列

  大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。n<=39

1. 递归法

 分析

斐波那契数列的标准公式为:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)

2.优化递归

分析

递归会重复计算大量相同数据,我们用个数组把结果存起来8!

3. 优化存储分析

其实我们可以发现每次就用到了最近的两个数,所以我们可以只存储最近的两个数

    • sum 存储第 n 项的值
    • one 存储第 n-1 项的值
    • two 存储第 n-2 项的值
public class fibonacci {

    public static void main(String[] args) {
        fibonacci fib = new fibonacci();
        int res = fib.Fibonacci3(39);
        System.out.println(res);
    }
        //递归  时间复杂度  O(2^n)  空间复杂度O(1)
     public int Fibonacci1(int n) {
         if(n <=1) {
             return n;
         }
         return Fibonacci1(n-1) + Fibonacci1(n-2);
     }
     //优化递归  递归每一次都会计算大量的数据,可以将之前计算的数据存储在数组中
     // 时间复杂度  O(n)  空间复杂度O(1)
     public int Fibonacci2(int n) {
         int[] arr = new int[40];
         arr[0] = 0;
         arr[1] = 1;
         for(int i =2; i <= n; i++) {
             arr[i] = arr[i-1] + arr[i-2];
         }
         return arr[n];
     }
     //优化存储  two代表第n-2的值   one代表第n-1的值
     public int Fibonacci3(int n) {
         int two = 0;
         int one = 1;
         int sum = 0;
         for(int i = 2; i <= n; i++) {
             sum = two + one;
             two = one;
             one = sum;
         }
         return sum;
     }
}

8 跳台阶

  一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
分析:

本质上还是斐波那契数列,所以迭代也可以求

当成 dp 问题来想的话:首先分析问题,它最终解是由前面的解累积起来的解,如何缩小问题的规模?

首先可知,第一阶有只能一步,一种;,第二阶可以两次一步、一次两步两种

  • 若楼梯阶级 n = 3
    • 跳 2 步到 3:剩下的是第一步没跳,起始跳到第一步只有一种
    • 跳 1 步到 3:剩下的是第二步没跳,起始跳到第二步有两种

通过分类讨论,问题规模就减少了:

  • 若楼梯阶级 n = n
    • 跳 2 步到 n:剩下的是第 n - 2 步没跳,起始跳到第 n - 2 步设它为 pre2 种
    • 跳 1 步到 n:剩下的是第 n - 1 步没跳,起始跳到第 n - 1 步设它为 pre1 种

同时可以发现第 n 阶的解法,只要用到 n - 1 和 n - 2 阶是多少,其他的不用考虑,因此用两个变量临时存下来即可

dp(i) = dp(i-2) + dp(i-1)

public class stepJump {

    public static void main(String[] args) {
        stepJump stepjump = new stepJump();
        int res = stepjump.JumpFloor(3);
        System.out.println(res);
        
    }
    //可以使用Fibonacci   但不推荐  
    public int JumpFloor(int target) {
        if(target <= 2) {
            return target;
        }
        int two = 1;
        int one = 2;
        int cur = 0;
        for(int i = 3;i <= target; i++) {
            cur = two + one;
            two = one;
            one = cur;
        }
        return cur;
    }

}

9变态跳台阶

  一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

分析

f(n)=f(n-1)+f(n-2)+……f(1)
f(n-1)=f(n-2)+……f(1)

两式相减得

f(n)=2f(n-1)

f(1) = 1

所以

f(n) = pow(2, n - 1)
public class StepJump_9 {
    public static void main(String[] args) { 
        StepJump_9 step = new StepJump_9();
        int res = step.JumpFloorII(9);
        System.out.println(res);
    }
    public int JumpFloorII(int target) {
        if(target ==1) {
            return target;
        }
//        return 2 * JumpFloorII(target -1);
        return (int)Math.pow(2, target-1);
    }
}

10矩形覆盖

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

比如n=3时,2*3的矩形块有3种覆盖方法:

涂掉最后一级矩形的时候,是用什么方式完成的?

    • n = 1 的时候
      • 只能横着覆盖,一种
    • n = 2 的时候
      • 可以横着和竖着覆盖,两种
    • n = 3 的时候
      • 第三级横着覆盖,用了一级,剩下 n = 2,有两种覆盖方法
      • 第三季竖着覆盖,用了两级,剩下 n = 1,有一种覆盖方法
      • 总共有 3 种
    • n = 4 的时候
      • 第 4 级横着覆盖,用了一级,剩下 n = 3,有三种覆盖方法
      • 第 4 级竖着覆盖,用了两级,剩下 n = 2,有两种覆盖方法
      • 总共有 5 种方法
    • n = n 的时候
      • 第 n 级横着覆盖,用了一级,剩下 n = n - 1,所以关注第 n - 1 种有几种覆盖方法
      • 第 n 级竖着覆盖,用了两级,剩下 n = n - 2,所以关注第 n - 2 种有几种覆盖方法
      • 总和为两种情况的总和

所以回答上面的问题,涂掉最后一级矩阵的时候,可以选择使用横向完成,也可以使用竖向完成,横向涂剩下 n - 1 阶,竖向涂剩下 n - 2 阶

关注 n - 1 与 n - 2 时的涂法有几种,这就是斐波那契数列

public class rectangularFootprint_10 {

    public static void main(String[] args) {
        rectangularFootprint_10 rectangular = new rectangularFootprint_10();
        int res = rectangular.RectCover(4);
        System.out.println(res);
    }
     public int RectCover(int target) {
         if(target <= 2) {
             return target;
         }
         int two = 1;
         int one = 2;
         int cur = 0;
         for(int i = 3; i <= target; i++) {
             cur = two + one;
             two = one;
             one = cur;
         }
         return cur;
     }
}

猜你喜欢

转载自www.cnblogs.com/lgh544/p/12964797.html