leetcode周赛 227

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) 。

posted on 2021-02-16 21:19  greenofyu  阅读(26)  评论(0编辑  收藏  举报