Topic 1:爱丽丝的人偶(一)(贪心)
两个指针一个从左找矮,一个从右找高,高矮高矮高矮....or 矮高矮高矮高...这样去排,高放奇数、矮放偶数,或者反过来,都行
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> res(n);
int l = 1, r = n;
for (int i = 0; i < n; i++)
{
if (i % 2 == 0) res[i] = l++;
else res[i] = r--;
}
for (const auto& e : res) cout << e << " ";
return 0;
}
Topic 2:集合
其实就是一个简单的合并字符串问题,但是带了一个集合的性质——集合有去重性,没有重复元素,额外加个条件判断即可;
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, m;
// 循环处理每组输入数据
while (cin >> n >> m)
{
vector<int> a(n), b(m), res; // a 和 b 是两个输入集合,res 用于存合并结果
// 读取集合 A 的元素
for (int i = 0; i < n; i++) cin >> a[i];
// 读取集合 B 的元素
for (int i = 0; i < m; i++) cin >> b[i];
// 对两个集合进行排序(为合并做准备)
sort(a.begin(), a.end());
sort(b.begin(), b.end());
// 双指针合并过程
int i = 0, j = 0;
while (i < n && j < m)
{
int tmp;
if (a[i] < b[j])
{
tmp = a[i++]; // a 的当前元素小,加入结果,并移动指针 i
}
else if (a[i] > b[j])
{
tmp = b[j++]; // b 的当前元素小,加入结果,并移动指针 j
}
else
{
tmp = a[i]; // 相等时,只加入一次
i++;
j++; // 两个指针都向前移动
}
// 避免重复元素加入结果
if (res.empty() || res.back() != tmp)
{
res.push_back(tmp);
}
}
// 把 a 中剩下的元素加入(去重)
while (i < n)
{
if (res.empty() || res.back() != a[i]) res.push_back(a[i]);
i++;
}
// 把 b 中剩下的元素加入(去重)
while (j < m)
{
if (res.empty() || res.back() != b[j]) res.push_back(b[j]);
j++;
}
// 输出结果集合(格式化输出,注意空格)
for (int k = 0; k < res.size(); k++)
{
if (k > 0) cout << " "; // 除了第一个元素前都加空格
cout << res[k];
}
cout << endl; // 输出结束换行
}
return 0;
}
当然你stl用的够熟就直接用set,set能自动去重排序,代码写的少
#include <bits/stdc++.h>
using namespace std;
// 使用 set 容器,自动去重和排序
int main()
{
int n, m; // 分别存储集合A和集合B的元素个数
// 循环读取,适用于多组输入
while (cin >> n >> m)
{
set<int> s; // 创建一个集合用于存储合并后的数据,自动去重并升序排列
int tmp; // 临时变量用于读取每个输入的元素
// 读取集合A的元素并插入集合s
for (int i = 0; i < n; ++i)
{
cin >> tmp;
s.insert(tmp);
}
// 读取集合B的元素并插入集合s
for (int i = 0; i < m; ++i)
{
cin >> tmp;
s.insert(tmp);
}
// 按顺序输出集合s中的元素
bool first = true; // 标志是否是第一个输出的元素,用来控制空格
for (const auto& e : s)
{
if (!first) cout << " "; // 不是第一个就先输出一个空格
cout << e; // 输出当前数字
first = false; // 后续元素输出前加空格
}
cout << endl; // 每组输出后换行
}
return 0;
}
Topic 3:最长回文子序列(区间DP)
推导顺序:
不同于常规的dp题目,很多遍历顺序都是从上到下,从左到右,这一题的dp如果转化成平面图如上,所求的结果是储存在右上角的,也就是i为0,j为str.size() - 1时,也就是说填表的顺序是由下至上,由左至右,这样才能保证推导的逻辑正确,红线左下的部分表示i > j,而这显然不合法,故保持为0即可,[i,i]的部分表示i和j重叠指向一个字符,一个字符被视作单独1个回文串,故初始化为1即可;
所以针对上述例子,去除[i,i]和无效的红叉(初始化设置为0,不影响计算结果)的部分,实际推导的填表顺序是
[i+2,j] -> [i+1,j-1] -> [i+1,j] -> [i,j-2] -> [i,j-1] -> [i, j]
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串 一个字符串由小写字母构成,长度小于5000
* @return int整型
*/
int longestPalindromeSubSeq(string s)
{
// dp[i][j] -- i,j位置所能组成的最长回文子序列
// if (s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
// else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
int n = s.size(), res;
vector<vector<int>> dp(n, vector<int>(n, 0));
for(int i = n - 1; i >= 0; --i)
{
for(int j = 0; j < n; ++j)
{
if(i > j) continue;
else if(i == j) dp[i][j] = 1;
else
{
if (s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
res = dp[0][n - 1];
return res;
}
};