2023寒假训练week3
Day1
2023牛客寒假算法基础集训营4
A.清楚姐姐学信息论
1.看懂题目,看出规律
2.求导
#include<iostream> using namespace std; int main() { long long x,y; cin>>x>>y; if(x==3||y==3)cout<<3; // 3的时候效率最大 else cout<<min(x,y); }
L.清楚姐姐的三角形I
给定三个数,两两相加已知。判断他们能否组成三角形
#include<bits/stdc++.h> using namespace std; signed main() { int t; cin>>t; while(t--) { int a,b,c; cin>>a>>b>>c; int sum = (a+b+c)/2; int la = ((b+c) - a)/2; //a的长度 int lb = ((a+c) - b)/2; int lc = ((a+b) - c)/2; if (la <= 0 || lb <= 0 || lc <= 0 || ((b+c) - a) % 2!=0) {//不能是奇数,每条边不能小于0 cout << "No"<<endl; }else if(la + lb <= lc || la + lc <= lb || lb + lc <= la){//两边之和大于第三边 cout<<"No"<<endl; }else if(abs(la - lb) >= lc || abs(la - lc) >= lb || abs(lb - lc) >= la){//三角形两边之差小于第三边 cout<<"No"<<endl; }else{ cout<<"Yes"<<"\n"<<la<<" "<<lb<<" "<<lc<<endl; } } }
M.清楚姐姐的三角形II
1.相邻三项一定不能组成三角形
2.只要满足两边之和等于第三边就可以
循环输出112显然不错
#include<bits/stdc++.h> using namespace std; int main() { int n,i; cin>>n; long long a[n]; a[0]=1; a[1]=1; a[2]=2; for(i=0;i<n;i++) { a[i]=a[i%3]; cout<<a[i]<<" "; } return 0; }
每日一题【模板】并查集
完成合并和查询操作
#include<bits/stdc++.h> using namespace std; const int N=1e5; int n,m,z; int fa[N]; int find_(int x)//返回x的祖宗结点 { if(fa[x]!=x) fa[x]=find_(fa[x]);//如果x不等于祖宗结点 return fa[x];//让他找到x的根节点,并让x等于他的根结点 } void union_(int x,int y) { fa[find_(x)]=find_(y);//让x的祖宗结点等于y的祖宗结点 } int main() { cin>>n>>m; //初始化 for(int i=0;i<n;i++) fa[i]=i; int x,y; for(int i=0;i<m;i++) { cin>>z; cin>>x>>y; if(z==1){ union_(x,y); } else{ if(find_(x)==find_(y)){ cout<<"Y"<<endl; } else{ cout<<"N"<<endl; } } } return 0; }
Day2
洛谷P1551 亲戚(并查集)
#include<bits/stdc++.h> using namespace std; const int N=1e5; int n,m,p; int fa[N]; int find(int x)//返回x的祖宗结点 { if(fa[x]!=x) fa[x]=find(fa[x]);//如果x不等于祖宗结点 return fa[x];//让他找到x的根节点,并让x等于他的根结点 } void union_(int x,int y) { fa[find(x)]=find(y);//让x的祖宗结点等于y的祖宗结点 } int main() { cin>>n>>m>>p; for(int i=0;i<n;i++) fa[i]=i; while(m--) { int m1,m2; cin>>m1>>m2; union_(m1,m2); } while(p--) { int p1,p2; cin>>p1>>p2; if(find(p1)==find(p2)) { cout<<"Yes"<<endl; } else { cout<<"No"<<endl; } } return 0; }
洛谷P1196 [NOI2002] 银河英雄传说
ACwing数组元素的目标和(双指针)
找出两个升序数组,满足a[i]+b[j]=x的数对(i, j)
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=1e5+100; LL a[N],b[N]; int main() { int n,m,x; cin>>n>>m>>x; for(int i=0;i<n;i++) cin>>a[i]; for(int i=0;i<m;i++) cin>>b[i]; //均升序 for(int i=0,j=m-1;i<n;i++){ while(j>=0&&a[i]+b[j]>x) j--; if(a[i]+b[j]==x){ cout<<i<<" "<<j<<endl; break; } } return 0; }
ACwing判断子序列(双指针)
请你判断a序列是否为b序列的子序列
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int a[N],b[N]; int main() { int n,m; cin>>n>>m; for(int i=0;i<n;i++) cin>>a[i]; for(int i=0;i<m;i++) cin>>b[i]; int i=0,j=0; while(i<n&&j<m){ if(a[i]==b[j]) i++; //匹配到一组,i++到下一个数 j++; //不管有没有匹配,j都要到下一个数 } if(i==n) cout<<"Yes"<<endl; else cout<<"No"<<endl; return 0; }
ACwing最长连续不重复子序列(双指针)
一段长度为n的序列,要求找出最长的不重复子序列
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int a[N]; int s[N]; int main() { int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; int res=0; for(int i=0,j=0;i<n;i++) { s[a[i]]++; //当a[i]>1就说明a[i]不只出现1次,有重复 while(s[a[i]]>1) { s[a[j]]--; j++; //j从左开始,依次弹出a[j],直到重复元素a[i]。 } res=max(res,i-j+1); } cout<<res<<endl; return 0; }
ACwing区间和(离散化、前缀和)
1.离散化存储每个数据
2.前缀和求区间和
#include<bits/stdc++.h> using namespace std; const int N = 300010; //n次插入和m次查询相关数据量的上界 int n, m; int a[N];//存储坐标插入的值 int s[N];//存储数组a的前缀和 vector<int> alls; //存储(所有与插入和查询有关的)坐标 vector<pair<int, int>> add, query; //存储插入和询问操作的数据 int find(int x) { //返回的是输入的坐标的离散化下标 int l = 0, r = alls.size() - 1; while (l < r) { int mid = l + r >> 1; if (alls[mid] >= x) r = mid; else l = mid + 1; } return l; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { int x, c; scanf("%d%d", &x, &c); add.push_back({x, c}); alls.push_back(x); } for (int i = 1; i <= m; i++) { int l , r; scanf("%d%d", &l, &r); query.push_back({l, r}); alls.push_back(l); alls.push_back(r); } //排序,去重 sort(alls.begin(), alls.end()); alls.erase(unique(alls.begin(), alls.end()), alls.end()); //执行前n次插入操作 for (auto item : add) { int x = find(item.first); a[x] += item.second; } //前缀和 for (int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i]; //处理后m次询问操作 for (auto item : query) { int l = find(item.first); int r = find(item.second); printf("%d\n", s[r] - s[l-1]); } return 0; }
ACwing数n的二进制表示中n的第k位是几
- 将n右移k位(将n的第k位移到最后一位)
n>>k ; - n的最后一位是几
n & 1 ;
10的二进制表示
#include<bits/stdc++.h> using namespace std; int main() { int n=10; for(int k=3;k>=0;k--) cout<<(n<<k)&1; return 0; }
二进制表示中n的第k位是几
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; int k; cin>>K; cout<<(n<<k)&1; }
ACwing二进制中1的个数
lowbit(x)操作返回x的最后一位1
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long long LL; int lowbit(int x) { return x&-x; } int main() { int n; cin>>n; while(n--){ int x; cin>>x; int res=0; while(x){ x-=lowbit(x); //x-x的最后一位1直到把1都减无 res++; } cout<<res<<" "; } return 0; }
ACwing区间合并
1.要求合并所有有交集的区间
2.输出合并完成后的区间个数
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef pair<int,int>PII; vector<PII>segs; int n; void merge(vector<PII> &segs){ vector<PII> res; // 左端点排序 sort(segs.begin(), segs.end()); // 左右端点初始化,-无穷 int start = -2e9, end = -2e9; for(auto seg: segs){ if(end < seg.first){ // 初始的[-无穷,-无穷]区间要跳过,不能装入 if(start != -2e9) res.push_back({start, end}); start = seg.first, end = seg.second; } else end = max(end, seg.second); } // 有两个作用,1.是防止n为0,把[-无穷,-无穷]压入;2.是压入最后一个(也就是当前)的区间,若n>=1,if可以不要 if (start != -2e9) res.push_back({start, end}); //覆盖segs segs = res; } int main() { cin>>n; for(int i=0;i<n;i++){ int l,r; cin>>l>>r; segs.push_back({l,r}); } merge(segs); cout<<segs.size()<<endl; return 0; }
ACwing滑动窗口(单调队列)
1.
确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
2.因为窗口位三个数,后面进来的数一定比前面进来的数后出。因此以最大值为例,若后一个
入队的数比前一个入队的数大,则前面的数永远没有出头之日,要被弹出队列。
双端队列版本:
双端队列相当于加强版vector,支持前后端弹出缺点就是比较慢
使用它主要是因为有clear()操作
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int a[N]; int main() { int n, k; cin >> n >> k; for (int i = 1; i <= n; i ++ ) cin >> a[i];//读入数据 deque<int> q; for(int i = 1; i <= n; i++) { while(!q.empty()&& q.back() > a[i]) //新进入窗口的值小于队尾元素,则队尾出队列 q.pop_back(); q.push_back(a[i]);//将新进入的元素入队 if(i - k >= 1 && q.front() == a[i - k])//若队头是否滑出了窗口,队头出队 q.pop_front(); if(i >= k)//当窗口形成,输出队头对应的值 cout << q.front() <<" "; } q.clear(); cout << endl; //最大值亦然 for(int i = 1; i <= n; i++) { while(!q.empty()&& q.back() < a[i]) q.pop_back(); q.push_back(a[i]); if(i - k >= 1 && a[i - k] == q.front()) q.pop_front(); if(i >= k) cout << q.front() << " "; } }
Day3
SMU Winter 2023 Round #9 (Div.2)
A. Who is The 19th ZUCCPC Champion
随便输出一个字符串就行。
#include<bits/stdc++.h> using namespace std; int main(){ cout<<"Ranni the Witch\n"; return 0; }
B. Jiubei and Overwatch
- t<=k,damage=tx;
- t>k,damage=kx+(t-k)y;
当时间小于k的时候,就是t倍的x。超过k的话,超过多少就加多少倍的y。
排序找出最大的防御力的怪物,因为同时攻击,最大的灭了,其他小的自然就灭了。
分成两部分求解: - 没超过k
- 超过k
#include<bits/stdc++.h> using namespace std; const int N=101; int n,k,x,y; int a[N]; void sovle() { cin>>n>>k>>x>>y; for(int i=0;i<n;i++) cin>>a[i]; sort(a,a+n,greater<int>()); // cout<<a[0]<<endl; for(int t=1;;t++){ if(t<=k) { int dam=t*x; if(a[0]<=dam) { cout<<t<<endl; break; } } else{ int dam=k*x+(t-k)*y; if(a[0]<=dam) { cout<<t<<endl; break; } } } } int main() { int _; cin>>_; while(_--){ sovle(); } }
C. Ah, It's Yesterday Once More
交换排序:
for(i->n) for(j->n) if(ai<aj) swap(ai,aj);
冒泡排序:
for(i->n) for(j->n-1) if(aj>a(j+1)) swap(ai,a(j+1));
题目要求找出全排列数组a,使得冒泡排序和交换排序的交换次数相同。
显然倒序输出的时候相同。
#include<bits/stdc++.h> using namespace std; const int N=1e5+100; void sovle() { int n; cin>>n; for(int i=n;i>0;i--) { cout<<i<<" "; } cout<<endl; } int main() { int _; cin>>_; while(_--){ sovle(); } }
F. Sum of Numerators
将分数化简到最小的分子相加。
1.奇数时:分子直接相加
2.偶数时:分子不断除2
3.找规律
#include<bits/stdc++.h> using namespace std; typedef long long int ll; ll t; ll n,k; int main(){ scanf("%lld",&t); while(t--){ scanf("%lld%lld",&n,&k); ll sum=n*(n+1)/2; //等差数列前n项和,未经处理的分子的和。 while(n&&k){ n/=2; //会被约分的数字个数每次都是总长的一半 k--; //每次被约分,2的次数减一 sum-=n*(n+1)/2; //每次被约分掉的总和是等差数列求1到被约分掉的数字个数之和。 } printf("%lld\n",sum); } return 0; }
L. Monster Tower
塔高为n,每层都有一个怪物,怪物能量为ai,找出初始的攻击力x最小可以为多少。
1.每次只能在1~k层攻击怪物,每次消灭掉怪物i之后,自身的攻击力将会提升ai
2.消灭掉这一层怪物后,这一层会消失,这层往上的层数会逐层-1
思路:
打怪的顺序是唯一的,所以维护一个有 k 个元素的小根堆,每次处理最小的元素,如果现有能力值大于怪的能力值,加上怪的能力值,否则更新初始值;
每遇到一个打不过的怪,最小可能初始值 = 怪的能力值-前面获得的能力值总和,用这个值去更新之前的 初始值,取其中大的;
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6+100; ll t,n,k; ll a[N]; priority_queue<ll,vector<int>,greater<int> >pmin; ll sta,now; int main() { cin>>t; while(t--) { cin>>n>>k; sta=0;now=0; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=1;i<=n;i++)//每个堆里只有k个元素 { if(pmin.empty()||pmin.size()<k) pmin.push(a[i]);//注意判空 else { ll s=pmin.top(); pmin.pop(); if(now>=s) { now+=s; }//总能力值大于怪的能力值 else { sta=max(sta,s-now); now+=s; }//更新初始值,注意更新方式 pmin.push(a[i]); } } while(!pmin.empty())//清空堆 { ll s=pmin.top(); pmin.pop(); if(now>=s) { now+=s; } else { sta=max(sta,s-now); now+=s; } } cout<<sta<<endl; } return 0; }
Day4
洛谷P1111 修复公路(并查集)
#include<bits/stdc++.h> using namespace std; const int N=1e6; int fa[N],num,ans; struct node{ int x,y,t; }e[N]; bool operator<(node a,node b){//重载小于运算符 return a.t<b.t; } int find(int x) { if(fa[x]!=x) { fa[x]=find(fa[x]); } return fa[x]; } void union_(int x,int y,int t) { if(find(x)==find(y)); else{ fa[find(x)]=find(y); num++; ans=max(ans,t); } } int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { cin>>e[i].x>>e[i].y>>e[i].t; } sort(e+1,e+m+1);//按照时间排序 for(int i=1;i<=m;i++) union_(e[i].x,e[i].y,e[i].t);//按时间大小合并 if(num!=n-1) cout<<-1<<endl; else cout<<ans<<endl; return 0; }
leetcode242.有效字母异位词(数组哈希)
class Solution { public: bool isAnagram(string s, string t) { if(s.size()!=t.size())return 0; int res[26]; for(int i=0;i<26;i++) res[i]=0; for(int i=0;i<s.size();i++){ res[s[i]-'a']++; } for(int i=0;i<t.size();i++){ res[t[i]-'a']--; } for(int i=0;i<26;i++){ if(res[i]){ return 0; } } return 1; } };
leetcode349.两数组的交集(set哈希)
1.用unodered_set模拟hash处理
2.用数组模拟hash处理
法1:
class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int>result;//存放交集 unordered_set<int> num_set(nums1.begin(),nums1.end());//直接将num1转化为unoderde_set类型 for(int num : nums2)//看num2里的元素是否在num1中出现 { if(num_set.find(num)!=num_set.end())//如果找不到对应元素,返回的是末尾的迭代器。 { result.insert(num); } } return vector<int>(result.begin(),result.end()); } };
法2:
class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int>result;//存放交集 int hash[1005]={0};//hash数组,初始化为0 for(int num : nums1) { hash[num]=1; } for(int num : nums2) { if(hash[num]){ result.insert(num);//nums2的元素出现过,直接插入result中 } } return vector<int>(result.begin(),result.end()); } };
leetcode1.两数之和(map哈希)
找出和为目标值target的那两个整数,并返回它们的数组下标。
num1+num2=target
1.key值存放num2,value存放下标。
2.遍历num1,看看map中是否存储了num2,防止重复计算。
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map <int,int> map;//无序,first存储数值,second存储下标 for(int i=0;i<nums.size();i++){//查询map中是否有相加等于target的元素 auto it=map.find(target-nums[i]); if(it!=map.end())//map中,找得到和为target的另一个数的下标 return {it->second,i}; // 如果没找到匹配对,就把访问过的元素和下标加入到map中 map.insert(pair<int,int>{nums[i],i}); } return {}; } };
leetcode454.四数相加(II)(map哈希)
给定四个数组,求num1[i]+num2[j]+num3[k]+num4[l]=target,一共有几种方法
1.朴素写法
class Solution { public: int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { unordered_map<int,int>map; for(int i=0;i<nums1.size();i++){//将nums1+nums2的值存在map中 for(int j=0;j<nums2.size();j++){ map[nums1[i]+nums2[j]]++; } } int conut=0; for(int i=0;i<nums3.size();i++){ for(int j=0;j<nums4.size();j++){ auto it=-(nums3[i]+nums4[j]); if(map.find(it)!=map.end()){//找到了 conut+=map[it]; } } } return conut; } };
2.优化
class Solution { public: int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { unordered_map<int,int>map; for(int i : nums1){//将nums1+nums2的值存在map中 for(int j : nums2){ map[i+j]++; } } int conut=0; for(int i : nums3){ for(int j : nums4){ auto it=-(i+j); if(map.find(it)!=map.end()){//找到了 conut+=map[it]; } } } return conut; } };
leetcode15.三数之和(双指针)
1.给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c 。使得 a
+b+c=0请你找出所有满足条件且不重复的三元组。
2.答案中不可以包含重复的三元组。
详细介绍:
例如答案为:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
这题的麻烦主要时去重
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(),nums.end());//排序 vector<vector<int>> result; for(int i=0;i<nums.size();i++){ if(nums[i]>0) return result;//最小的数大于0,说明不管怎相加都不会等于0 if(i>0&&nums[i]==nums[i-1])//去重复 continue; int l=i+1; int r=nums.size()-1; while(l<r){ if(nums[i]+nums[l]+nums[r]>0){ r--; } else if(nums[i]+nums[l]+nums[r]<0){ l++; } else{ result.push_back(vector<int>{nums[i] ,nums[l] ,nums[r]}); //接下来要对l和r去重 while(l<r&&nums[l]==nums[l+1]) l++; while(l<r&&nums[r]==nums[r-1]) r--; //找到result后,将l和r收缩 l++; r--; } } } return result; } };
leetcode18.四数之和(双指针)
1.剪枝
2.去重
3.三数之和
class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> result; sort(nums.begin(),nums.end()); for(int a=0;a<nums.size();a++){ if(nums[a]>0&&target>0&&nums[a]>target){//剪枝 break; } if(a>0&&nums[a]==nums[a-1]){//对a去重 continue; } for(int b=a+1;b<nums.size();b++){//剪枝 if(nums[b]+nums[a]>0&&target>0&&nums[a]+nums[b]>target){ break; } if(b>a+1&&nums[b]==nums[b-1]){//对b去重 continue; } int c=b+1,d=nums.size()-1; while(c<d){ // nums[a] + nums[b] + nums[c] + nums[d] > target 会溢出 if((long)nums[a]+nums[b]+nums[c]+nums[d]>target) d--; else if((long)nums[a]+nums[b]+nums[c]+nums[d]<target) c++; else{ result.push_back(vector<int>({nums[a],nums[b],nums[c],nums[d]})); //获得答案之后对c和d进行去重 while(c<d&&nums[c]==nums[c+1]) c++; while(c<d&&nums[d]==nums[d-1]) d--; //获得答案后将范围收缩 c++; d--; } } } } return result; } };
leetcode344.反转字符串(I)(双指针)
要求空间复杂度o(1)即不能另外开一个字符串,而改变s字符串的值
class Solution { public: void reverseString(vector<char>& s) { char t; for(int i=0,j=s.size()-1;i<j;i++,j--){ t=s[j]; s[j]=s[i]; s[i]=t; } } };
leetcode541.反转字符串(II)(双指针)
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
1.可以自己写一个反转函数
class Solution { public: string reverseStr(string s, int k) { for(int i=0;i<s.size();i+=(2*k)){ // 以2k间距来操作 if(i+k<=s.size()){ //i后面字符大于k个,反转k个字符 for(int j=i,l=i+k-1;j<l;j++,l--){//注意在[i,i+k)区间内反转 char t=s[j]; s[j]=s[l]; s[l]=t; } continue; } else{ //到最后,i后面的字符小于k个 for(int j=i,l=s.size()-1;j<l;j++,l--){ char t=s[j]; s[j]=s[l]; s[l]=t; } } } return s; } };
2.可以用stl函数
class Solution { public: string reverseStr(string s, int k) { for(int i=0;i<s.size();i+=(2*k)){ // 以2k间距来操作 if(i+k<=s.size()){ //i后面字符大于k个,反转k个字符 reverse(s.begin() + i, s.begin() + i + k ); continue; } else{ //到最后,i后面的字符小于k个 reverse(s.begin() + i, s.end()); } } return s; } };
Day6
洛谷P1536 村村通(并查集)
#include<bits/stdc++.h> using namespace std; const int N=1e5; int n,m; int fa[N]; int find(int x)//返回x的祖宗结点 { if(fa[x]!=x) fa[x]=find(fa[x]);//如果x不等于祖宗结点 return fa[x];//让他找到x的根节点,并让x等于他的根结点 } void union_(int x,int y) { fa[find(x)]=find(y);//让x的祖宗结点等于y的祖宗结点 } int main() { while(1) { cin>>n; if(n==0) return 0; cin>>m; for(int i=1;i<=n;i++) fa[i]=i;//城镇 while(m--) { int m1,m2; cin>>m1>>m2;//由这条道路相连的城镇编号 union_(m1,m2); } int ans=0; for(int i=1;i<=n;i++) { if(find(i)==i) { ans++; } } cout<<ans-1<<endl; } return 0; }
leetcode27. 移除元素(双指针)
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
class Solution { public: int removeElement(vector<int>& nums, int val) { int slow=0; for(int fast=0;fast<nums.size();fast++){ if(nums[fast]!=val){ //快指针的值不等于val时将元素的值赋给nums[slow] nums[slow]=nums[fast]; slow++; //慢指针移动 } } return slow; } };
leetcode151. 反转字符串中的单词(双指针)
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: " hello world! "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
一定要记得resize操作
class Solution { public: string reverseWords(string s) { //空格移除操作 int slow=0;//慢指针 for(int fast=0;fast<s.size();fast++){//快指针 if(s[fast]!=' ')//如果fast指向的元素不为空格 { if(slow!=0)//如果slow指向的元素不为首元 { s[slow]=' ';//就在单词前加空格 slow++; } while(fast<s.size()&&s[fast]!=' ')//当在数组内,且不等于空格时 { s[slow]=s[fast];//覆盖 slow++; fast++; } } } s.resize(slow); //slow的大小即为去除多余空格后的大小。 //反转操作,先反转整个句子,再逐个反转单词 for(int i=0,j=s.size()-1;i<j;i++,j--) { char t=s[i]; s[i]=s[j]; s[j]=t; } int st=0;//起始的单词字母在0处 for(int i=0;i<=s.size();i++){ if(s[i]==' '||i==s.size()){ //到达单词结尾 for(int l=st,r=i-1;l<r;l++,r--){ char t=s[l]; s[l]=s[r]; s[r]=t; } st=i+1; //新单词的起始位置 } } return s; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效