LeetCode第 227 场周赛
5672. 检查数组是否经排序和轮转得到
给你一个数组 nums 。nums 的源数组中,所有元素与 nums 相同,但按非递减顺序排列。
如果 nums 能够由源数组轮转若干位置(包括 0 个位置)得到,则返回 true ;否则,返回 false 。
源数组中可能存在 重复项 。
注意:我们称数组 A 在轮转 x 个位置后得到长度相同的数组 B ,当它们满足 A[i] == B[(i+x) % A.length] ,其中 % 为取余运算。
代码:
class Solution {
public boolean check(int[] nums) {
int []a=new int[110];
int len=nums.length;
for(int i=0;i<len;i++) {
a[i]=nums[i];
}
Arrays.sort(a,0,len);
boolean f=false;
for(int i=0;i<len;i++) {
int []b=new int[110];
for(int j=0;j<len;j++) {
b[(j+i)%len]=nums[j];
}
f=true;
for(int j=0;j<len;j++) {
if(b[j]!=a[j]) {
f=false;
break;
}
}
if(f==true) break;
}
return f;
}
}
5673. 移除石子的最大得分
难度中等3收藏分享切换为英文接收动态反馈
你正在玩一个单人游戏,面前放置着大小分别为 a
、b
和 c
的 三堆 石子。
每回合你都要从两个 不同的非空堆 中取出一颗石子,并在得分上加 1
分。当存在 两个或更多 的空堆时,游戏停止。
给你三个整数 a
、b
和 c
,返回可以得到的 最大分数 。
思路
a,b,c排序从大到小:
- a<=b+c ans=a+(b+c-a)/2;
- a>b+c ans=b+c
代码
class Solution {
public:
int maximumScore(int a, int b, int c) {
if(a<b)swap(a,b);
if(a<c) swap(a,c);
if(b<c) swap(b,c);
//a>b>c
int sum=0;
if(b+c>=a) {
sum=a+(b+c-a)/2;
}
else sum=b+c;
return sum;
}
};
5674. 构造字典序最大的合并字符串
给你两个字符串 word1
和 word2
。你需要按下述方式构造一个新字符串 merge
:如果 word1
或 word2
非空,选择 下面选项之一 继续操作:
- 如果
word1
非空,将word1
中的第一个字符附加到merge
的末尾,并将其从word1
中移除。- 例如,
word1 = "abc"<span> </span>
且merge = "dv"
,在执行此选项操作之后,word1 = "bc"
,同时merge = "dva"
。
- 例如,
- 如果
word2
非空,将word2
中的第一个字符附加到merge
的末尾,并将其从word2
中移除。- 例如,
word2 = "abc"<span> </span>
且merge = ""
,在执行此选项操作之后,word2 = "bc"
,同时merge = "a"
。
- 例如,
返回你可以构造的字典序 最大 的合并字符串* merge
。*
长度相同的两个字符串 a
和 b
比较字典序大小,如果在 a
和 b
出现不同的第一个位置,a
中字符在字母表中的出现顺序位于 b
中相应字符之后,就认为字符串 a
按字典序比字符串 b
更大。例如,"abcd"
按字典序比 "abcc"
更大,因为两个字符串出现不同的第一个位置是第四个字符,而 d
在字母表中的出现顺序位于 c
之后。
思路
贪心即可 若从当前字符向后所组成的子串大于另外一个则选择当前这个字符,反之选择另外一个字符
代码
class Solution {
public:
string largestMerge(string word1, string word2) {
int lena=word1.size();
int lenb=word2.size();
int i=0,j=0;
string ans="";
while(i<lena&&j<lenb) {
if(word1[i]>word2[j]) ans+=word1[i++];
else if(word1[i]<word2[j])ans+=word2[j++];
else {
string p=word1.substr(i,lena);
string q=word2.substr(j,lenb);
if(p>q) ans+=word1[i++];
else ans+=word2[j++];
}
}
while(i<lena) ans+=word1[i++];
while(j<lenb) ans+=word2[j++];
return ans;
}
};
5675. 最接近目标值的子序列和
给你一个整数数组 nums
和一个目标值 goal
。
你需要从 nums
中选出一个子序列,使子序列元素总和最接近 goal
。也就是说,如果子序列元素和为 sum
,你需要 最小化绝对差 abs(sum - goal)
。
返回 abs(sum - goal)
可能的 最小值 。
注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。
思路
双向dfs,单项dfs会超时,将前20个数的所有方案组合放到数组中,排序,从小到大,对后面20个数进行dfs,当搜到最后一个数的时候就判断两种情况:
- 从前20个方案中二分找出比当前goal小的最大值
- 从前20个方案中二分找出比当前goal大的最小值
代码
const int N=2e6+10;
int q[N];
class Solution {
public:
int n,cnt,goal,ans;
void dfs1(vector<int>&nums,int u,int s) {
if(u==(n+1)/2) {
q[cnt++]=s;
return ;
}
dfs1(nums,u+1,s);
dfs1(nums,u+1,s+nums[u]);
}
void dfs2(vector<int>&nums,int u,int s) {
if(u==n) {
int l=0,r=cnt-1,as=-1;
//找比goal小的最大值
while(l<=r){
int mid=l+r>>1;
if(q[mid]+s<=goal) {
l=mid+1;
as=mid;
}
else r=mid-1;
}
//cout<<as<<'\n';
if(as!=-1)ans=min(ans,abs(q[as]+s-goal));
as=-1;
l=0,r=cnt-1;
//找出比goal大的最小值
while(l<=r) {
int mid=l+r>>1;
if(q[mid]+s>=goal) {
r=mid-1;
as=mid;
}
else l=mid+1;
}
//cout<<as<<'\n';
if(as!=-1) ans=min(ans,abs(q[as]+s-goal));
return;
}
dfs2(nums,u+1,s);
dfs2(nums,u+1,s+nums[u]);
}
int minAbsDifference(vector<int>& nums, int _goal) {
n=nums.size(),cnt=0,goal=_goal,ans=0x3f3f3f3f;
dfs1(nums,0,0);
sort(q,q+cnt);
for(int i=0;i<cnt;i++) {
// cout<<q[i]<<' ';
}
dfs2(nums,(n+1)/2,0);
return ans;
}
};
同理变形背包问题
注意:遇到这种给定一个集合,每个选与不选,求最大值或者最小值的时候看数据范围而定:
- 若单个数据大小<=1e3 而n在1e5左右可以考虑背包问题
- 若单个数据大小<=1e7而n在40左右考虑双向dfs问题