简单
比特位计数
思路一
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
思路:
真的有人不知道斐波那契?
使用最小花费爬楼梯
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节阶梯跨两下。
那么就可以得到转移方程
但是这题不仅仅是求怎么来,还要求是体力消耗最小,所以需要在两种方式里取小。
除数博弈
class Solution {
public:
bool divisorGame(int n) {
if(n%2) return false;
else return true;
}
};
成绩:100 83
思路:
脑筋急转弯(不是)
第N个泰波那契数
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
;
像这种形态的数列,尽量用滚动变量,可以答复降低空间复杂度。
其他倒是没什么好说的。
获取生成数组中的最大值
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了。
下载插件
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带宽数;最后加一,即进行下载这一步。
按摩师
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-2
与dp[i-1]
,那么就不需要创建数组,直接用former和later滚动记录即可。
连续数列
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的核心思想去想这道题,具体思路之前做过那题写了,这次代码就是优化了一下。
三步问题
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
思路:
主要就是数据类型的处理,其他没啥