声明:因为是先在注释里面写了思路,要看思路的话看注释吧。就不搬出来了
第一题、三除数
链接:https://leetcode-cn.com/problems/three-divisors/
思路:
直接暴力循环,查找正除数的个数就可以了
代码实现:
class Solution {
public:
bool isThree(int n) {
int cur = 0 ;
for(int i = 1 ; i <= n ; ++ i)
cur += n % i == 0 ? 1 : 0 ;
return cur == 3 ;
}
};
第二题、你可以工作的最大周数
链接:https://leetcode-cn.com/problems/maximum-number-of-weeks-for-which-you-can-work/
思路:
根据每周切换项目的规则,可以借助阶段任务最多的项目完成多次切换。推导结果看代码注释
代码实现:
class Solution {
public:
long long numberOfWeeks(vector<int>& w) {
sort(w.begin() , w.end()) ;
long long sum = 0 , cur = 0 ;
for(auto &i : w)
sum += i ; //计算所有数的总和
cur = sum - w.back() ; //计算除了最大的数,其他数的和
if(cur < w.back()) //这是y + z + ... < x 的情况
return cur * 2 + 1 ;
return sum ; //否则返回sum即可
}
};
/*
x y z ....
x是最大的,判断是不是比其他的加起来都大
y + z + ... <= x 则最大结果为:(y + z) * 2 + 1
切换方法:一个x项目,一个其他项目,来回切换,最后可以再参与一次x项目
y + z + ... >= x 则最大结果为sum
切换方法,每个项目做一周,循环直到y + z + ... = x为止,然后一次其他项目,一次x项目来回切换直到所有项目完成
*/
第三题、收集足够苹果的最小花园
链接:https://leetcode-cn.com/problems/minimum-garden-perimeter-to-collect-enough-apples/
思路:
使用二分的方法枚举边长即可,具体细节看代码注释
代码实现:
typedef long long ll ;
class Solution {
public:
bool check(ll x , ll n){ //如果边长为x,苹果的总数>= n,返回ture,否则返回false
ll y = (x + 1) * x / 2 ;
ll tot = (2 * y + x * x) * (x + 1) * 2 ;
if(tot >= n)
return true ;
return false ;
}
long long minimumPerimeter(long long n) {
ll l = 0 , r = 1e6 + 10 ;
while(l < r){
ll mid = (l + r) / 2 ;
if(check(mid , n))
r = mid ;
else
l = mid + 1 ;
}
return l * 8 ;
}
};
/*
设x为正方形的边到(0,0)的距离
x:
(0,0) 1 2 3 4 5 ... x
1 2 3 4 5 6 ....x+1
2 3 4 5 6 7 ... x+2
3 x+3
4 x+4
5
.
.
.
x x+1 x+2 .... x+x
第1列苹果总和: (x + 1) * x / 2
第2列苹果总和: (x + 1) * x / 2 + x
第3列苹果总和: (x + 1) * x / 2 + 2 * x
...
第x列苹果总和: (x + 1) * x / 2 + x * x
设:y = (x + 1) * x / 2
那么y的负半轴上的苹果加上右下角的苹果的总和:tot = (y + y + x * x) * (x + 1) / 2 ;
那么整个土地的苹果总和为:ans = tot * 4
*/
第四题、统计特殊子序列的数目
链接:https://leetcode-cn.com/problems/count-number-of-special-subsequences/
思路:
使用动态规划,推导出状态转移方程,具体看代码注释
代码实现:
const int N = 1e5 + 10 ;
const int mod = 1e9 + 7 ;
class Solution {
int f[N][3] ;
/*
f[i][0] 表示0...0的子序列数
f[i][1] 表示0..01..1的子序列数
f[i][2] 表示0..01..12..2的子序列数
*/
public:
int countSpecialSubsequences(vector<int>& nums) {
int n = nums.size() ;
for(int i = 1 ; i <= n ; ++ i){
f[i][0] = f[i - 1][0] ; //继承i - 1的
f[i][1] = f[i - 1][1] ;
f[i][2] = f[i - 1][2] ;
if(nums[i - 1] == 0)
f[i][0] = (f[i - 1][0] * 2 + 1) % mod ;
/*
如果当前数字为0,那么f[i][0]有三种来源:
第一、由f[i - 1][0]的情况不变得来,情况数为f[i - 1][0]
第二、由f[i - 1][0]的情况后面加上一个0得来,情况数为f[i - 1][0]
第三、仅由当前这个0组成的子序列,情况数为1
*/
else if(nums[i - 1] == 1)
f[i][1] = ((f[i - 1][1] * 2) % mod + f[i - 1][0]) % mod ;
/*
如果当前数字为1,那么f[i][1]的来源有三种:
第一、由f[i - 1][1]的情况不变得来,情况数为f[i - 1][1]
第二、由f[i - 1][1]的情况后面加上当前这个1得来,情况数为f[i - 1][1]
第三、由f[i - 1][0]的情况后面加上当前这个1得来,情况数为f[i - 1][0]
*/
else
f[i][2] = ((f[i - 1][2] * 2) % mod + f[i - 1][1]) % mod ;
/*
如果当前数字为2,那么f[i][1]的来源有三种:
第一、由f[i - 1][2]的情况不变得来,情况数为f[i - 1][2]
第二、由f[i - 1][2]的情况后面加上当前这个2得来,情况数为f[i - 1][2]
第三、由f[i - 1][1]的情况后面加上当前这个2得来,情况数为f[i - 1][1]
*/
}
return f[n][2] ; //返回结果
}
};