算法训练营【2】类似斐波那契数列的递归+快速幂

类似斐波那契数列的递归+快速幂

如果某个递归,除了初始项之外,具有如下的形式

F(N) = C1 * F(N) + C2 * F(N-1) + … + Ck * F(N-k) ( C1…Ck 和k都是常数)

并且这个递归的表达式是严格的、不随条件转移的

那么都存在类似斐波那契数列的优化,时间复杂度都能优化成O(logN)

马走棋盘问题

马从(0,0)出发,到达指定的(x,y)位置,必须走k步数,一共有多少种方法?

(马只能走日)

对于每个点,到达他的位置有8个位置(不越界的前提下)

public static int f(int х,int y,int k){
    
    
  if(k ==0) {
    
    
    returnх==0&&y==0?1:0;
  }
  if(x_ < 0 || х> 9 ||  у<0 || у>8) {
    
     
  return 0;
  }
  //有步数要走,x,y也是棋盘上的位置
  return
   f	(x+2,y-1, k-1)
  +f(x + 2, y+1, k-1)
  + f(х+1,y+2,k-1)
  +f(x-1,у+2,k-1)
  + f(x- 2,y+1,k-1)
  +f(x - 2, y-1, k-1)
  + f(x-1,y-2,k-1)
  +f(x + 1, у-2, k-1);
}

改动态规划

因为是后一步依赖前一步,所以先准备第一步的数据,逐步往前,直到最后一步。

public static int ways2(int x, int y, int k) {
    
     
  int[][][] dp = new int[10][9][k+1];// O~k
  dp[0][0][0] = 1;  // dp[..][..][0] = 0
  for(int level = 1; level <= k; level++) {
    
     
    for(int x =0;x<10;x++){
    
    //x可能性
      for(int y =0; y < 9;y++){
    
     
      	 // 求 dp[i][j][level];  递归函数怎么求的。这里也怎么求
      	 dp[i][j][level]=
   getValue(dp,x+2,y-1, level-1)
  +getValue(dp,x + 2, y+1, level-1)
  +getValue(dp,х+1,y+2,level-1)
  +getValue(dp,x-1,у+2,level-1)
  +getValue(dp,x- 2,y+1,level-1)
  +getValue(dp,x - 2, y-1, level-1)
  +getValue(dp,x-1,y-2,level-1)
  +getValue(dp,x + 1, у-2, level-1);
           ;
      }
    }
  }
  return dp[x][y][k];
}

public static int getValue(int[][][] dp, int x, int y, int k) {
    
     
  if(x<0 ||  x>9 || y<0 || y>8){
    
     
  return 0;
  }
return dp[x][y][k];
}

斐波那契数列快速幂解

暴力解复杂度为

O(2^N)

在这里插入图片描述

快速求 10^75.

75转为2进制 1001011

int res=0;

intemp=10

t每次和自己相乘,10^1 10^2. 10^4. 10^8. 10^16……

然后判断对应二进制位是否为1 ,如果为1 ,res= res * t

对于矩阵,每次也是 M^1 M^2 ……

对应二进制位为1 乘进res中

剑指 Offer 10- I. 斐波那契数列

class Solution {
    
    
    public int fib(int n) {
    
    
        if(n==0)return 0;
        if(n==1||n==2)return 1;
        int[][]base={
    
    
            {
    
    1,1},
            {
    
    1,0}
        }; 
        int [][] res = matrixPower(base,n-1);
        return res[0][0];
    }
    public int[][]matrixPower(int [][] m, int temp){
    
    
        int[][] ret = {
    
    {
    
    1, 0}, {
    
    0, 1}};
            while(temp!=0){
    
    
                // 如果对应二进制位为1 则乘进去
                if((temp&1)!=0){
    
     
                    ret = muliMatrix(ret, m);
                }
                m = muliMatrix(m, m);
                temp>>=1;
            }
        return ret;
    }
    public static int[][] muliMatrix(int[][] a, int[][] b) {
    
     
        int[][] c = new int[2][2];
        for (int i = 0; i < 2; i++) {
    
    
            for (int j = 0; j < 2; j++) {
    
    
                c[i][j] = (int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % 1000000007);
            }
        }
        return c;
    }
}

值得记忆

           //当二进制不为0时
            while(temp!=0){
    
    
                // 如果对应二进制位为1 则乘进去
                if((temp&1)!=0){
    
     
                    ret = muliMatrix(ret, m);
                }
                //如果二进制位为0,则自乘
                m = muliMatrix(m, m);
                // 右移
                temp>>=1;
            }

上楼问题

一个人可以一次往上迈1个台阶,也可以迈2个台阶

返回这个人迈上N级台阶的方法数


第n阶可以从n-1阶台阶到达,也可以从n-2阶台阶到达:

F(n)=F(n-1)+F(n-2)

若一个人一次可以上k步,p步,m步

求到N级台阶

F(n)=f(n-k)+f(n-p)+f(n-m)

矩阵为 max(k,p,m) * max(k,p,m)

母牛问题

第一年农场有1只成熟的母牛A,往后的每年:

1)每一只成熟的母牛都会生一只母牛

2)每一只新出生的母牛都在出生的第三年成熟

3)每一只母牛永远不会死

返回N年后牛的数量


n年的牛由n-1年牛的个数+n-3年牛个数(满三年都生一只小牛)

F(n)=F(n-1)+F(n-3)

字符问题

给定一个数N,想象只由0和1两种字符,组成的所有长度为N的字符串

如果某个字符串,任何0字符的左边都有1紧挨着,认为这个字符串达标

返回有多少达标的字符串


n位数,最左边一位为1有:F(n-1)种方法;最左边为0则倒数第二位必须为1,则有F(n-2)种方法

F(n)=F(n-1)+F(n-2)

瓷砖问题

用12的瓷砖,把N2的区域填满

返回铺瓷砖的方法数


第一个瓷砖竖着排,则后面有F(n-1)种方法;第一个瓷砖横着排,则后面有F(n-2)种方法

F(n)=F(n-1)+F(n-2)

参考

猜你喜欢

转载自blog.csdn.net/qq_41852212/article/details/121177853