A:问能否将一个数组通过轮换的方式得到一个单调不减的数组。
因为范围只有100,直接将数组拷贝并排序,然后对原数组轮换n次,每次进行一下判断。
1 class Solution { 2 public: 3 bool check(vector<int>&a,vector<int>& b){ 4 int n=a.size(); 5 for(int i=0;i<n;i++){ 6 if(a[i]!=b[i]){ 7 return false; 8 } 9 } 10 return true; 11 } 12 bool check(vector<int>& nums) { 13 int n=nums.size(); 14 vector<int> tmp=nums; 15 sort(tmp.begin(),tmp.end()); 16 for(int i=0;i<n;i++){ 17 int t=tmp.back(); 18 tmp.pop_back(); 19 tmp.insert(tmp.begin(),t); 20 if(check(tmp,nums)) return true; 21 } 22 return false; 23 } 24 };
B:给定三堆石子,每次操作从其中两堆各拿走一个石子,获得价值1,问价值最大为多少。
三堆石子数量分别为a,b,c。
不妨设a<=b<=b。
1.若a+b<=c,那么ans=a+b
2.若a+b>c,那么必然可以消耗成两两之间的差小于等于1,即|a-b|<=1,|a-c|<=1,|b-c|<=1。
而且可以发现,这种情况之后的都会一直保持上述性质。
故最终答案为0,0,0或者0,0,1,1取决于石子总数的奇偶。
1 class Solution { 2 public: 3 int maximumScore(int a, int b, int c) { 4 int d[]={a,b,c}; 5 sort(d,d+3); 6 if(d[0]+d[1]<=d[2]) return d[0]+d[1]; 7 else return (d[0]+d[1]+d[2])/2; 8 } 9 };
C:给定两个字符串,每次操作选择其中一个串的首字符,放到res的末尾,问字典序最大的串是什么。
原始写法:考试的时候想的是每次挑字典序大的字符,如果相同,就需要判断后面的字符的大小,假设A串为"ccbda",B串为"ccaza",那么我们应该先将A串的 ‘c’ 拿尽。
根据这个思路,在每次A和B相同的时候就继续往后判断。
1 class Solution { 2 public: 3 int finds(int i,int j,string& w1,string& w2){ 4 char c=w1[i]; 5 while(i<w1.size()&&j<w2.size()){ 6 if(w1[i]>w2[j]){ 7 return 1; 8 }else if(w1[i]<w2[j]){ 9 return 2; 10 } 11 i++,j++; 12 } 13 while(i<w1.size()){ 14 if(w1[i]>c){ 15 return 1; 16 }else if(w1[i]<c){ 17 return 2; 18 } 19 i++; 20 } 21 while(j<w2.size()){ 22 if(w2[j]>c){ 23 return 2; 24 }else if(w2[j]<c){ 25 return 1; 26 } 27 j++; 28 } 29 return 1; 30 } 31 string largestMerge(string w1, string w2) { 32 int i=0,j=0; 33 string res=""; 34 while(i<w1.size()&&j<w2.size()){ 35 if(w1[i]>w2[j]){ 36 res+=w1[i]; 37 i++; 38 }else if(w1[i]<w2[j]){ 39 res+=w2[j]; 40 j++; 41 }else{ 42 int t=finds(i,j,w1,w2); 43 if(t==1){ 44 res+=w1[i]; 45 i++; 46 }else{ 47 res+=w2[j]; 48 j++; 49 } 50 } 51 } 52 while(i<w1.size()){ 53 res+=w1[i]; 54 i++; 55 } 56 while(j<w2.size()){ 57 res+=w2[j]; 58 j++; 59 } 60 return res; 61 } 62 };
优化写法:如果两个串首字母相等,就比较往后的第一个不想的的字母的本质就是子串的比较。
故可直接利用substr函数进行比较。
1 class Solution { 2 public: 3 string largestMerge(string w1, string w2) { 4 int i=0,j=0; 5 string res=""; 6 while(i<w1.size()||j<w2.size()){ 7 if(w1.substr(i)>w2.substr(j)){ 8 res+=w1[i++]; 9 }else{ 10 res+=w2[j++]; 11 } 12 } 13 return res; 14 } 15 };
D:给定一个长度为n的数组,从中选出一个子序列,其和记为sum,求|sum-goal|最小为多少,输出这个最小值。
如果数组长度<20,那么就可以直接暴搜,时间复杂度为2^20=1e6
如果要求的是最大和或者最小和,那么可以应用01背包的模型。
而这个题数组长度为40,就需要用双向dfs来做。
首先对前一半数组做一遍dfs,处理出全部的的和,再排序。
对于后半部分的数组同样进行dfs,到终点时,利用二分找到和小于goal的最大值和大于goal的最小值。
1 const int N=1e7; 2 int q[N]; 3 class Solution { 4 public: 5 int cnt,res,n,goal; 6 void dfs1(vector<int>& nums,int u,int s){ 7 if(u==(n+1)/2){ 8 q[cnt++]=s; 9 return ; 10 } 11 dfs1(nums,u+1,s); 12 dfs1(nums,u+1,s+nums[u]); 13 } 14 void dfs2(vector<int>&nums,int u,int s){ 15 if(u==n){ 16 int l=0,r=cnt-1; 17 while(l<r){ 18 int mid=l+r+1>>1; 19 if(q[mid]+s<=goal) l=mid; 20 else r=mid-1; 21 } 22 res=min(res,abs(q[r]+s-goal)); 23 if(r+1<cnt){ 24 res=min(res,abs(q[r+1]+s-goal)); 25 } 26 return ; 27 } 28 dfs2(nums,u+1,s); 29 dfs2(nums,u+1,s+nums[u]); 30 } 31 int minAbsDifference(vector<int>& nums, int _goal) { 32 n=nums.size(); 33 goal=_goal; 34 res=INT_MAX; 35 dfs1(nums,0,0); 36 sort(q,q+cnt); 37 dfs2(nums,(n+1)/2,0); 38 return res; 39 } 40 };
时间复杂度为1e6 + 1e6*log(1e6) + 1e6*log(1e6) 。