签到题,简单来说就是一共三个数,有两个操作:1,一个数减一;2,两个数减一;
问最少操作多少次使三个数都为0。
最直观的想法就是每次都对三个数排序,每次都进行第二种操作,最后第一种操作;
故代码如下:
class Solution {
public:
int fillCups(vector<int>& amount) {
int res=0;
while(amount[0]+amount[1]+amount[2])
{
sort(amount.begin(),amount.end());//排序
amount[2]--;//最大数减一
if(amount[1]) amount[1]--;//次大数非0减一
res++;
}
return res;
}
};
下面讲讲对上述的优化
第一步还是对三个数进行排序,假设最大数a[2],次大数a[1],最小数a[0],根据对问题的考虑可以将三个数分成两种情况;
1,a[2]>a[0]+a[1],最大数大于剩余两数之和,所以答案就是a[2],因为这里每次都能进行第二种操作,最后又回到操作最大数剩余的数上,所以此时答案就是a[2]。
2,a[2]<=a[0]+a[1],这种情况的话就是保证了每次都能进行第二次操作,除了最后一次以外,故最后答案为(a[2]+a[0]+a[1])/2(上取整)
综上,代码如下:
class Solution {
public:
int fillCups(vector<int>& a) {
sort(a.begin(),a.end());
if(a[2]>a[0]+a[1]) return a[2];
return (a[0]+a[1]+a[2]+1)/2;
}
};
第二题:2336. 无限集中的最小数字
问题在于维护一个集合,初始为正整数的集合,共两个操作;
1,移除并返回最小整数
2,添加一个数
且操作次数只有1000次,故选择定义一个set自动排序和判重
代码如下:
class SmallestInfiniteSet {
public:
set<int> S;
SmallestInfiniteSet() {
for(int i=1;i<=1000;i++)
S.insert(i);
}
int popSmallest() {
int t=*S.begin();
S.erase(S.begin());
return t;
}
void addBack(int num) {
S.insert(num);
}
};
第三题:2337. 移动片段得到字符串
下图为原题题意和样例
先分析一下问题,要想答案为true,首先要求start与target的长度一致,且相对数据不变即L和R不能相互跨越,代码如下,详细注释在代码中体现:
class Solution {
public:
bool canChange(string a, string b) {
int n=a.size();
int j=0;//开辟双指针
for(int i=0;i<n;i++)
{
if(a[i]=='_') continue;//空位跳过
while(j<n&&b[j]=='_') j++;//j也相同,在不越界的情况下空位跳过
if(j==n) return false;//j等于n表示没有字符互相对应
if(a[i]!=b[j]) return false;//同上
if(a[i]=='L'&&i<j) return false;
if(a[i]=='R'&&i>j) return false;
j++;
}
for(int i=j;j<n;j++)
{
if(b[i]!='_') return false;//判断第二串有没多一些字符
}
return true;
}
};
第四题:2338. 统计理想数组的数目
给定n,m要求数组大小在n和m之间且每一个数是前面一个数的倍数,求方案数量。
题目给定的数据范围较小,m最大10000,所以数据限制在2的0次方到2的13次方8192之间。
我们假定数组中所有数字不同,则序列长度最后长度只有14,暴搜能过
class Solution {
public:
int n,m;
int ans=0;
const int MOD=1e9+7;
vector<vector<int>> f;
void dfs(int u,int cnt)
{
ans=(ans+f[n-1][cnt-1])%MOD;
if(cnt<n){
for(int i=2;i*u<=m;i++)
{
dfs(i*u,cnt+1);
}
}
}
int idealArrays(int n, int m) {
this->n=n,this->m=m;
f=vector<vector<int>>(n,vector<int>(20));
for(int i=0;i<n;i++)
for(int j=0;j<20&&j<=i;j++)
{
if(!j) f[i][j]=1;
else f[i][j]=(f[i-1][j] + f[i-1][j-1]) % MOD;
}
for(int i=1;i<=m;i++) dfs(i,1);
return ans;
}
};
下面看看dp怎么写
class Solution {
public:
int idealArrays(int n, int m) {
const int MOD=1e9+7;
vector<vector<int>> f(m+1,vector<int>(15));
for(int i=1;i<=m;i++) f[i][1]=1;
for(int j=1;j<14;j++)
for(int i=1;i<=m;i++)
for(int k=2;k*i<=m;k++)
f[k*i][j+1]=(f[k*i][j+1]+f[i][j])%MOD;
vector<vector<int>> C(n,vector<int>(15));
for(int i=0;i<n;i++)
for(int j=0;j<=i&&j<=14;j++)
if(!j) C[i][j]=1;
else C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
int res=0;
for(int i=1;i<=m;i++)
for(int j=1;j<=14&&j<=n;j++)
res=(res+(long long)f[i][j]*C[n-1][j-1])%MOD;
return res;
}
};
这里还涉及了组合数的运用,但算法基础课还没刷完,最后一题能理解的有限,上述代码参考yxc大佬