9.其他
HJ108. 求最小公倍数
-
描述
正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。 数据范围:1≤a,b≤100000 输入描述:输入两个正整数A和B。 输出描述:输出A和B的最小公倍数。 示例1 输入: 5 7 输出: 35 示例2 输入: 2 4 输出: 4
-
思路
先获取两个数的最大公因数p,最小公倍数是m*n/p
-
代码
#include <iostream> using namespace std; int getMaxFactor(int m, int n) { int res = min(m,n); while (res > 1) { if(m % res == 0 && n % res == 0) break; res--; } return res; } int getMinMultiple(int m, int n) { int k = getMaxFactor(m, n); return m*n/k; } int main() { int m; int n; cin >> m >> n; cout << getMinMultiple(m, n); return 0; }
HJ28.素数伴侣
-
描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的 N ( N 为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。 输入: 有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。 输出: 输出一个整数 K ,表示你求得的“最佳方案”组成“素数伴侣”的对数。 数据范围:1≤n≤100,输入的数据大小满足 2≤val≤30000 输入描述:输入说明:1 输入一个正偶数 n;2 输入 n 个整数 输出描述:求得的“最佳方案”组成“素数伴侣”的对数。 示例1 输入: 4 2 5 6 13 输出: 2 示例2 输入: 2 3 6 输出: 0
-
思路
-
概念
-
二分图
-
顶点分为两个不想交的集合(U,V)
-
集合内的点两两不相连
-
二分图匹配
- 匹配:如果选择一条边就会连通对应的两个点,就会构成一个匹配。规定一个顶点最多只能构成一个匹配
- 最大匹配:对于一张二分图,构成匹配数量最多的情况叫最大匹配
- 完美匹配:所有定点都有了匹配
-
-
增广路径:二分图的匹配中,有一条路径的首尾是非匹配点,路径中其他点均是匹配点,这条路径就是一条增广路径。(即一条首尾相连的路径)
-
匈牙利算法
- 寻找增广路径,从而达成最大匹配。
- 本质是一个调整匹配的过程,通过递归调用的形式尝试调整已经占据了发生冲突位置的匹配,腾出位置来给右边的节点
-
-
变量:
- vector ev、vector od:记录所有奇数/偶数
- vector evVis、vector odVis:记录所有该顶点匹配的对应顶点
- vector visited:当前轮次(对应不同的i),是否已遍历当前顶点
- vector<vector> allPair:记录所有的匹配
-
思路
- 针对每个左侧图的i,将所有的visited清零,深度搜索找到能匹配的点,并返回1
- 读取每个右侧图的j,如果该右侧顶点没有遍历切存在匹配i-j,进入匹配
- 进入匹配先将visited状态修改
- 进行匹配
- 右侧点未匹配,则直接修改匹配
- 右侧点已经匹配,重新将其原来对应的左侧点送入递归重新调整匹配
- 确认匹配后记录左右点对应的匹配点
参考:https://www.cnblogs.com/techflow/p/13522712.html
https://zhuanlan.zhihu.com/p/534989336
- 代码
#include <iostream> using namespace std; #include <vector> class Solution { private: vector<vector<bool>> allPair; vector<int> evVis; vector<int> odVis; vector<int> visited; public: Solution(vector<int> ev, vector<int> od) { int m = ev.size(); int n = od.size(); allPair.resize(m, vector<bool> (n, false)); for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { if(isPrime(ev[i] + od[j])) allPair[i][j] = true; } } evVis.resize(m, -1); odVis.resize(n, -1); } bool isPrime(int num) { for(int i = 2; i < num/2; i++) if(num % i == 0) return false; return true; } int dfs(int i) { for(int j = 0; j < odVis.size(); j++) { if(!visited[j] && allPair[i][j]) { visited[j] = true; if(odVis[j] == -1 || dfs(odVis[j])) { evVis[i] = j; odVis[j] = i; return 1; } } } return 0; } int getCouple() { int res = 0; for(int i = 0; i < evVis.size(); i++) { visited.assign(odVis.size(),0); res += dfs(i); } return res; } }; int main() { int n; cin >> n; vector<int> nums(n); vector<int> ev,od; int num; for(int i = 0; i < n; i++) { cin >> num; if(num % 2 == 0) od.push_back(num); else ev.push_back(num); } Solution sol(ev, od); cout << sol.getCouple() << endl; return 0; }
-
HJ60. 查找组成一个偶数最接近的两个素数
-
描述
任意一个偶数(大于2)都可以由2个素数组成,组成偶数的2个素数有很多种情况,本题目要求输出组成指定偶数的两个素数差值最小的素数对。 数据范围:输入的数据满足4≤n≤1000 输入描述:输入一个大于2的偶数 输出描述:从小到大输出两个素数 示例1 输入: 20 输出: 7 13 示例2 输入: 4 输出: 2 2
-
思路
从一半开始从大到小遍历,判断是否为素数
-
代码
#include <iostream> using namespace std; bool isPrime(int n) { for(int i = 2; i < n/2; i++) if(n%i == 0) return false; return true; } void getPrimeCouple(int n) { int a = n/2; int b; while(a) { b = n - a; if(!isPrime(a)){ a--; continue; } if(isPrime(b)) break; a--; } cout << a << endl; cout << b << endl; } int main() { int n; cin >> n; getPrimeCouple(n); return 0; }
leetcode 994. 腐烂的橘子
-
描述
在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一: 值 0 代表空单元格; 值 1 代表新鲜橘子; 值 2 代表腐烂的橘子。 每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 示例 1: 输入:grid = [[2,1,1],[1,1,0],[0,1,1]] 输出:4 示例 2: 输入:grid = [[2,1,1],[0,1,1],[1,0,1]] 输出:-1 解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。 示例 3: 输入:grid = [[0,2]] 输出:0 解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。 提示: m == grid.length n == grid[i].length 1 <= m, n <= 10 grid[i][j] 仅为 0、1 或 2
-
思路
使用bfs算法,先遍历烂橘子的周围,step++,直到遍历完为止
-
代码
#include <iostream> using namespace std; #include <vector> #include <queue> class Solution { int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; public: int orangesRotting(vector<vector<int>>& grid) { int step = -1; queue<pair<int,int>> que; bool isOnlyZero = true; for (auto ls:grid) for (auto x:ls) if (x) isOnlyZero = false; if(isOnlyZero) return 0; for (int i = 0; i < grid.size(); i++) for (int j = 0; j < grid[i].size(); j++) if (grid[i][j] == 2) que.emplace(i,j); while (!que.empty()) { int size = que.size(); step++; while(size--) { auto [x, y] = que.front(); que.pop(); for(int i = 0; i < 4; i++) { int nx = x + dirs[i][0]; int ny = y + dirs[i][1]; if (nx >= 0 && nx < grid.size() && ny >= 0 && ny < grid[nx].size() && grid[nx][ny] == 1) { que.emplace(nx, ny); grid[nx][ny] = 2; } } } } for (auto ls:grid) for (auto x:ls) if (1 == x) return -1; return step; } }; int main() { vector<vector<int>> grid; grid.push_back({2,1,1}); grid.push_back({0,1,1}); grid.push_back({1,0,1}); Solution sol; cout << sol.orangesRotting(grid) << endl; return 0; }
leetcode 204. 计算质数
-
描述
给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。 示例 1: 输入:n = 10 输出:4 解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 示例 2: 输入:n = 0 输出:0 示例 3: 输入:n = 1 输出:0 提示: 0 <= n <= 5 * 106
-
思路
- 暴力解答,直接枚举
- 空间换时间,列举所有数字初始化为质数,将所有数的倍数设置为合数
-
代码
#include <iostream> using namespace std; #include <vector> // class Solution { // public: // int countPrimes(int n) { // int res = 0; // bool isPrimes = true; // for (int i = 2; i < n; i++) { // isPrimes = true; // for (int j = 2; j * j <= i; j++) { // if(i % j == 0) isPrimes = false; // } // if (isPrimes){ // res++; // printf("%d\n",i); // } // } // return res; // } // }; class Solution { public: int countPrimes(int n) { int res = 0; vector<bool> isPrimes(n,true); for (int i = 2; i * i < n; i++) { if (isPrimes[i]) for (int j = i * i; j < n; j += i) isPrimes[j] = false; } for (int i = 2; i < n; i++) if (isPrimes[i]) res++; return res; } }; int main() { int n = 20; Solution sol; cout << sol.countPrimes(n) << endl; return 0; }
HJ25. 数据分类处理
-
描述
信息社会,有海量的数据需要分析处理,比如公安局分析身份证号码、 QQ 用户、手机号码、银行帐号等信息及活动记录。 采集输入大数据和分类规则,通过大数据分类处理程序,将大数据分类输出。 数据范围:1≤I,R≤100 ,输入的整数大小满足 0≤val≤2^31−1 输入描述:一组输入整数序列I和一组规则整数序列R,I和R序列的第一个整数为序列的个数(个数不包含第一个整数);整数范围为0~(2^31)-1,序列个数不限 输出描述:从R依次中取出R<i>,对I进行处理,找到满足条件的I: I整数对应的数字需要连续包含R<i>对应的数字。比如R<i>为23,I为231,那么I包含了R<i>,条件满足 。 按R<i>从小到大的顺序: (1)先输出R<i>; (2)再输出满足条件的I的个数; (3)然后输出满足条件的I在I序列中的位置索引(从0开始); (4)最后再输出I。 附加条件: (1)R<i>需要从小到大排序。相同的R<i>只需要输出索引小的以及满足条件的I,索引大的需要过滤掉 (2)如果没有满足条件的I,对应的R<i>不用输出 (3)最后需要在输出序列的第一个整数位置记录后续整数序列的个数(不包含“个数”本身) 序列I:15,123,456,786,453,46,7,5,3,665,453456,745,456,786,453,123(第一个15表明后续有15个整数) 序列R:5,6,3,6,3,0(第一个5表明后续有5个整数) 输出:30, 3,6,0,123,3,453,7,3,9,453456,13,453,14,123,6,7,1,456,2,786,4,46,8,665,9,453456,11,456,12,786 说明: 30----后续有30个整数 3----从小到大排序,第一个R<i>为0,但没有满足条件的I,不输出0,而下一个R<i>是3 6--- 存在6个包含3的I 0--- 123所在的原序号为0 123--- 123包含3,满足条件 示例1 输入: 15 123 456 786 453 46 7 5 3 665 453456 745 456 786 453 123 5 6 3 6 3 0 输出: 30 3 6 0 123 3 453 7 3 9 453456 13 453 14 123 6 7 1 456 2 786 4 46 8 665 9 453456 11 456 12 786 说明: 将序列R:5,6,3,6,3,0(第一个5表明后续有5个整数)排序去重后,可得0,3,6。 序列I没有包含0的元素。 序列I中包含3的元素有:I[0]的值为123、I[3]的值为453、I[7]的值为3、I[9]的值为453456、I[13]的值为453、I[14]的值为123。 序列I中包含6的元素有:I[1]的值为456、I[2]的值为786、I[4]的值为46、I[8]的值为665、I[9]的值为453456、I[11]的值为456、I[12]的值为786。 最后按题目要求的格式进行输出即可。
-
思路
- 将R排序并删除重复项
- 将每个R和J的元素对比,是否符合条件
- 都转换为string
- I中的元素与R元素第一个匹配,则将子串与R元素对比
- 将符合条件的元素和索引压入res
-
代码
#include <iostream> using namespace std; #include <vector> #include <algorithm> vector<int> sortAndDel(vector<int> nums) { sort(nums.begin(), nums.end()); if(nums.size() <= 1) return nums; int pre = nums[0]; vector<int> res; res.push_back(pre); for(int i = 1; i < nums.size(); i++) { if(nums[i] != pre) { pre = nums[i]; res.push_back(pre); } } return res; } bool isRight(int x, int y) { string a = to_string(x); string b = to_string(y); for(int i = 0; i < a.size(); i++) if(a[i] == b[0] && !a.substr(i,b.size()).compare(b)) return true; return false; } //取出R[i],对I进行处理,找到满足条件的I //条件:I证书对应的数字需要连续包含R[i],对I进行处理 vector<vector<pair<int,int>>> getRes(vector<int> I, vector<int> R) { //R[i]从小到大的顺序 R = sortAndDel(R); vector<vector<pair<int,int>>> res(R.size(), vector<pair<int,int>>()); for(int i = 0; i < R.size(); i++) { for(int j = 0; j < I.size(); j++) { if(isRight(I[j],R[i])) res[i].push_back({j, I[j]}); } } int num = 0; for(int i = 0; i < res.size(); i++) { if(res[i].size()) num = num + 2 + 2 * res[i].size(); } printf("%d ",num); for(int i = 0; i < res.size(); i++) { if(!res[i].size()) continue; //先输出R[i] 输出满足条件的I的个数 printf("%d %d ", R[i], res[i].size()); for(int j = 0; j < res[i].size(); j++) { //输出满足条件的I在I序列中的位置索引 输出I printf("%d %d ",res[i][j].first,res[i][j].second); } } printf("\n"); return res; } int main() { int m; cin >> m; vector<int> I(m); for(int i = 0; i < m; i++) cin >> I[i]; int n; cin >> n; vector<int> R(n); for(int i = 0; i < n; i++) cin >> R[i]; getRes(I,R); return 0; }