• 【算法】求最小子集的和被5整除


    昨天面试了一家公式,面试上来问我,使用过哪些STL容器,我说了一下,然后又问从最简单的开始说。

    面试官:说说使用vector是需要注意什么?

    我:注意什么......。迭代器失效问题。

    面试官:你是看面经的吧

    我:我没有看面经,平时就刷题用用这些容器,使用时需要注意什么,使用时需要注意什么(我连说两遍),平时就是用,没注意到有什么。

    面试官:好吧,有看过STL源码剖析吗?

    我:内心:我刷过侯捷老师的视频,但是书没看过,看的比较久了,基本上已经忘了。于是脱口而出,没看过。

    面试官:好吧,你有了解什么性能优化的工具吗

    我:我注意到贵公司的笔试题中有类似的问题,我就只知道valgrind,但是没用过。

    面试官:好吧,那你做完笔试,有没有了解过呢?

    我:没有。

    面试官呵呵一笑:那你了解图吗?

    我:图我就知道有向图、无向图,图的算法:迪杰斯特拉、克鲁斯卡尔(没记错的话)

    面试官:图的存储呢?

    我:邻接表,邻接矩阵

    面试官:那什么时候用邻接表、邻接矩阵呢?

    我:秋招这么久,没有面试官问过我关于图的算法,这几个算法是我之前看的。现在有点忘了。

    面试官:(很惊讶),竟然没有人问过你图,好吧。你有参与过或者做过什么开源的项目吗?

    我:项目没有做过,看过levelDB源码中的切片和内存分配部分。

    面试官:好吧,那我们先做一道在线编程,我看看你的编程习惯,你用你熟悉的环境。

    我:我熟练的打开VS,面试官把题发了过来

    给定一个正整数集合S。该集合中的元素很多(大于100万),而且该集合满足以下条件:   
    条件A: 集合中的所有元素之和能被正整数P=5整除。?
        
    1.请你设计并实现一个程序,求出S的一个最小子集(最小的定义是集合元素个数最少)T,使得T也满足条件A. ?
    示例:当P=5的时候,
    如果
    Case1: 输入 S = {1, 2, 3, 4, 5}, 则输出 T = {5} (元素个数为1)
    Case2: 输入 S = {1,2,3,4}, 则输出 T = {1, 4} 或 T = {2, 3}
    Case3: ?输入 S = {1,2,6,7,12,17}, 则输出 T = {1,2,7} 或 T = {6,12,17}
    Case4: ?输入 S = {1,2,6,7,11, 12,13, 14, 17, 22}, 则输出 T = {1,14} 或 T = {2, 13}?...?
    注意:任意输出一个最小子集即可,不要求输出所有的最小子集。

    我最开始想的是暴力,思考了有3-5min,发现不行,后来想到可以用回溯求出所有子集,然后再根据子集去找,写了半天,没写出来怎么求子集(真是蠢,平时都可以的),后面面试官说了他的思路,先按下不提,我这里先把自己的思路再写写。

    (1)首先求子集;

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. // 求最小子集的和被5整除
    6. vectorint>> res; // 存放所有子集
    7. vector<int> path; // 存放子集
    8. void helper(vector<int>& nums, int index) {
    9. res.push_back(path);
    10. // 终止条件
    11. if (index >= nums.size()) {
    12. return;
    13. }
    14. for (int i = index; i < nums.size(); i++) {
    15. path.push_back(nums[i]);
    16. helper(nums, i + 1);
    17. path.pop_back();
    18. }
    19. }
    20. int main(int argc, char** argv) {
    21. res.clear();
    22. path.clear();
    23. vector<int> nums = { 1,2,3,4,5 };
    24. helper(nums, 0);
    25. for (int i = 0; i < res.size(); i++) {
    26. for (int j = 0; j < res[i].size(); j++) {
    27. cout << res[i][j];
    28. }
    29. cout << endl;
    30. }
    31. system("pause");
    32. return 0;
    33. }

    测试

    (2)对子集进行判断;

    path中存储的是某个子集,res中存储的是所有子集,需要对所有子集进行遍历;需要求的是最小的子集,那么先对子集path按照个数排序

    1. // 我这里贴是核心代码
    2. static bool cmp(vector<int>& a, vector<int>& b) {
    3. return a.size() < b.size();
    4. }
    5. sort(res.begin(), res.end(), cmp);
    6. for (int i = 0; i < res.size(); i++) {
    7. for (int j = 0; j < res[i].size(); j++) {
    8. cout << res[i][j];
    9. }
    10. cout << endl;
    11. }

    测试

    (3)对子集求和,找出满足条件的最小子集

    子集已经排序了,直接遍历找到第一个满足的就行

    1. // 贴的核心代码
    2. // 求和函数
    3. int add(vector<int>& nums) {
    4. int sum = 0;
    5. for (auto num : nums) {
    6. sum += num;
    7. }
    8. return sum;
    9. }
    10. for (int i = 0; i < res.size(); i++) {
    11. // 去掉空集
    12. if (res[i].size() == 0) {
    13. continue;
    14. }
    15. if (add(res[i]) % 5 == 0) {
    16. for (auto num:res[i]) {
    17. cout << num << "\t";
    18. }
    19. break;
    20. }
    21. }

    测试

    换一组数据

    S = {1,2,6,7,11, 12,13, 14, 17, 22}

     6和14是满足的,

    but,使用了回溯,整个程序复杂度就提上来了,也总算写出了(苦笑)

    注:上述代码在面试过程中并没有写出来,今天早上复盘的时候才写出来的

    贴上整体代码:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. /*
    6. 给定一个正整数集合S。该集合中的元素很多(大于100万),而且该集合满足以下条件:   
    7. 条件A: 集合中的所有元素之和能被正整数P=5整除。?
    8. 1.请你设计并实现一个程序,求出S的一个最小子集(最小的定义是集合元素个数最少)T,使得T也满足条件A. ?
    9. 示例:当P=5的时候,
    10. 如果
    11. Case1: 输入 S = {1, 2, 3, 4, 5}, 则输出 T = {5} (元素个数为1)
    12. Case2: 输入 S = {1,2,3,4}, 则输出 T = {1, 4} 或 T = {2, 3}
    13. Case3: ?输入 S = {1,2,6,7,12,17}, 则输出 T = {1,2,7} 或 T = {6,12,17}
    14. Case4: ?输入 S = {1,2,6,7,11, 12,13, 14, 17, 22}, 则输出 T = {1,14} 或 T = {2, 13}?...?
    15. 注意:任意输出一个最小子集即可,不要求输出所有的最小子集。
    16. */
    17. // 求最小子集的和被5整除
    18. vectorint>> res; // 存放所有子集
    19. vector<int> path; // 存放子集
    20. void helper(vector<int>& nums, int index) {
    21. res.push_back(path);
    22. // 终止条件
    23. if (index >= nums.size()) {
    24. return;
    25. }
    26. for (int i = index; i < nums.size(); i++) {
    27. path.push_back(nums[i]);
    28. helper(nums, i + 1);
    29. path.pop_back();
    30. }
    31. }
    32. // 排序
    33. static bool cmp(vector<int>& a, vector<int>& b) {
    34. return a.size() < b.size();
    35. }
    36. // 求和函数
    37. int add(vector<int>& nums) {
    38. int sum = 0;
    39. for (auto num : nums) {
    40. sum += num;
    41. }
    42. return sum;
    43. }
    44. int main(int argc, char** argv) {
    45. res.clear();
    46. path.clear();
    47. vector<int> nums = { 1,2,6,7,11, 12,13, 14, 17, 22 };
    48. helper(nums, 0);
    49. for (int i = 0; i < res.size(); i++) {
    50. for (int j = 0; j < res[i].size(); j++) {
    51. cout << res[i][j];
    52. }
    53. cout << endl;
    54. }
    55. cout << "************************" << endl;
    56. sort(res.begin(), res.end(), cmp);
    57. for (int i = 0; i < res.size(); i++) {
    58. for (int j = 0; j < res[i].size(); j++) {
    59. cout << res[i][j];
    60. }
    61. cout << endl;
    62. }
    63. cout << "************************" << endl;
    64. for (int i = 0; i < res.size(); i++) {
    65. // 去掉空集
    66. if (res[i].size() == 0) {
    67. continue;
    68. }
    69. if (add(res[i]) % 5 == 0) {
    70. for (auto num:res[i]) {
    71. cout << num << "\t";
    72. }
    73. break;
    74. }
    75. }
    76. system("pause");
    77. return 0;
    78. }

    话接上回,我用回溯没有写出来,说了一下我的思路,面试官和我说了他的思路

    【可以先预处理一波,所有数字先对5取余,得到的数字是在0-4范围内,然后再用5个桶,类似桶排序,把数字存起来,再进行判断(取余、存储我理解了,那么怎么和原数据进行对应的)】,我没有理解面试官后面的意思(苦笑),也没有顺着他的思路写出来。

    面试官:你这个回溯的复杂度是多少,你了解代码的复杂度吗,

    我:代码的复杂度分为时间复杂度和空间复杂度,回溯的复杂度,我还不会分析(尴尬)。

    后面就聊聊我的基本情况,今年的大环境。面试官人很好,是大佬级别的。

  • 相关阅读:
    Python 潮流周刊第 42 期(摘要)+ 赠书《流畅的Python》6本
    大语言模型底层架构丨带你认识Transformer
    掌握Explain分析性能瓶颈、避免索引失效
    el7升级Apache模块编译
    操作系统——并发相关问题
    搜索与图论总结
    c++成员变量和函数的储存
    携创教育:2022年10月自考英语二高分技巧有哪些?
    设计模式-原型模式
    【Mongo 实战】——库备份和恢复,指定集合导出和导入
  • 原文地址:https://blog.csdn.net/Zhouzi_heng/article/details/127608979