Coding Practice,48天强训(25)
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-1if(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; // 单独处理2if(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 falsecl = 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;
}