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​​​​​​、bc​​​​​​ 的 三堆 石子。

每回合你都要从两个 不同的非空堆 中取出一颗石子,并在得分上加 1 分。当存在 两个或更多 的空堆时,游戏停止。

给你三个整数 abc ,返回可以得到的 最大分数

思路
a,b,c排序从大到小:

  1. a<=b+c ans=a+(b+c-a)/2;
  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. 构造字典序最大的合并字符串

给你两个字符串 word1word2 。你需要按下述方式构造一个新字符串 merge :如果 word1word2 非空,选择 下面选项之一 继续操作:

  • 如果 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 。*

长度相同的两个字符串 ab 比较字典序大小,如果在 ab 出现不同的第一个位置,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,当搜到最后一个数的时候就判断两种情况:

  1. 从前20个方案中二分找出比当前goal小的最大值
  2. 从前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;
    }
};

同理变形背包问题

注意:遇到这种给定一个集合,每个选与不选,求最大值或者最小值的时候看数据范围而定:

  1. 若单个数据大小<=1e3 而n在1e5左右可以考虑背包问题
  2. 若单个数据大小<=1e7而n在40左右考虑双向dfs问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值