目录
[1404. 将二进制表示减到 1 的步骤数](#1404. 将二进制表示减到 1 的步骤数)
[2460. 对数组执行操作](#2460. 对数组执行操作)
[2365. 任务调度器 II](#2365. 任务调度器 II)
[2109. 向字符串添加空格](#2109. 向字符串添加空格)
[LCR 002. 二进制求和](#LCR 002. 二进制求和)
[3688. 偶数的按位或运算](#3688. 偶数的按位或运算)
[2073. 买票需要的时间](#2073. 买票需要的时间)
[3834. 合并相邻且相等的元素](#3834. 合并相邻且相等的元素)
[2079. 给植物浇水](#2079. 给植物浇水)
1404. 将二进制表示减到 1 的步骤数
法一:用carry存储进位值(感觉跟高精度运算原理差不多)
cpp
class Solution {
public:
int numSteps(string s) {
int ans=s.size()-1;
int carry=0;
for(int i=s.size()-1;i>0;i--){
int sum=s[i]-'0'+carry;
ans+=sum%2;
carry=(sum+sum%2)/2;
}
return ans+carry;
}
};
注释详解版本:
cpp
class Solution {
public:
int numSteps(string s) {
//初始化:除了最高位不需要操作,其他位至少操作1次
int ans=s.size()-1;
//进位
int carry=0;
for(int i=s.size()-1;i>0;i--){
int sum=s[i]-'0'+carry;
//sum可以是0/1/2
//为什么要%2?
//sum是偶数时,不需要额外操作,ans+=0
//sum是奇数时,需要额外进位,ans+=1
ans+=sum%2;
//sum是0时,carry=0,不需要进位
//sum是1时,要先+1,这一位变成了2,所以要进1
//sum是2时,说明原位是1,进位是1,还要向更高位进位
//也可以写成:carry = (sum >= 1 ? 1 : 0);
carry=(sum+sum%2)/2;
}
//for中没有处理最高位,如果有进位的话,还需一次操作
return ans+carry;
}
};
当然,可以写成更易懂的代码:
cpp
class Solution {
public:
int numSteps(string s) {
int n=s.size();
int ans=n-1;
int carry=0;
for(int i=n-1;i>0;i--){
int bit=s[i]-'0';
int cur=bit+carry;
if(cur==1){
ans++;
}
if(cur>=1){
//必然产生进位,如果是1就要先+1,如果是2就要向更高位进位
carry=1;
}
else if(cur==0){
carry=0;
}
}
return ans+carry;
}
};
法二:暴力模拟,时O(N)
cpp
class Solution {
public:
int numSteps(string s) {
int ans = 0;
while (s != "1") {
ans++;
if (s.back() == '0') {
s.pop_back();
} else {
for (int i = s.size() - 1; i >= 0; i--) {
if (s[i] == '1') {
s[i] = '0';
if (i == 0) {
s = "1" + s;
break;
}
} else {
s[i] = '1';
break;
}
}
}
}
return ans;
}
};
2460. 对数组执行操作
cpp
class Solution {
public:
vector<int> applyOperations(vector<int>& nums) {
vector<int> ans;
for (int i = 0; i < nums.size() - 1; i++) {
if (nums[i] == nums[i + 1]) {
nums[i] *= 2;
nums[i + 1] = 0;
}
if(nums[i])ans.push_back(nums[i]);
}
ans.push_back(nums[nums.size() - 1]);
ans.resize(nums.size());
return ans;
}
};
2365. 任务调度器 II
暴力解法(超时):模拟冷却倒计时
缺点是每次都要维护所有状态
cpp
class Solution {
public:
long long taskSchedulerII(vector<int>& tasks, int space) {
long long ans=0;
unordered_map<int,int>map;
for(int t:tasks){
int days=map[t]+1;
ans+=days;
for(auto& [key,val]:map){
val=max(0,val-days);
}
map[t]=space;
}
return ans;
}
};
优化:只要记录对于某个任务t,下次最早可以执行是什么时候
cpp
class Solution {
public:
long long taskSchedulerII(vector<int>& tasks, int space) {
//day指当前日期
long long day=0;
//nextDay指该任务下一次可以执行的日期
unordered_map<int,long long>nextDay;
for(int t:tasks){
//若无限制,下一天(day+1)就可以执行
//若有限制,在nextDay[t]时才可以执行
day=max(day+1,nextDay[t]);
//该任务下一次可以执行的日期是day+space+1
nextDay[t]=day+space+1;
}
return day;
}
};
2109. 向字符串添加空格
直接模拟题意即可
主要掌握substr用法
cpp
class Solution {
public:
string addSpaces(string s, vector<int>& spaces) {
string ans=s.substr(0,spaces[0]);
for(int i=1;i<spaces.size();i++){
ans+=" ";
ans+=s.substr(spaces[i-1],spaces[i]-spaces[i-1]);
}
if(spaces[spaces.size()-1]!=s.size()){
ans+=" ";
ans+=s.substr(spaces[spaces.size()-1],s.size()-spaces[spaces.size()-1]);
}
return ans;
}
};
LCR 002. 二进制求和
按照题意暴力模拟
和高精度差不多,又是carry记录进位
cpp
class Solution {
public:
string addBinary(string a, string b) {
string ans = "";
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
int carry = 0;
int p = 0;
while (p < min(a.size(), b.size())) {
int cur = (a[p]-'0' )+ (b[p]-'0') + carry;
ans += to_string(cur % 2);
carry = cur / 2;
p++;
}
while (p < a.size()) {
int cur = (a[p]-'0') + carry;
ans += to_string(cur % 2);
carry = cur / 2;
p++;
}
while (p < b.size()) {
int cur = (b[p]-'0') + carry;
ans += to_string(cur % 2);
carry = cur / 2;
p++;
}
if(carry)ans+=to_string(carry);
reverse(ans.begin(), ans.end());
return ans;
}
};
或者p可以取高位,这样就不用反转a和b了
3688. 偶数的按位或运算
简单,不过要知道按位或的符号是|
cpp
class Solution {
public:
int evenNumberBitwiseORs(vector<int>& nums) {
int ans=0;
for(int i:nums){
if(i%2==0)ans=ans|i;
}
return ans;
}
};
2073. 买票需要的时间
队列模拟(注意下标不是i+1==k)
cpp
class Solution {
public:
int timeRequiredToBuy(vector<int>& tickets, int k) {
queue<pair<int,int>>q;
for(int i=0;i<tickets.size();i++){
if(i==k)q.push({tickets[i],1});
else q.push({tickets[i],0});
}
int ans=0;
while(!q.empty()){
auto t=q.front();
q.pop();
ans++;
t.first--;
if(t.second==1&&t.first==0)break;
if(t.first>0)q.push({t.first,t.second});
}
return ans;
}
};
3834. 合并相邻且相等的元素
用栈模拟(栈不一定要用stack,用vector也行)
先进后出
cpp
class Solution {
public:
vector<long long> mergeAdjacent(vector<int>& nums) {
vector<long long>ans;
for(int i:nums){
ans.push_back(i);
while(ans.size()>1&&ans[ans.size()-1]==ans[ans.size()-2]){
ans.pop_back();
ans[ans.size()-1]*=2;
}
}
return ans;
}
};
先出后进(注意i要设置为long long)
cpp
class Solution {
public:
vector<long long> mergeAdjacent(vector<int>& nums) {
vector<long long>ans;
for(long long i:nums){
while(!ans.empty()&&ans.back()==i){
ans.pop_back();
i*=2;
}
ans.push_back(i);
}
return ans;
}
};
2079. 给植物浇水
直接按照题意模拟
注意仔细讨论每种情况
cpp
class Solution {
public:
int wateringPlants(vector<int>& plants, int capacity) {
int ans = 0;
int cur = capacity;
int p = -1;
for (int i = 0; i < plants.size(); i++) {
if (p == -1) {
ans += i - p;
cur = capacity - plants[i];
p = i;
} else {
if (cur < plants[i]) {
ans += p + 1;
ans += i + 1;
p = i;
cur = capacity - plants[i];
} else {
ans += i - p;
cur -= plants[i];
p = i;
}
}
}
return ans;
}
};
优化:不用维护p,因为每次都是向右走
cpp
class Solution {
public:
int wateringPlants(vector<int>& plants, int capacity) {
int ans = 0;
int cur = capacity;
for (int i = 0; i < plants.size(); i++) {
if (cur < plants[i]) {
ans += i * 2;
cur = capacity;
}
cur -= plants[i];
ans++;
}
return ans;
}
};
