Topic 1:笨小猴(质数判断的几种优化方式,容器使用的取舍)

#include <bits/stdc++.h>
using namespace std;
bool isPrime(int n)
{
if(n <= 1) return false;
if(n <= 3) return true; // 2和3是质数
if(n % 2 == 0 || n % 3 == 0) return false; // 排除2和3的倍数
// 只需检查6n±1形式的因数
for(int i = 5; i*i <= n; i += 6)
{
if(n % i == 0 || n % (i+2) == 0) return false;
}
return true;
}
int main()
{
string s; cin >> s;
int freq[26] = {0};
for (char c : s) freq[tolower(c)-'a']++;
int maxn = *max_element(freq, freq+26);
int minn = 101;// 最小可能为0, 所以不能用*min_element处理,手写一个
for (int n : freq)
{
if (n > 0 && n < minn) minn = n;
}
int diff = maxn - minn;
if (isPrime(diff)) cout << "Lucky Word\n" << diff;
else cout << "No Answer\n0";
}
另外选取几种判断质数的方式,忘了就回来看看
朴素判断:
bool isPrime(int n) {
if(n <= 1) return false; // 1不是质数
for(int i = 2; i < n; i++) { // 检查2到n-1
if(n % i == 0) return false; // 能被整除就不是
}
return true;
}
平方根判断:只需判断到平方根,因为如果n有因数,一定会被分解成<=根号n的两个因数
bool isPrime(int n) {
if(n <= 1) return false;
for(int i = 2; i*i <= n; i++) { // i <= sqrt(n)
if(n % i == 0) return false;
}
return true;
}
跳过偶数:除了2,所有偶数都不是质数
bool isPrime(int n) {
if(n <= 1) return false;
if(n == 2) return true; // 单独处理2
if(n % 2 == 0) return false; // 排除其他偶数
for(int i = 3; i*i <= n; i += 2) { // 只检查奇数
if(n % i == 0) return false;
}
return true;
}
6n+(-)1法则:更高级的数学原理——所有质数(除了2和3)都符合6n±1的形式。即:质数只能是6n+1或6n-1
bool isPrime(int n) {
if(n <= 1) return false;
if(n <= 3) return true; // 2和3是质数
if(n % 2 == 0 || n % 3 == 0) return false; // 排除2和3的倍数
// 只需检查6n±1形式的因数
for(int i = 5; i*i <= n; i += 6) {
if(n % i == 0 || n % (i+2) == 0)
return false;
}
return true;
}
Topic 2:主持人调度(一)(贪心)

#include <memory>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param schedule int整型vector<vector<>>
* @return bool布尔型
*/
struct compare
{
bool operator()(const vector<int>& a, const vector<int>& b)// 写个比较用的仿函数
{
return a[1] < b[1]; // a 的结束时间(数组第二个元素) < b 的结束时间,则 a 排在前面
}
};
bool hostschedule(vector<vector<int> >& schedule)
{
int cl = 0;
vector<int> res(schedule.size() * 2);
sort(schedule.begin(), schedule.end(), compare());// 对原始数据排序,利用仿函数规则
for(const auto& s : schedule)
{
for(const auto& e : s)
{
if(e >= cl)
{
res.push_back(e);
cl = e;
}
else return false;
}
}
return true;
}
};
初步考虑是这样,不过空间上还能优化,不用输出,不用储存,所以可以考虑不用额外的res,直接用下标+[]实现比对
#include <memory>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param schedule int整型vector<vector<>>
* @return bool布尔型
*/
struct compare
{
bool operator()(const vector<int>& a, const vector<int>& b)// 写个比较用的仿函数
{
return a[1] < b[1]; // a 的结束时间(数组第二个元素) < b 的结束时间,则 a 排在前面
}
};
bool hostschedule(vector<vector<int> >& schedule)
{
sort(schedule.begin(), schedule.end(), compare());// 对原始数据排序,利用仿函数规则
int cl = schedule[0][1];// 最早那个活动的结束时间
for(int i = 1; i < schedule.size(); ++i)// 从第二次活动开始遍历其结束时间
{
if(schedule[i][0] < cl) return false;// 本次活动开始时间和上一次结束时间对比,<意味着有时间冲突,return false
cl = schedule[i][1];
}
return true;
}
};
Topic 3:分割等和子集

其实是01背包的一个变体,推荐做这题之前先去把01背包和滚动数组的两题先写了
带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili
关于01背包的dp[i][j]的dp含义我觉得卡尔讲的还不是特别清楚,这里我选取了另一位老师的解法

这个我觉得相对清晰,在这题中,dp[i][j]表示从0-i个数中选出的元素,最后总和为j
然后如果是有重量和价值的01背包,dp[i][j]就表示从0-i个物品中选出总重为j的物品,并且这些物品有最多的价值
所以dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])就可以理解成,最后的i我不选,因为我之前i-1时,背包容量j已经凑够了,所以是dp[i - 1][j]。最后的i我选,意味着j还没凑够,所以j此时就是j - weight[i],刚好还能容纳最后那个i,此时再加上它的价值就是dp[i - 1][j - weight[i]] + value[i]
然后再用滚动数组将二维压缩成一维,以示例1为例,以下是滚动数组的模拟过程,实际上就是用一个一维数组不断刷新并累加数据,这里注意滚动数组一定要倒着遍历,从前遍历的数据会影响后续的结果,会重复相加;
我既是现在的我,也是下一次行动中之前的我


#include <iostream>
#include <vector>
using namespace std;
int main()
{
// 抽象为01背包问题,题目中数组元素相当于物品,其重量和价值都是元素的值
// 抽出的数之和 = 剩下数之和 = 总数/2 = 背包容量
// 如果找到有物品能够装满背包容量,也就意味着这个数组可以取出若干个数,使得取出的数之和和剩下的数之和相同
// 状态转移方程:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
// dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]) 重量和价值都是元素的值
// 一维记得要倒序遍历,两层循环不能颠倒,先物品后重量,二维无所谓
int n, sum = 0; cin >> n;
vector<int> nums(n);
for(int i = 0; i < n; ++i)
{
cin >> nums[i];
sum += nums[i]; // 读取数组元素并计算总和sum
}
if (sum % 2 != 0) // 如果总和sum为奇数,直接输出false,因为无法均分
{
cout << "false";
return 0;
}
int target = sum / 2; // 计算目标和target,即总和的一半
vector<int> dp(target + 1, 0);
// 初始化动态规划数组dp,dp[j]表示容量为j的背包能装的最大价值
// 这里价值和重量都是nums[i],所以dp[j]表示能否凑出和为j的子集
for(int i = 0; i < nums.size(); i++)
{
for(int j = target; j >= nums[i]; j--) // 倒序遍历,防止重复计算
{
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);// 状态转移方程:不选择当前数字或选择当前数字
}
}
if (dp[target] == target) cout << "true";// 如果dp[target]等于target,说明可以凑出和为target的子集
else cout << "false";
return 0;
}
4671

被折叠的 条评论
为什么被折叠?



