leetcode—动态规划

简单

比特位计数

leetcode直达

思路一

class Solution {
public:
    vector<int> countBits(int n) {
        if(!n) return {0};
        vector<int> res;
        res.resize(n+1);
        res[0] = 0;
        //res[1] = 1;
        for(int i = 1;i<=n;i++){
            int tmp = log2(i)-1;
            int tmpn = i^(2<<tmp);
            res[i] = 1+res[tmp];
        }
        return res;
    }
};

成绩:27 96
思路:
dp转移方程:
res[i] = { 0 ,i=0
1+res[i^(2<<(log2(i)-1))] i>0
这个其实很好理解,就是把最高位去掉(能去掉的一定是1),取找剩下的二进制数的“1”的个数。
思路二

class Solution {
public:
    vector<int> countBits(int n) {
        if(!n) return {0};
        vector<int> res;
        res.resize(n+1);
        res[0] = 0;
        //res[1] = 1;
        for(int i = 1;i<=n;i++){
            res[i] = 1+res[i&(i-1)];
        }
        return res;
    }
};

成绩:94 62
思路:
答题思路一样,但是有个最关键的地方不一样,就是在往回dp的时候,条件不一样。res[i] = 1+res[i&(i-1)];。这个能提高将近2/3的速度。

斐波那契数列

class Solution {
public:
    int fib(int n) {
        if(n == 0 || n == 1) return n;
        int former = 0;
        int later = 1;
        int count = n-1;
        while(count--){
            int tmp = later;
            later = former+later;
            former = tmp;
        }
        return later;
    }
};

成绩:100 73
思路:
真的有人不知道斐波那契?

使用最小花费爬楼梯

leetcode直达

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) { 
        int former = 0;
        int later = 0;
        for(int i = 2;i<=cost.size();i++){
            int tmp = later;
            later = min(former+cost[i-2],later+cost[i-1]);
            former = tmp;
        }
        return later;
    }
};

成绩:91 96
思路:
假设到达第i节阶梯需要消耗f(i)的体力,那么由题意可得有两种方式可以到达第i节阶梯:即从i-1节阶梯跨一下;从i-2节阶梯跨两下。
那么就可以得到转移方程
但是这题不仅仅是求怎么来,还要求是体力消耗最小,所以需要在两种方式里取小。

除数博弈

leetcode直达

class Solution {
public:
    bool divisorGame(int n) {
        if(n%2) return false;
        else return true;
    }
};

成绩:100 83
思路:
脑筋急转弯(不是)

第N个泰波那契数

leetcode直达

class Solution {
public:
    int tribonacci(int n) {
        int first = 0;
        int second = 1;
        int third = 1;
        if(!n) return 0;
        for(int i = 3;i<=n;i++){
            int tmp1 = second;
            int tmp2 = third;
            third = first+second+third;
            second = tmp2;
            first = tmp1;
        }
        return third;
    }
};

成绩:100 80.64
思路:
和斐波那契数列一样,无非这个是Tn+3 = Tn + Tn+1 + Tn+2
像这种形态的数列,尽量用滚动变量,可以答复降低空间复杂度。
其他倒是没什么好说的。

获取生成数组中的最大值

leetcode直达

class Solution {
public:
    int getMaximumGenerated(int n) {
        if(n==0 || n==1) return n;
        vector<int> res;
        res.resize(n+1);
        res[0] = 0;
        res[1] = 1;
        int MAX = 1;
        for(int i = 1;i<=n/2;i++){
            res[2*i] = res[i];
            if(2*i+1<=n){
            res[2*i+1] = res[i]+res[i+1];
            MAX = max({MAX,res[2*i],res[2*i+1]});
            continue;
            }
            MAX = max({MAX,res[2*i]});
        }
        return MAX;
    }
};

成绩:100 45
思路:
转移方程都写在题目里了,唯一要注意的就是算到哪一个数。for里面要加个判断,当n为偶数时就不能走完一个完整的for了。

下载插件

leetcode直达

class Solution {
public:
    int leastMinutes(int n) {
        if(!n) return 1;
        return ceil(log2(n))+1;
    }
};

成绩:100 34.05
思路:
也算是看了好几遍才看懂这道题的意思
每分钟都有两种选择:
1、不下载,带宽乘2
2、下载,带宽不变
最后选一种使下载最快的方案
语文看不懂,咱把它用数学语言来描述:
比较2n,n~2n,n的斜率。清楚了吧
所以只要求出ceil(log2(n)),此时我们就能求出刚好大于插件数的2n带宽数;最后加一,即进行下载这一步。

按摩师

leetcode直达

class Solution {
public:
    int massage(vector<int>& nums) {
        int len = nums.size();
        if(!len) return 0;
        int dp[len];
        dp[0] = nums[0];
        if(len == 1) return nums[0];
        dp[1] = max(nums[0], nums[1]);
        for(int i = 2;i<len;i++){
            dp[i] = max(dp[i-2]+nums[i], dp[i-1]);
        }
        return dp[len-1];
    }
};

空间优化

class Solution {
public:
    int massage(vector<int>& nums) {
        int len = nums.size();
        if(!len) return 0;
        if(len == 1) return nums[0];
        int former = nums[0];
        int later = max(nums[0], nums[1]);
        for(int i = 2;i<len;i++){
            int temp = later;
            later = max(former+nums[i], later);
            former = temp;
        }
        return later;
    }
};

从O(n)–>O(1)
成绩:100 63
思路:
令dp[i]为到第i个预约为止的最优解。
假设dp[i-1]已知,需要求dp[i]。有两种情况:
1、选择第i个预约,那么第i-1个预约就不能选择,即dp[i-2]+nums[i]
2、不选择第i个预约,即dp[i-1]
那么两者取max即为dp[i]
上述操作中我们可以看出,只有两个需要记录的变量,即dp[i-2dp[i-1],那么就不需要创建数组,直接用former和later滚动记录即可。

连续数列

leetcode直达

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size() == 0) return 0;
        int max = nums[0];
        for(int i = 1;i<nums.size();i++){
            if(nums[i-1]>0) nums[i] += nums[i-1];
            if(max<nums[i]) max = nums[i];
        }
        return max;
    }
};

成绩:90.36 92.60
思路:
我们要结合dp的核心思想去想这道题,具体思路之前做过那题写了,这次代码就是优化了一下。

三步问题

leetcode直达

class Solution {
public:
    int waysToStep(int n) {
        long dp[1000001];
        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 4;
        for(int i = 4;i<=n;i++){
            dp[i] = dp[i-1] + dp[i-2] +dp[i-3];
            dp[i] %= 1000000007;
        }
        return dp[n];
    }
};

成绩:63.05 40.90
思路:
主要就是数据类型的处理,其他没啥

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值