笔试强训:Week-3

目录

一、牛牛冲钻五(模拟)

二、最长无重复子数组(滑动窗口)

三*、重排字符串(贪心)

四、乒乓球筐(哈希)

五?、组队竞赛(排序+贪心)

六、删除相邻数字的最大分数(多状态dp)

七*?、平方数(数学)

八?、分组(枚举+二分)

九*、【模板】拓扑排序(建图+多源bfs)

十、字符串替换(模拟)

十一*、神奇数(固定长度全排列)

十二、DNA序列(定长滑动窗口)

十三、小乐乐改数字(模拟)

十四、十字爆破(模拟)

十五、比那名居的桃子(定长滑动窗口)

十六、压缩字符串(一)

十七、chika和蜜柑(重写排序,自定义比较规则)

十八*、01背包


一、牛牛冲钻五(模拟)

牛牛冲钻五

#include <iostream>
using namespace std;

int main() {
    int T;cin>>T;
    while(T--)
    {
        int n,k;
        cin>>n>>k;
        string str;
        cin>>str;
        int sum=0;
        for(int i=0;i<n;++i)
        {
            if(str[i]=='W')
            {
                if(i>=2&&str[i-1]=='W'&&str[i-2]=='W')sum+=k;
                else sum+=1;
            }
            else sum-=1;
        }
        cout<<sum<<endl;
    }
    return 0;
}

二、最长无重复子数组(滑动窗口)

最长无重复子数组_牛客题霸_牛客网

注意hash的key值是in和out,老是写成left和right

class Solution {
public:
    int maxLength(vector<int>& arr) {
        unordered_map<int,int> hash;
        int ret=1,left=0,right=0,n=arr.size();
        if(n==0||n==1)return n; 
        while(right<n)
        {
            int in=arr[right];
            ++hash[in];
            while(hash[in]>1)
            {
                int out=arr[left++];
                --hash[out];
            }
            ret=max(ret,right-left+1);
            ++right;
        }
        return ret;
    }
};

三*、重排字符串(贪心)

重排字符串

优先处理出现次数最多的那个,每隔一个位置放一个,x<=(n+1)/2才可以排,否则直接cout<<"no"

#include<iostream>
#include<string>
using namespace std;
int main()
{
    int n;
    string s;
    cin>>n>>s;
    int MaxCount=0,hash[26]={0};
    char MaxChar;
    for(auto&ch:s)
    {
        if(++hash[ch-'a']>MaxCount)
        {
            MaxCount=hash[ch-'a'];
            MaxChar=ch;
        }
    }
    if(MaxCount>(n+1)/2)cout<<"no";
    else
    {
        cout<<"yes"<<endl;
        //处理出现次数最多的那个
        int index=0;
        while(MaxCount--)
        {
            s[index]=MaxChar;
            index+=2;
        }
        //处理剩下的
        for(int i=0;i<26;++i)
        {
            if(hash[i]&&i!=MaxChar-'a')
            {
                char chr=i+'a';
                while(hash[i]--)
                {
                    if(index>=n)index=1;
                    s[index]=chr;
                    index+=2;
                }
            }
        }
        cout<<s;
    }
    return 0;
}

四、乒乓球筐(哈希)

乒乓球筐__牛客网

先遍历s2,存进,然后遍历s1,最后再遍历26个字母,如果有剩下的就cout<<"No";

#include <iostream>
using namespace std;

int main() {
    string s1,s2;
    cin>>s1>>s2;
    int hash[26]={0};
    int n=s1.size(),m=s2.size();
    for(int i=0;i<m;++i)
    {
        hash[s2[i]-'A']++;
    }
    for(int i=0;i<n;++i)
    {
        if(hash[s1[i]-'A'])--hash[s1[i]-'A'];
    }
    for(int i=0;i<26;++i)
    {
        if(hash[i])
        {
            cout<<"No";
            return 0;
        }
    }
    cout<<"Yes";
    return 0;
}

或者先遍历s1,然后遍历s2,如果hash[]<0说明s1包不住s2,cout<<"No",此外,对于这种二元判断的,我们可以添加一个bool变量来实现cout哪个,这样就不用写两个return了

#include <iostream>
#include <string>
using namespace std;
 
int main() {
   string a,b;
   cin>>a>>b;
   int hash[26]={0};
   for(auto&ch:a) ++hash[ch-'A'];
   bool ret=true;
   for(auto&ch:b)
   { 
       if(--hash[ch-'A']<0)
      {
          ret=false;
          break;
      }
   }
    cout<<(ret?"Yes":"No");

    return 0;
}

五?、组队竞赛(排序+贪心)

组队竞赛_牛客笔试题_牛客网

做错了,错误的以为是排序后从下标1开始+=3加到sum。

贪心的想,应该是排序后,因为我们得是第2大的,那么我们取数就得保证还有一个数比我大,那么我们从倒数第二的开始往前选,index-=2,找到n个,就是最大的。

#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+5;
int n;
long long a[N*3];
int main() {
    cin>>n;
    for(int i=0;i<n*3;++i) cin>>a[i];
    sort(a,a+3*n);
    
    //从倒数第二个开始
    int pos=3*n-2;
    long long ret=0;
    //取n个
    while(n--){
        ret+=a[pos];
        pos-=2;
    }
    cout<<ret;
    return 0;
}

六、删除相邻数字的最大分数(多状态dp)

删除相邻数字的最大分数_牛客题霸_牛客网

没想到自己能想到这么做。

无非就是不能接着选的问题,遍历到i的时候无非就是i选和不选的问题,然后在dp[i-1]和dp[i-2]+count[i-2](伪)里找max。

我们将数据先存进count,count[某个数]=该数之和,建立映射关系,如果选了这个数,那么这个数-1/+1就不都不能选,相当于不能连续选的意思,接下来用这个数组取填dp表就行了。

#include <iostream>
using namespace std;
const int N=1e5+1;
int arr[N],count[N],dp[N];
int main() {
    int n;cin>>n;
    for(int i=0;i<n;++i)
    {
        cin>>arr[i];
        count[arr[i]]+=arr[i];
    }
    for(int i=2;i<=10001;++i)
    {
        dp[i]=max(dp[i-1],dp[i-2]+count[i-1]);
    }
    cout<<dp[10001];
    return 0;
}

七*?、平方数(数学)

平方数

这题没做出来,感觉自己废了。。。。

我现在在怀疑是不是int范围太小所以平方后溢出的问题,做的时候没有考虑这点忘记开longlong了

也有可能是二分判断时,mid*mid会溢出的问题,应该把其中一个mid除到另一边。唉修改了很多还是只能到百分之80.还是用sqrt函数吧服了

这里我又不服又试了新的解法,还是错了,算了老实用sqrt吧

sqrt(x);       #include<cmath>

#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
int main(){
    LL x;
    cin>>x;
    LL a=sqrt(x);
    LL x1=a*a,x2=(a+1)*(a+1);
    if(x2-x>x-x1) cout<<x1<<endl;
    else cout<<x2<<endl;
}

八?、分组(枚举+二分)

分组

完全没思路X﹏X

看完解答后感觉是很有意思的二分题。

如果我们知道了最终的人数最多的小组的人数x,那么对于每个声部的人假设有a人可以分成

a/x+(a%x==0?0:1)组,然后计算所有声部总和是不是等于m即可。所以这种找值的题目先想想暴力是怎么做的,然后再思考更优解吧~~~~~~

从这点上进行二分,我们将二分修改左右边界的判断条件写成一个函数

#include<iostream>
#include<unordered_map>
using namespace std;

const int N=1e5+1;
int arr[N],n,m,hmax;

bool check(int mid,unordered_map<int, int> hash)
{
    int groups=0;
    for(auto&[x,y]:hash)
    {
        groups+=(y/mid+(y%mid==0?0:1)); 
    }
    return groups<=m;
}


int main()
{
    unordered_map<int,int> hash;
    cin>>n>>m;
    for(int i=0;i<n;++i)
    {
        //注意key是arr[i]不是i
        cin>>arr[i];
        ++hash[arr[i]];
        if(hash[arr[i]]>hmax)hmax=hash[arr[i]];
    }
    int kinds=hash.size(),ret=0;
    if(kinds>m)cout<<-1;
    else 
    {    
        int left=1,right=hmax;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(check(mid,hash))right=mid;
            else left=mid+1;
        }
        cout<<left;
    }
    return 0;
}

九*、【模板】拓扑排序(建图+多源bfs)

【模板】拓扑排序_牛客题霸_牛客网

建图+多源bfs

说起来多源bfs解决拓扑排序系列最近才总结了,做题的有意识要用bfs但是已经忘记如何建图了,无命休矣。

原多源bfs解决拓扑排序,建图过程:unordered_map<int,vector<int>> hash :key->value

然后还需要额外创建一个数组统计入度,因为每层bfs我们处理的都是入度为0的点,开始bfs前先将所有入度为0的源点入队,然后每层dfs,取完队头元素,将队头元素指向的所有结点入度减去1,如果有变成入度为0的

最后return检查是不是还有入度为0的点,如果有就是有环,该题的话就是返回-1

复习完多源bfs解决拓扑排序,现在看看该题具体该如何解答,按照这个思路也是可行的开始写代码吧!

#include <iostream>
#include<unordered_map>
#include<vector>
#include<queue>
using namespace std;

const int N=2e5+1;
int in[N];//处理入度

int main() {
    int n,m;
    cin>>n>>m;
    //建图
    unordered_map<int,vector<int>> hash;
    int x,y;
    while(m--)
    {
        cin>>x>>y;
        hash[x].push_back(y);
        ++in[y];
    }
    //入度为0的点入队
    queue<int> q;
    for(int i=1;i<=n;++i)
    {
        if(in[i]==0)q.push(i);
    }
    //bfs
    vector<int> ret;
    while(!q.empty())
    {
        int t=q.front();
        ret.push_back(t);
        q.pop();
        for(auto&x:hash[t])
        {
            if(--in[x]==0)q.push(x);
        }
    }
    //检查是否有环
    // for(int i=1;i<=n;++i)
    // {
    //     if(in[i])
    //     {
    //         cout<<-1;
    //         break;
    //     }
    // }
    //其实也可以按照ret。size判断
    if(ret.size()!=n)cout<<-1;
    else
    {
        for(int i=0;i<n-1;++i)cout<<ret[i]<<" ";
        cout<<ret[n-1];//最后一下没空格
    }
    return 0;
}

明天继续加油o(* ̄︶ ̄*)o

书接上回~今天三道题都做出来了很开心哈哈

十、字符串替换(模拟)

很轻松的一道题

#include <cctype>
class Solution {
public:
    string formatString(string str, vector<char>& arg) {
        string ret;
        int cur1=0,cur2=0;
        while(cur1<str.size())
        {
            if(isalpha(str[cur1]))
            {
                ret+=str[cur1++];
            }
            else {
                ret+=arg[cur2++];
                cur1+=2;
            }
        }
        while(cur2<arg.size())ret+=arg[cur2++];
        return ret;
    }
};

十一*、神奇数(固定长度全排列)

神奇数_牛客笔试题_牛客网

其实全排列用嵌套for循环就能直接实现了

标答,看来质数判断得学习一下

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
bool isprimenum(int x){//判断该数是否是质数 用试除法
    if(x<2||x%2==0) return false;//偶数肯定不是质数
    int n=sqrt(x);
    for(int i=3;i<=n;i+=2)//奇数除以偶数肯定不能整除
       if(x%i==0) return false;
    return true;
}
bool check(int x){//判断是否是神奇数 
    vector<int> nums;
    while(x){
       nums.emplace_back(x%10);
       x/=10;
    }
    int n=nums.size();
    for(int i=0;i<n;++i)//枚举十位数 
      for(int j=0;j<n;++j)//枚举个位数
        if(i!=j&&nums[i]!=0&&isprimenum(nums[i]*10+nums[j]))
           return true;
    return false;
}
int a, b;
int main() {
    cin>>a>>b;
    int ret=0;
    for(int i=max(10,a);i<=b;++i)
       if(check(i)) ++ret;
    cout<<ret<<endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

本人写的

#include <iostream>
#include <string>
using namespace std;

const int N=1e5+1;
bool check[N];
int add,sum;
string path;

bool isPrime(int num)
{
    bool flag=true;
    for(int i=2;i<num/2;++i)
    {
        if(num%i==0)
        {
            flag=false;
            break;
        }
    }
    return flag;
}
void isRightNum(string s)
{
    if(path.size()==2)
    {
        if(path[0]=='0')return;
        if(isPrime(stoi(path)))
        {
            add=1;
            return;
        }
    }
    for(int i=0;i<s.size();++i)
    {
        if(check[i]==false)
        {
            path.push_back(s[i]);
            check[i]=true;
            isRightNum(s);
            path.pop_back();
            check[i]=false;
        }
    }
}
int main() {
    int a,b;
    cin>>a>>b;
    for(int i=a;i<=b;++i)
    {
        add=0;
        //如果是神奇数,add置为1
        isRightNum(to_string(i));
        sum+=add;
    }
    cout<<sum;
    return 0;
}

十二、DNA序列(定长滑动窗口)

DNA序列_牛客题霸_牛客网

写得和标答一样,不愧是我

#include <iostream>
#include <ostream>
using namespace std;

int main() {
    string s;int n;
    cin>>s>>n;
    //不能写等于,不然会输出两次s,一直没检查出来服了hhh
    if(n>s.size())cout<<s;
    int cur=0;
    int begin,max=0,count=0;
    int left=0,right=0;
    while(right<n)
    {
        if(s[right]=='G'||s[right]=='C')++count;
        ++right;
        if(count>max)
        {
            max=count;
            begin=left;
        }
    }
    while(right<s.size())
    {
        if(s[right]=='G'||s[right]=='C')++count;
        if(s[left]=='G'||s[left]=='C')--count;
        ++left;
        ++right;
        if(count>max)
        {
            max=count;
            begin=left;
        }
    }
    cout<<s.substr(begin,n)<<endl;
    return 0;
}

十三、小乐乐改数字(模拟)

小乐乐改数字_牛客题霸_牛客网

#include <iostream>
#include <string>
using namespace std;

int main() {

    int n;
    cin>>n;
    string s=to_string(n);
    for(int i=0;i<s.size();++i)
    {
        if((s[i]-'0')%2)s[i]='1';
        else s[i]='0';
    }
    int cur=0,num=0;
    while(cur<s.size())
    {
        if(num==0&&s[cur]=='0')++cur;
        else
        {
            num=num*10+s[cur]-'0';
            ++cur;
        }
    }
    cout<<num;
    return 0;
}

十四、十字爆破(模拟)

十字爆破

牛牛咱下次别玩这么危险的游戏了好吗

long long格式化输出占位符是lld,不是d我服了。

#include <iostream>
#include<vector>
using namespace std;
int main() {
    int n,m;
    cin>>n>>m;
    vector<vector<long long>> arr(n,vector<long long>(m));
    vector<long long> row(n);
    vector<long long> col(m);
    for(int i=0;i<n;++i)
    {
        for(int j=0;j<m;++j)
        {
            scanf("%lld",&arr[i][j]);
            row[i]+=arr[i][j];
            col[j]+=arr[i][j];
        }

    }
    for(int i=0;i<n;++i)
    {
        for(int j=0;j<m-1;++j)
        {
            arr[i][j]=(row[i]+col[j]-arr[i][j]);
            cout<<arr[i][j]<<" ";
        }
        arr[i][m-1]=(row[i]+col[m-1]-arr[i][m-1]);
        cout<<arr[i][m-1]<<endl;
    }
    return 0;
}

十五、比那名居的桃子(定长滑动窗口)

比那名居的桃子

我服了,一直过不了,结果是int溢出了,以后遇到要算术运算操作的都开long long

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    for (int i = 0; i < n; ++i) cin >> b[i];

    long long happy = 0, embrassment = 0;
    for (int i = 0; i < k; ++i) {
        happy += a[i];
        embrassment += b[i];
    }

    long long maxHappy = happy, minEmbra = embrassment;
    int ret = 0;

    int left = 0, right = k;
    while (right < n) {
        happy += a[right] - a[left];
        embrassment += b[right] - b[left];
        ++right;
        ++left;

        if (happy > maxHappy) {
            maxHappy = happy;
            minEmbra = embrassment;
            ret = left;
        }
        else if (happy == maxHappy && embrassment < minEmbra) {
            minEmbra = embrassment;
            ret = left;
        }
    }

    cout << ret + 1 << endl;
    return 0;
}

十六、压缩字符串(一)

压缩字符串(一)_牛客题霸_牛客网

#include <string>
class Solution {
public:
    string compressString(string param) {
        string ret;
        int cur=1,n=param.size(),count;
        if(n==0||n==1)return param;
        while(cur<n)
        {
            count=1;
            while(cur<n&&param[cur]==param[cur-1])
            {
                ++count;
                ++cur;
            }
            ret+=param[cur-1];
            if(count>1)ret+=to_string(count);
            ++cur;
        }
        //cur==n,末尾的没加上,如果末尾的加上了cur==n+1
        if(cur==n)
        {
            ret+=param[cur-1];
            if(count>1)ret+=to_string(count);
        }
        return ret;
    }
};

十七、chika和蜜柑(重写排序,自定义比较规则)

chika和蜜柑

自定义比较方法

#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
#include<vector>
#include<utility>
using LL=long long;
struct cmp{
    bool operator()(pair<LL, LL>&a,pair<LL,LL>&b)
    {
        //相等酸度降序排序
        if(a.first==b.first)return a.second>b.second;
        //按照甜度,升序排序
        return a.first<b.first;
    }
};
int main() {
    int n,k;
    cin>>n>>k;
    vector<LL> Sour(n),Sweet(n);
    for(int i=0;i<n;++i)cin>>Sour[i];
    for(int i=0;i<n;++i)cin>>Sweet[i];

    //key:Sweet[i]->value:Sour[i]
    vector<pair<LL,LL>> Bind(n);
    for(int i=0;i<n;++i)
    {
        Bind[i]={Sweet[i],Sour[i]};
    }
    sort(Bind.begin(), Bind.end(),cmp());

    LL SweetSum=0,SourSum=0;
    for(int i=n-1;i>n-1-k;--i)
    {   
        SweetSum+=Bind[i].first;
        SourSum+=Bind[i].second;
    }
    cout<<SourSum<<" "<<SweetSum;
    return 0;
}

十八*、01背包

01背包_牛客题霸_牛客网

已经忘了背包问题怎么写了。。。。

短短几行代码,看来要复习复习背包问题了/(ㄒoㄒ)/~~

class Solution {
public:
    int dp[1010]={0};
    int knapsack(int V, int n, vector<vector<int> >& vw) {
       //体积不超过V的情况下 当前能够装下的最大重量
       //dp[i][j]表示从前i个物品选,体积不超过j的最大重量
       for(int i=0;i<n;++i)
         for(int j=V;j>=vw[i][0];--j)
           dp[j]=max(dp[j],dp[j-vw[i][0]]+vw[i][1]);
       return dp[V];
    }
};

本周笔试完结撒花!!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_dindong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值