【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;
}

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

相关推荐
树叶@17 分钟前
Python数据分析7
开发语言·python
wydaicls20 分钟前
十一.C++ 类 -- 面向对象思想
开发语言·c++
Biomamba生信基地1 小时前
R语言基础| 下载、安装
开发语言·r语言·生信·医药
姜君竹1 小时前
QT的工程文件.pro文件
开发语言·c++·qt·系统架构
思捻如枫1 小时前
C++数据结构和算法代码模板总结——算法部分
数据结构·c++
奇树谦1 小时前
使用VTK还是OpenGL集成到qt程序里哪个好?
开发语言·qt
嘉陵妹妹1 小时前
深度优先算法学习
学习·算法·深度优先
VBA63371 小时前
VBA之Word应用第三章第十节:文档Document对象的方法(三)
开发语言
老胖闲聊1 小时前
Python Rio 【图像处理】库简介
开发语言·图像处理·python
GalaxyPokemon2 小时前
LeetCode - 53. 最大子数组和
算法·leetcode·职场和发展