【C++】 —— 笔试刷题day_21

一、爱丽丝的人偶

题目解析

现在存在n个玩偶,每个玩偶的身高是1、2、3......n

现在我们要对这些玩偶进行排序(如果x人偶,它左右两边的玩偶一个比x高、一个比x矮,那这个玩偶就会爆炸)。

我们不想要任何一个人偶爆炸,题目输入一个n,让我们返回满足条件的排列。

算法思路

这道题,可以说比较简单了,我们要让i人偶比i-1i+1位置的人偶高或者低;

我们可以这样去排列:1, n , 2 , n-1 , 3 , n-2......

这样我们可以发现,任何一个位置,它都是比左右两个人偶高或者低的;

那这道题我们就可以从1n开始放置人偶 ,所以只需要定义两个变量分别从1n开始向中间遍历。

**这里有一个要注意的点:**当我们放置完l人偶后,l是可能等于r

如果我们不做判断,那就可能放置两个身高一样的人偶:1 3 2 2

所以我们要进行判断,如果放置完l的人偶后,让l++,再判断l是否小于等于r :(如果l<=r就放置r,否则就不放置)。

这里我们也没有必要将数据存储起来,直接输出即可。

代码实现

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int l = 1,r = n;
    while(l<=r)
    {
        cout<<l<<' ';
        l++;
        if(l<=r)
        {
            cout<<r<<' ';
            r--;
        }
    }
    cout<<endl;
    return 0;
}

二、集合

题目解析

题目给定两个集合(数组)AB,让我们求出AB的交集(A+B);

输出时要求按照升序输出。

算法思路

对于这道题,就类似于归并排序中,合并两个数组的操作,但是这道题目求的是交集,也就是最后结果中不能存在相同的元素。

思路一:排序+合并数组

对于AB,题目并没有说这两个数组是有序的,那我们要进行和并数组操作就要先对AB进行排序;

排完序之后,我们使用lr分别遍历两个数组(注意:要求升序且不能存在重读元素

如果l位置元素等于r位置元素就先加入到结果数组中,让r++(或者l++);

如果l位置元素大于r位置元素,就将r位置元素加入到结果数组中;

如果l位置元素小于r位置元素,就将l位置元素加入到结果数组中。

最后遍历结束之后,lr可能没有遍历完,所以要将A或者B中剩余的元素加入到结果数组中。

思路二:set去重+排序

对于这种思路就有一点投机取巧了:

set中是不允许出现重复元素的,并且set底层是红黑树,是一个平衡搜索二叉树;使用迭代器遍历是有序的。

代码实现

cpp 复制代码
#include <iostream>
#include <set>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    //set去重+排序
    set<int> ret;
    int x;
    for (int i = 0; i < n; i++) {
        cin >> x;
        ret.insert(x);
    }
    for (int i = 0; i < m; i++) {
        cin >> x;
        ret.insert(x);
    }
    for (auto& e : ret) {
        cout << e << ' ';
    }
    cout << endl;
}

三、最长回文子序列

题目解析

题目给定一个字符串str,然后让我们在这个字符串中找到最长的回文子序列,然后输出它的长度。

算法思路

对于这道题,初看可能没什么思路

这里我们可以选取不连续的元素构成子序列,那这如何去找啊?

先说整道题用什么方法去解决:动态规划

要使用动态规划去解决这道问题,那我们就要搞清楚状态表示和状态转移方程

状态表示: dp[i][j]表示区间[i,j]内最长的回文子序列的长度

**状态转移方程:**对于状态转移方程,这里就要好好的分析一下了:

dp[i][j]表示的是区间[i,j]内最长的回文子序列的长度,但是可能i>j或者i == j或者i<j

  • i > j:这种情况肯定是不存在区间[i,j]的,那此时dp[i][j] = 0

  • i == j:这种情况,区间[i,j]只有一个元素,那此时这一个元素它可以构成一个回文子序列;所有dp[i][j] = 1

  • i < j:这种情况,区间[i,j]内是大于等于2个元素的;这时候我们就要看i位置和j位置是否相等了。

    如果str[i] == str[j],区间[i,j]中最长回文子序列的长度就等于[i+1,j-1]中最长回文子序列的长度再加上2

    如果str[i] == str[j],我们不能直接去找区间[i+1,j-1]内的最长回文子序列 ,因为i+1位置的元素和j位置的元素、i位置的元素和j-1位置的元素是可能相等的;所以我们要找的就是区间[i+1,j]和区间[i,j-1]中最长回文子序列长度的最大值。

填表顺序: 这里我们填dp[i][j]时用到了dp[i][j-1]dp[i+1,j]dp[i+1,j-1];那我们填表的顺序:从下到上,每一行从左到右。

**初始化:**我们在填第n-1行要用到第n行的数据、填写第1列时要用到第0列的数据,所以我们要初始化第n行和第0列。

**返回:**我们最后要的结果在dp[0][n-1]里存着(区间[0,n-1]内最长回文子序列的长度),最后输出dp[0][n-1]即可。

代码实现

cpp 复制代码
#include <iostream>
using namespace std;
const int N = 1001;
int dp[N][N] = {0};
int main() {
    string str;
    cin>>str;
    for(int i = str.size()-1;i>=0;i--)
    {
        for(int j = 0;j<str.size();j++)
        {
            if(i>j)
                dp[i][j] = 0;
            else if(i == j)
                dp[i][j] = 1;
            else 
            {
                if(str[i] == str[j])
                    dp[i][j] = dp[i+1][j-1]+2;
                else
                    dp[i][j] = max(dp[i+1][j],dp[i][j-1]);
            }
        }
    }
    cout<<dp[0][str.size()-1]<<endl;
    return 0;
}

到这里本篇文章内容就结束了
感谢各位的支持

相关推荐
夜夜敲码6 分钟前
C语言教程(十五):C 语言函数指针与回调函数详解
c语言·开发语言
Cao1234567893218 分钟前
判断是否为闰年(C语言)
c语言·开发语言
菜鸟射手11 分钟前
QT creater和vs2017文件路径问题
linux·c++·windows·qt
wuqingshun31415918 分钟前
蓝桥杯17. 机器人塔
c++·算法·职场和发展·蓝桥杯·深度优先
是发财不是旺财19 分钟前
跟着deepseek学golang--认识golang
开发语言·后端·golang
simple_whu31 分钟前
解决编译pcl时报错‘chrono_literals‘: is not a member of ‘std‘
c++·windows·visual studio
图灵科竞社资讯组1 小时前
图论基础:图存+记忆化搜索
算法·图论
Bruce_Liuxiaowei1 小时前
基于Python+Flask的MCP SDK响应式文档展示系统设计与实现
开发语言·python·flask·mcp
chuxinweihui1 小时前
数据结构——栈与队列
c语言·开发语言·数据结构·学习·算法·链表