数组和集合的搜索

举报
用户已注销 发表于 2021/11/19 01:27:32 2021/11/19
【摘要】 目录 一,数组和集合的搜索 二,OJ实战 力扣 1. 两数之和(二分法) 力扣 167. 两数之和 II - 输入有序数组(二分法) 力扣 454. 四数相加 II(二分+计重) 力扣 136. 只出现一次的数字(基于计算的搜索) 力扣 137. 只出现一次的数字 II(基于计算的搜索) 力扣 260. 只出现...

目录

一,数组和集合的搜索

二,OJ实战

力扣 1. 两数之和(二分法)

力扣 167. 两数之和 II - 输入有序数组(二分法)

力扣 454. 四数相加 II(二分+计重)

力扣 136. 只出现一次的数字(基于计算的搜索)

力扣 137. 只出现一次的数字 II(基于计算的搜索)

力扣 260. 只出现一次的数字 III(基于计算的搜索)

力扣 268. 缺失数字(基于计算的搜索)


一,数组和集合的搜索

DFS、BFS一般用来解决树和图的搜索问题,对象空间是不是良序的,

而数组和集合的搜索,对象空间是良序的。

DFS、BFS一般把对象空间搜索一遍就能得到答案,比较复杂的问题往往复杂度在于如何高效剪枝,

而数组和集合的搜索,往往搜索一遍还得不到答案,

比如寻找2个数的和为给定数的所有数对,需要两层的嵌套搜索,暴力时间是O(n^2),

一些技巧,比如二分等,可以用在数组和集合的搜索问题上,但不能用于DFS、BFS

 

二,OJ实战

力扣 1. 两数之和(二分法)

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路:枚举一个数,嵌套搜索另外一个数的时候采用二分法


  
  1. //给vector拓展,加上id并排序
  2. template<typename T>
  3. bool cmp(T x,T y)
  4. {
  5. return x<y;
  6. }
  7. template<typename T>
  8. vector<pair<T,int>> sortWithId(vector<T>v)
  9. {
  10. vector<pair<T,int>>ans;
  11. ans.resize(v.size());
  12. for(int i=0;i<v.size();i++)ans[i].first=v[i],ans[i].second=i;
  13. sort(ans.begin(),ans.end(),[](pair<T,int>p1,pair<T,int>p2){return cmp(p1.first,p2.first);});
  14. return ans;
  15. }
  16. //2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
  17. template<typename T>
  18. vector<vector<int>> findSum(vector<T>v1,vector<T>v2,T s)
  19. {
  20. vector<vector<int>>ans;
  21. vector<int>tmp(2);
  22. vector<pair<T,int>>v3=sortWithId(v2);
  23. sort(v2.begin(), v2.end(),cmp<T>);
  24. for(int i=0;i<v1.size();i++)
  25. {
  26. auto it1=lower_bound(v2.begin(), v2.end(), s-v1[i]);
  27. auto it2=upper_bound(v2.begin(), v2.end(), s-v1[i]);
  28. tmp[0]=i;
  29. for(auto j=it1;j<it2;j++)
  30. {
  31. tmp[1]=v3[j-v2.begin()].second;
  32. ans.push_back(tmp);
  33. }
  34. }
  35. return ans;
  36. }
  37. //删除二维vector中,含有重复元素的行
  38. template<typename T>
  39. vector<vector<T>> deleteSame(vector<vector<T>>&v)
  40. {
  41. vector<vector<int>>ans;
  42. ans.reserve(v.size());
  43. for(int i=0;i<v.size();i++)
  44. {
  45. for(int j=0;j<v[i].size();j++)for(int k=j+1;k<v[i].size();k++)if(v[i][j]==v[i][k])goto here;
  46. ans.push_back(v[i]);
  47. here:;
  48. }
  49. return ans;
  50. }
  51. class Solution {
  52. public:
  53. vector<int> twoSum(vector<int>& nums, int target) {
  54. vector<vector<int>>ans=findSum(nums,nums,target);
  55. return deleteSame(ans)[0];
  56. }
  57. };

力扣 167. 两数之和 II - 输入有序数组(二分法)

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

说明:

返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:

输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

 

题目和  力扣OJ 1. 两数之和  基本没啥差别。


  
  1. //vector加一个数
  2. template<typename T1,typename T2>
  3. void fjia(vector<T1> &v,T2 n)
  4. {
  5. for(int i=v.size()-1;i>=0;i--)v[i]+=n;
  6. }
  7. class Solution {
  8. public:
  9. vector<int> twoSum(vector<int>& nums, int target) {
  10. vector<vector<int>>ans=findSum(nums,nums,target);
  11. vector<int>res = deleteSame(ans)[0];
  12. fjia(res,1);
  13. return res;
  14. }
  15. };

PS:省略重复代码

力扣 454. 四数相加 II(二分+计重)

给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -2^28 到 2^28 - 1 之间,最终结果不会超过 2^31 - 1 。

例如:

输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]

输出:
2

解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0


  
  1. //给vector拓展,加上id并排序
  2. template<typename T>
  3. bool cmp(T x,T y)
  4. {
  5. return x<y;
  6. }
  7. template<typename T>
  8. vector<pair<T,int>> sortWithId(vector<T>v)
  9. {
  10. vector<pair<T,int>>ans;
  11. ans.resize(v.size());
  12. for(int i=0;i<v.size();i++)ans[i].first=v[i],ans[i].second=i;
  13. sort(ans.begin(),ans.end(),[](pair<T,int>p1,pair<T,int>p2){return cmp(p1.first,p2.first);});
  14. return ans;
  15. }
  16. //2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
  17. template<typename T>
  18. vector<vector<int>> findSum(vector<T>v1,vector<T>v2,T s)
  19. {
  20. vector<vector<int>>ans;
  21. int m=min((long long)(v1.size()*v2.size()),(long long)12345678);
  22. ans.reserve(m);
  23. vector<int>tmp(2);
  24. vector<pair<T,int>>v3=sortWithId(v2);
  25. sort(v2.begin(), v2.end(),cmp<T>);
  26. for(int i=0;i<v1.size();i++)
  27. {
  28. auto it1=lower_bound(v2.begin(), v2.end(), s-v1[i]);
  29. auto it2=upper_bound(v2.begin(), v2.end(), s-v1[i]);
  30. tmp[0]=i;
  31. for(auto j=it1;j<it2;j++)
  32. {
  33. tmp[1]=v3[j-v2.begin()].second;
  34. ans.push_back(tmp);
  35. }
  36. }
  37. return ans;
  38. }
  39. //枚举2个vector的两数之和
  40. template<typename T>
  41. vector<T> everySum(vector<T>&v1,vector<T>&v2)
  42. {
  43. vector<T>ans;
  44. ans.resize(v1.size()*v2.size());
  45. int k=0;
  46. for(int i=0;i<v1.size();i++)for(int j=0;j<v2.size();j++)ans[k++]=v1[i]+v2[j];
  47. return ans;
  48. }
  49. //判断有序数组中有多少个不同的数
  50. template<typename T>
  51. int getDifNum(vector<T>v)
  52. {
  53. int ans=1;
  54. for(int i=1;i<v.size();i++)ans+=(v[i]!=v[i-1]);
  55. return ans;
  56. }
  57. //收缩计数,把[1 1 4 4 4]变成[(1,2)(4,3)]
  58. template<typename T>
  59. vector<pair<T,int>> fshr(vector<T>v)
  60. {
  61. vector<pair<T,int>>ans;
  62. if(v.size()==0)return ans;
  63. sort(v.begin(),v.end());
  64. ans.resize(getDifNum(v));
  65. ans[0]=make_pair(v[0],1);
  66. for(int i=1,j=0;i<v.size();i++)
  67. {
  68. if(v[i]==v[i-1])ans[j].second++;
  69. else ans[++j]=make_pair(v[i],1);
  70. }
  71. return ans;
  72. }
  73. //提取pair数组的first
  74. template<typename T1,typename T2>
  75. vector<T1> fdraw(vector<pair<T1,T2>>v)
  76. {
  77. vector<T1>ans(v.size());
  78. for(int i=0;i<v.size();i++)ans[i]=v[i].first;
  79. return ans;
  80. }
  81. //提取pair数组的second
  82. template<typename T1,typename T2>
  83. vector<T2> fdraw2(vector<pair<T1,T2>>v)
  84. {
  85. vector<T2>ans(v.size());
  86. for(int i=0;i<v.size();i++)ans[i]=v[i].second;
  87. return ans;
  88. }
  89. class Solution {
  90. public:
  91. int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
  92. vector<int> v1 = everySum(A,B),v2 = everySum(C,D);
  93. vector<pair<int,int>>v3=fshr(v1),v4=fshr(v2);
  94. vector<int> v5=fdraw(v3),v6=fdraw(v4);
  95. vector<int> v7=fdraw2(v3),v8=fdraw2(v4);
  96. vector<vector<int>> ans = findSum(v5,v6,0);
  97. int res=0;
  98. for(int i=0;i<ans.size();i++)res+=v7[ans[i][0]]*v8[ans[i][1]];
  99. return res;
  100. }
  101. };

力扣 136. 只出现一次的数字(基于计算的搜索)

题目:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1
示例 2:

输入: [4,1,2,1,2]
输出: 4

 

代码:


  
  1. class Solution {
  2. public:
  3. int singleNumber(vector<int>& nums) {
  4. int ans = 0;
  5. for (auto it = nums.begin(); it != nums.end(); it++)ans ^= *it;
  6. return ans;
  7. }
  8. };

 

力扣 137. 只出现一次的数字 II(基于计算的搜索)

题目:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,3,2]
输出: 3
示例 2:

输入: [0,1,0,1,0,1,99]
输出: 99

代码:


  
  1. class Solution {
  2. public:
  3. long long yiHuoAtBase3(long long a, long long b)
  4. {
  5. for (long long k = 1; k <= b; k *= 3){
  6. a -= (a / k % 3 - (a / k + b / k) % 3)*k;
  7. }
  8. return a;
  9. }
  10. int singleNumber(vector<int>& nums) {
  11. long long ans1 = 0, ans2 = 0;
  12. for (auto it = nums.begin(); it != nums.end(); it++){
  13. long long tem = *it;
  14. if (tem >= 0){
  15. ans1 = yiHuoAtBase3(ans1, tem);
  16. }
  17. else{
  18. ans2 = yiHuoAtBase3(ans2, -tem);
  19. }
  20. }
  21. return ans1-ans2;
  22. }
  23. };

力扣 260. 只出现一次的数字 III(基于计算的搜索)

题目:

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

示例 :

输入: [1,2,1,3,2,5]
输出: [3,5]
注意:

结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

 

代码:


  
  1. class Solution {
  2. public:
  3. vector<int> singleNumber(vector<int>& nums) {
  4. int k, s, s1, s2;
  5. s = 0;
  6. for (int i = 0; i < nums.size(); i++)s ^= nums[i];
  7. s = s & -s;
  8. s1 = 0, s2 = 0;
  9. for (int i = 0; i < nums.size(); i++)
  10. {
  11. if (s&nums[i])s1 ^= nums[i];
  12. else s2 ^= nums[i];
  13. }
  14. vector<int>ans;
  15. ans.insert(ans.end(), s1);
  16. ans.insert(ans.end(), s2);
  17. return ans;
  18. }
  19. };

力扣 268. 缺失数字(基于计算的搜索)

题目:

给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

示例 1:

输入: [3,0,1]
输出: 2
示例 2:

输入: [9,6,4,2,3,5,7,0,1]
输出: 8
说明:
你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?

 

代码:


   
  1. class Solution {
  2. public:
  3. int missingNumber(vector<int>& nums) {
  4. int n = nums.size();
  5. int ans = 0;
  6. for (int i = 1; i <= n; i++)ans ^= (i^nums[i - 1]);
  7. return ans;
  8. }
  9. };

 

 

 

文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nameofcsdn/article/details/116016266

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。