B站左程云算法视频中级班06

斐波那契数列

1 1 2 3 5 8 13

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

满足此类严格递归(无条件转移) 转换成O(logN)

斐波那契套路        复杂度O(logN)

1 1 2 3 5

[2 1]= [1 1] * \begin{bmatrix} 1 &1 \\ 1& 0 \end{bmatrix}

[F(N)        F(N-1)] = [F(2)           F(1)]   *   \begin{bmatrix} 1 &1 \\ 1& 0 \end{bmatrix}^{n-2}

\left | a \right |^{75} = \left | a \right |^{1001011}         设置 t  =   \left | a \right |^{1}      \left | a \right |^{2}       \left | a \right |^{4}     \left | a \right |^{8}      \left | a \right |^{16}      \left | a \right |^{32}      \left | a \right |^{64}

res = E*   \left | a \right |^{1}  *    \left | a \right |^{2}   *\left | a \right |^{8}*\left | a \right |^{64} 

 斐波那契公式 优化到O(logN)

 

public static int fi(int n){
    if (n < 1){
        return 0;
    }
    if(n == 1 || n == 2){
        return 1;
    }
    int[][] base = { {1, 1}, {1, 0} };
    int[][] res = matrixPower(base, n - 2);
    return res[0][0] + res[1][0];
}

public static int[][] matrixPower(int[][] m, int p){
    int[][] res = new int[m.length][m[0].length];
    for (int i = 0; i < res.length; i++){
        res[i][i] = 1;
    }
    int[][] t = m;
    for(; p != 0; p >>=1) {
        if ((p & 1) != 0){
            res = muliMatrix(res, t);
        }
        t = muliMatrix(t, t);
    }
    return res;
}

public static int[][] muliMatrix(int[][] m1, int[][] m2){
    int[][] res = new int[m1.length][m2[0].length];
    for (int i = 0; i < m1.length; i++){
        for(int j = 0; j < m2[0].length; j++){
            for(int k = 0; k < m2.length; k++){
                res[i][j] += m1[i][k] * m2[k][j];
            }
        }
    }
}

 

 推广

F(N) = 3F(N-1)-4F(N-3)+6F(N-5)

五阶矩阵

[F(N) ..... F(N-4)]   =  [F(5).....F(1)] *  \left | a \right |^{n-5}

题目:农场有一个牛,不会死,三年后产仔,问N年后有几只牛

A        AB         ABC          ABCD       ABCDEF    ABCDEFGHI

1          2            3                 4               6                   9

F(N)   = F(N-1) + F(N-3)        去年的加三年前的

三阶矩阵

题目:字符串只由0和1组成

当字符串长度为1时,所有可能的字符串为0和1

长度为2时,可能的字符串为00、01、10、11

如果某一个字符串中,只要出现0的位置,左边就靠着1,这样的字符串叫做达标字符串

给定一个正数N,返回所有长度为N的字符串中,达标字符串的数量

思路:i长度之前一定放着一个1字符

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

题目二:n根木棍,第i根木棍的长度为i,像选出骑着三根组成三角形。最少去掉多少根木棍,使得任意的三根木棍都不能组成三角形

给定N = 17

1  2  3  4  5  6  7  8  9  10  11  12  13   14  15  16   17

斐波那契数列 1   1   2  3  5   8   13  

去掉斐波那契数列外的木棍就是答案

证明:留下的数字abcdef   从小达大排序, 使得i位置的木棍 大于等于前两根相加   等于时候去掉的木棍最少

题目三:往背包里装一些零食,背包容量为w。家里一共有n袋零食,第i袋零食体积为v[i],想知道在总体积不超过背包容量的情况下,一共有多少种零食放法,总体积为0也算一种方法

假设背包容量为10,使用i位置的数和不用i位置的数

题目四:(IPO问题)有序表  先根据难度排序,由小到大,同样难度的工作在根据工作的报酬由大到小排。

保留每组的组长,在保留难度增加报酬也增加的工作,然后进行选择

public static class JobComparator implements Comparator<Job> {
    public int compare(Job o1, Job o2){
        return o1.hard != o2.hard ? (o1.hard - 02.hard) : (o2.money - o1.money);
    }
}

public static int[] getMoneys(J0b[] job, int[] ability){
    Arrays.sort(job, new JobComparator());
    //难度为key的工作,最优钱数是多少,有序表
    TreeMap<Integer, Integer> map = new TreeMap<>();
    map.put(job[0].hard, job[0].money);
    Job pre = job[0]; // pre之前组的组长
    for(int i = 1; i < job.length; i++){
        if (job[i].hard != pre.hard && job[i].money > pre.money) {
            pre = job[i];
            map.put(pre.hard, pre.money);
        }
    }
    int[] ans = new int[ability.length];
    for (int i = 0; i < ability.length; i++){
        Integer key = map.floorKey(ability[i]);
        ans[i] = key != null ? map.get(key) : 0;
    }
    return ans;
}

题目五:给定一个字符串,如果该字符串符合人们日常书写一个整数的形式,返回int类型的这个数;如果不符合或者越界返回-1或者报错

总结:   1)数字字符外只允许出现"-"

              2)如果有-,只允许在开头出现一次,且后面必须跟着不为0的数字字符

              3)如果开头第一个字符为0.后续必须没有数字

public static boolean isValid(char[] str){
    if (syr[0] != '-' && (str[0] < '0' || str[0] > '9')){
        return false;
    }
    // 1) str[0] == '-' && str.length == 1
    // 2) str[0] == '-' && str.length != 1 && str[1] == '0'
    if (str[0] == '-' && (str.length == 1 || str[1] == '0')){
        return false;
    }
    if (str[0] == '0' && str.length > 1){
        return false;
    }
    for (int i = 1; i < str.length; i++){
        if (str[i] < '0' || str[i] > '9'){
            return false;
        }
    }
    return true;
}

判断的时候用负数接这个值,因为负数的范围比正数大

public static int convert(String s){
    if(s == null || s.equals("")){
        return 0; // can not convert
    }
    char[] str = s.toCharArray();
    if (!isValid(str)){
        throw new RuntimeException("can not convert");
    }
    boolean nef = str[0] == '-' ? true : false;
    int minq = Integer.MIN_VALUE / 10;
    int minr = Integer.MIN_VALUE % 10;
    int res = 0;
    int cur = 0;
    for (int i =neg ? 1 : 0; i < str.length; i++){
        cur = '0' - str[i];
        //中途转化过程中,溢出的时候
        if ((res < minq) || (res == minq && cur < minr)) {
            throw new RuntimeException("can not convert");
        }
        res = res * 10 + cur;
    }
    //res是,转化数字绝对值的负数表达
    if (!neg && res == Integer.MIN_VALUE){
        throw new RuntimeException("can not convert");
    }
    return neg ? res : -res;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值