A:水题
1 class Solution { 2 public: 3 int sumBase(int n, int k) { 4 int res=0; 5 while(n){ 6 res+=n%k; 7 n/=k; 8 } 9 return res; 10 } 11 };
B:给定一个数组和一个可操作次数,每次操作可将某一个元素加一,问操作之后的最大的频数数目是多少。
数组排序之后。
性质一:答案的最终频数一定可以是原数组中的数
性质二:对于一个确定的目标,在往左寻找最大频数的过程中操作次数单调增加
二分解法
对于一个 i(目标) 和 j(左端)操作次数等于 (a [ i ] - a [ j ] ) + (a [ i ] - a [ j+1 ] ) + ....+(a [ i ] - a [ i ] ) = (j-i+1) a[i] - ( a[j]+a[j+1]+...+a[i] )
后者可用前缀和进行计算
1 typedef long long LL; 2 class Solution { 3 public: 4 vector<LL> s; 5 LL get_op(int i,int j,vector<int>&nums){ 6 return nums[j]*(j-i+1ll)-(s[j+1]-s[i]); 7 } 8 int maxFrequency(vector<int>& nums, int k) { 9 sort(nums.begin(),nums.end()); 10 s.resize(nums.size()+1); 11 for(int i=1;i<=nums.size();i++) s[i]=s[i-1]+nums[i-1]; 12 int res=0; 13 for(int i=0;i<nums.size();i++){ 14 int l=0,r=i; 15 while(l<r){ 16 int mid=l+r>>1; 17 if(get_op(mid,i,nums)<=k){ 18 r=mid; 19 }else{ 20 l=mid+1; 21 } 22 } 23 res=max(res,i-l+1); 24 } 25 return res; 26 } 27 };
设定i为区间左端点,j为区间右端点,将区间内全部的数变成nums [ j ] ,操作次数小于k
性质三:当 j 往右移动,左端点 i 同时跟着往右移动
双指针算法
计算操作次数同样用前缀和
1 typedef long long LL; 2 class Solution { 3 public: 4 vector<LL> s; 5 LL get_op(int i,int j,vector<int>&nums){ 6 return nums[j]*(j-i+1ll)-(s[j+1]-s[i]); 7 } 8 int maxFrequency(vector<int>& nums, int k) { 9 sort(nums.begin(),nums.end()); 10 s.resize(nums.size()+1); 11 for(int i=1;i<=nums.size();i++) s[i]=s[i-1]+nums[i-1]; 12 int res=0; 13 int i=0; 14 for(int j=0;j<nums.size();j++){ 15 while(get_op(i,j,nums)>k){ 16 i++; 17 } 18 res=max(res,j-i+1); 19 } 20 return res; 21 } 22 };
C:可以直接模拟求解,注意分类讨论即可。
1 class Solution { 2 public: 3 int longestBeautifulSubstring(string s) { 4 string p="aeiou"; 5 int res=0; 6 for(int i=0;i<s.size();i++){ 7 if(s[i]!='a') continue; 8 int j=i,k=0; 9 while(j<s.size()){ 10 if(s[j]==p[k]) j++; 11 else{ 12 if(k==4) break; 13 if(s[j]==p[k+1]) j++,k++; 14 else break; 15 } 16 if(k==4) 17 res=max(res,j-i);//不需要加一,j-1才是确定的 18 } 19 i=j-1; 20 } 21 return res; 22 } 23 };
D:线性规划问题。
单独分析 i 这个点。
对于 i 这个点前边和后边对他高度的限制如图所示。
我们可以通过记录截距来记录每一条直线,也就很容易算出一个点的最高高度是多少了。
但是这样的话我们还是得算1e9次,但是观察到总共只有1e5个限制。
假设 i 和 j 之间是没有别的限制的话,i,j 之间的最大高度就是 i 和 j 以及他们限制交点的最低点(如果焦点在i,j之间的话)
1 class Solution { 2 public: 3 int maxBuilding(int n, vector<vector<int>>& h) { 4 typedef long long LL; 5 h.push_back({1,0}); 6 sort(h.begin(),h.end()); 7 if(h.back()[0]!=n){ 8 h.push_back({n,n-1}); 9 } 10 LL m=h.size(); 11 vector<LL> f(m+1,INT_MAX),g(m+1,INT_MAX); 12 f[0]=-1; 13 for(int i=1;i<m;i++){ 14 int x=h[i][0],y=h[i][1]; 15 f[i]=min(f[i-1],(LL)y-x); 16 } 17 for(int i=m-1;i>=0;i--){ 18 int x=h[i][0],y=h[i][1]; 19 g[i]=min(g[i+1],(LL)y+x); 20 } 21 LL res=0; 22 for(int i=0;i<m;i++){ 23 int x=h[i][0]; 24 if(i){//防止数组越界,计算h[i-1][0]和h[i][0]之间的最高建筑高度 25 LL Y=(f[i-1]+g[i])/2; 26 LL X=Y-f[i-1]; 27 if(x>=h[i-1][0]&&X<=h[i][0]) 28 res=max(res,Y); 29 } 30 res=max(res,min(x+f[i],g[i]-x)); 31 } 32 //下面这样写也是可以的 33 // for(int i=0;i<m;i++){ 34 // int x=h[i][0]; 35 // if(i<m-1){ 36 // LL Y=(f[i]+g[i+1])/2; 37 // LL X=Y-f[i]; 38 // if(x>=h[i][0]&&X<=h[i+1][0]) 39 // res=max(res,Y); 40 // } 41 // res=max(res,min(x+f[i],g[i]-x)); 42 // } 43 44 return res; 45 } 46 };