字符串的排序,活动安排,合唱团,小红的口罩,春游,数位染色,爱吃素数

在这里插入图片描述

字符串的排序

链接:字符串排序
来源:牛客网

题目描述

输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。

数据范围:
𝑛<10
要求:空间复杂度 𝑂(𝑛!),时间复杂度 𝑂(𝑛!)

输入描述:

输入一个字符串,长度不超过10,字符只包括大小写字母。

示例1

输入
“ab”
输出
[“ab”,“ba”]
说明
返回[“ba”,“ab”]也是正确的

示例2

输入
“aab”
输出
[“aab”,“aba”,“baa”]

示例3

输入
“abc”
输出
[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]

示例4

输入
“”
输出
[“”]

算法法原理

排序+递归/dfs
在这里插入图片描述
在同一层,如果相同的字符已经访问过了,那么就直接剪枝掉不再递归了

代码


```cpp
class Solution {
  public:
    vector<string> ret;
    vector<bool> vis;
    void dfs(string& str, string& path) {
        if (path.size() == str.size()) {
            ret.push_back(path);
            return;
        }
        for (int i = 0; i < str.size(); i++) {
            if (!vis[i]) {
                path.push_back(str[i]);
                vis[i] = true;
                //cout << path << endl;
                dfs(str, path);
                path.pop_back();
                vis[i] = false;
                //剪枝,相同的字符,直接跳过
                while (i + 1 < str.size() && str[i] == str[i + 1]) {
                    i++;
                }
            }

        }
    }
    vector<string> Permutation(string str) {
        // write code here
        sort(str.begin(), str.end());
        vis.resize(str.size(), false);
        string path;
        dfs(str, path);
        return ret;
    }
};

活动安排

算法原理

排序+贪心
在这里插入图片描述

代码

#include <iostream>
using namespace std;
#include <vector>
#include <functional>
#include <utility>
struct Com
{
    bool operator()(pair<int,int>& l,pair<int,int>& r)
    {
        return l.first==r.first?l.second<r.second:l.first<r.first;
    }
};
int main() {
    int n;
    cin>>n;
    vector<pair<int,int>> v;
    for(int i = 0;i<n;i++)
    {
        int _first,_second;
        cin>>_first>>_second;
        v.push_back(make_pair(_first,_second));
    }
    Com com;
    sort(v.begin(),v.end(),com);
    int count = 0;
    int right = -1;
    for(int i = 0;i<n;i++)
    {
        if(v[i].first>=right)
        {
            count++;
            right = v[i].second;
        }
        else {
            right = min(right,v[i].second);
        }
    }
    cout<<count;
    return 0;

}

合唱团

题目描述

有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?

输入描述:

每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。

输出描述:

输出一行表示最大的乘积。

示例1

输入
3
7 4 7
2 50
输出
49

算法原理

动态规划–线性dp
在这里插入图片描述

代码

#include <iostream>
using namespace std;
#include <functional>
#include <vector>
int main() {
    int n,k,d;
    cin>>n;
    vector<int> v(n+1,0);
    vector<vector<long long>> f(n+1,vector<long long>(k+1,-0x3f3f3f3f3f3f3f3f));
    vector<vector<long long>> g(n+1,vector<long long>(k+1,0x3f3f3f3f3f3f3f3f));
    for(int i = 1; i <= n; i++)
    {
        cin>>v[i];
    }
    cin>>k>>d;

    //初始化
    long long ret = -0x3f3f3f3f3f3f3f3f;
    for(int i = 1;i<=n;i++)
    {
        f[i][1] = v[i];
        g[i][1] = v[i];
        //如果只选一个
        if(k==1)
            ret = max<long long>(ret,v[i]);
    }
    for(int j = 2;j<=k;j++)
    {
        for(int i = j;i<=n;i++)
        {
            //prev>=i-d&&prev>=j-1
            for(int prev = max(i-d,j-1);prev<=i-1;prev++)
            {
                long long tmp1 = f[prev][j-1]*v[i];
                long long tmp2 = g[prev][j-1]*v[i];
                f[i][j] = max(f[i][j],max(tmp1,tmp2));
                g[i][j] = min(g[i][j],min(tmp1,tmp2));
            }
            //cout<<f[i][j]<<endl;
            if(j==k)
                ret = max(ret,max(f[i][j],g[i][j]));
        }
    }
    cout<<ret<<endl;
    return 0;
}

小红的口罩

题目描述

疫情来了,小红网购了 𝑛 个口罩。众所周知,戴口罩是很不舒服的。小红每个口罩戴一天的初始不舒适度为 𝑎𝑖。
小红有时候会将口罩重复使用(注:这是非常不卫生的!),每次重复使用时,该口罩的不舒适度会翻倍!小红想知道,自己在不舒适度总和不超过 𝑘 的情况下,最多能用现有的口罩度过多少天?

输入描述:

第一行输入两个正整数
𝑛 和 𝑘 ,分别代表口罩的总数、以及小红最多能忍受的不舒适度总和。
第二行输入 𝑛个正整数 𝑎𝑖 ,用空格隔开。分别代表每个口罩初始的不舒适度。
1≤𝑛≤105,1≤𝑎𝑖,𝑘≤1091≤n≤10 5 ,1≤a i,k≤10 9

输出描述:

一个整数,代表小红最多能度过的天数。

示例1

输入
2 30
2 3

输出
5

说明
第一天用第一个口罩,不舒适度为2。
第二天用第一个口罩,不舒适度为4。
第三天用第二个口罩,不舒适度为3。
第四天用第二个口罩,不舒适度为6。
第五天用第二个口罩,不舒适度为12。
总不舒适度为2+4+3+6+12=27,没有超过30。
可以证明,无论怎样分配,都无法度过6天且不舒适度总和不超过30

示例2

输入
3 5
7 6 8
输出
0

说明
显然,使用任何一个口罩都会使不舒适度超过5。

算法原理

使用一个小根堆就可以解决

代码

#include <iostream>
using namespace std;
#include <queue>
#include <functional>
int main()
{
    int n,k;
    cin>>n>>k;
    //小根堆
    priority_queue<int,vector<int>,greater<int>> q;
    for(int i = 0;i<n;i++)
    {
        int val;
        cin>>val;
        q.push(val);
    }
    int day = 0;
    int sum = 0;
    while(sum<=k)
    {
        int _top = q.top();
        q.pop();
        sum+=_top;
        _top*=2;
        q.push(_top);
        day++;
    }
    cout<<day-1<<endl;
    return 0;
}

春游

  • 链接:春游
    来源:牛客网

题目描述

盼望着,盼望着,东风来了,春天脚步近了。值此大好春光,老师组织了同学们出去划船,划船项目收费如下:
双人船最多坐两人,也可以坐一人,收费𝑎元
三人船最多坐三人,也可以坐两人或者一人,收费𝑏元

本次出游加上带队老师共𝑛人,如何安排能使得花费最小呢?

输入描述:

第一行给出一个正整数 𝑇(1≤𝑇≤1000),代表测试数据的组数。
接下来 𝑇行每行给出三个正整数𝑛,𝑎,𝑏,1≤𝑛,𝑎,𝑏≤109n,a,b,1≤n,a,b≤109 ,含义如题。

输出描述:

每组输入输出一行,代表最小的花费

示例1

输入
2
2 20 200
3 20 20
输出
20
20

算法原理

在这里插入图片描述

代码

#include <iostream>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        long long n,a,b;
        cin>>n>>a>>b;
        long long  ret = 0;
        if(n<=2)
        {
            ret = min(a,b);
        }
        else if(3*a<=2*b)//双人船
        {
            ret += (n/2)*a;
            if(n%2)
            {
                ret+=min(b-a,min(a,b));
            }
        }
        else
        {
            ret += (n/3)*b;
            if(n%3==1)
            {
                ret+=min(2*a-b,min(a,b));
            }
            else if(n%3==2)
            {
                ret += min(3*a-b,min(a,b));
            }
        }
        cout<<ret<<endl;
    }    
    return 0;
}

数位染色

算法原理

动态规划 0-1背包问题

在这里插入图片描述

代码

#include <iostream>
using namespace std;
#include <vector>
int main() {
    
    long long x;
    cin>>x;
    int sum = 0;
    vector<int> arr;
    arr.push_back(-1);
    while(x)
    {
        arr.push_back(x%10);
        sum+=x%10;
        x/=10;
    }
    if(sum%2==1)
    {
        cout<<"No";
        return 0;
    }
    int n = arr.size()-1;
    vector<vector<int>> dp(n+1,vector<int>(sum/2+1,false));
    //初始化
    dp[0][0] = true;
    for(int i = 1;i<=n;i++)
    {
        for(int j = 0;j<=sum/2;j++)
        {
            //选arr[i]
            if(j>=arr[i])
                dp[i][j]|=dp[i-1][j-arr[i]];    
            //不选
            dp[i][j]|=dp[i-1][j];
            //cout<<dp[i][j]<<" ";
        }
        //cout<<endl;
    }
    if(dp[n][sum/2])
        cout<<"Yes";
    else
        cout<<"No";
    return 0;
}

爱吃素数

算法原理

a,b的最大值为211,两个数相乘,然后再判断是否是素数,那么最糟糕的情况,时间复杂度也为 211,是超时的。
那么就需要根据素数的性质来优化判断了:

  1. a1&&b是素数 || b1&&a是素数 ,只有这两种情况,a*b才是素数
  2. a>1 ,b>1 -->a*b = x–>x有a,b得来,所以x一定不是素数

代码

#include <iostream>
using namespace std;
#include <cmath>
bool isPrime(long long n)
{
    if(n<2)
        return false;
    for(int i = 2;i<=sqrt(n);i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        long long a,b;
        cin>>a>>b;
        if(a==1&&isPrime(b))
        {
            cout<<"YES"<<endl;
        }
        else if(b==1&&isPrime(a))
        {
            cout<<"YES"<<endl;
        }
        else
        {
            cout<<"NO"<<endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值