数组和集合的搜索
目录
一,数组和集合的搜索
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]
思路:枚举一个数,嵌套搜索另外一个数的时候采用二分法
  
   - 
    
     
    
    
     
      //给vector拓展,加上id并排序
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      bool cmp(T x,T y)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         return x<y;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<pair<T,int>> sortWithId(vector<T>v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<pair<T,int>>ans;
     
    
- 
    
     
    
    
     
          ans.resize(v.size());
     
    
- 
    
     
    
    
         for(int i=0;i<v.size();i++)ans[i].first=v[i],ans[i].second=i;
     
    
- 
    
     
    
    
         sort(ans.begin(),ans.end(),[](pair<T,int>p1,pair<T,int>p2){return cmp(p1.first,p2.first);});
     
    
- 
    
     
    
    
         return ans;      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<vector<int>> findSum(vector<T>v1,vector<T>v2,T s)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<vector<int>>ans;
     
    
- 
    
     
    
    
     
          vector<int>tmp(2);
     
    
- 
    
     
    
    
     
          vector<pair<T,int>>v3=sortWithId(v2);
     
    
- 
    
     
    
    
         sort(v2.begin(), v2.end(),cmp<T>);
     
    
- 
    
     
    
    
         for(int i=0;i<v1.size();i++)
     
    
- 
    
     
    
    
     
          {
     
    
- 
    
     
    
    
             auto it1=lower_bound(v2.begin(), v2.end(), s-v1[i]);
     
    
- 
    
     
    
    
             auto it2=upper_bound(v2.begin(), v2.end(), s-v1[i]);
     
    
- 
    
     
    
    
     
              tmp[0]=i;
     
    
- 
    
     
    
    
             for(auto j=it1;j<it2;j++)
     
    
- 
    
     
    
    
     
              {
     
    
- 
    
     
    
    
     
                  tmp[1]=v3[j-v2.begin()].second;
     
    
- 
    
     
    
    
     
                  ans.push_back(tmp);
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //删除二维vector中,含有重复元素的行
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<vector<T>> deleteSame(vector<vector<T>>&v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<vector<int>>ans;
     
    
- 
    
     
    
    
     
          ans.reserve(v.size());
     
    
- 
    
     
    
    
         for(int i=0;i<v.size();i++)
     
    
- 
    
     
    
    
     
          {
     
    
- 
    
     
    
    
             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;
     
    
- 
    
     
    
    
     
              ans.push_back(v[i]);
     
    
- 
    
     
    
    
     
      here:;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Solution {
     
    
- 
    
     
    
    
     
      public:
     
    
- 
    
     
    
    
         vector<int> twoSum(vector<int>& nums, int target) {
     
    
- 
    
     
    
    
     
              vector<vector<int>>ans=findSum(nums,nums,target);
     
    
- 
    
     
    
    
             return deleteSame(ans)[0];
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      };
     
    
 力扣 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. 两数之和 基本没啥差别。
  
   - 
    
     
    
    
     
      //vector加一个数
     
    
- 
    
     
    
    
     
      template<typename T1,typename T2>
     
    
- 
    
     
    
    
     
      void fjia(vector<T1> &v,T2 n)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         for(int i=v.size()-1;i>=0;i--)v[i]+=n;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Solution {
     
    
- 
    
     
    
    
     
      public:
     
    
- 
    
     
    
    
         vector<int> twoSum(vector<int>& nums, int target) {
     
    
- 
    
     
    
    
     
              vector<vector<int>>ans=findSum(nums,nums,target);
     
    
- 
    
     
    
    
     
              vector<int>res = deleteSame(ans)[0];
     
    
- 
    
     
    
    
             fjia(res,1);
     
    
- 
    
     
    
    
             return res;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      };
     
    
 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
  
   - 
    
     
    
    
     
      //给vector拓展,加上id并排序
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      bool cmp(T x,T y)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         return x<y;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<pair<T,int>> sortWithId(vector<T>v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<pair<T,int>>ans;
     
    
- 
    
     
    
    
     
          ans.resize(v.size());
     
    
- 
    
     
    
    
         for(int i=0;i<v.size();i++)ans[i].first=v[i],ans[i].second=i;
     
    
- 
    
     
    
    
         sort(ans.begin(),ans.end(),[](pair<T,int>p1,pair<T,int>p2){return cmp(p1.first,p2.first);});
     
    
- 
    
     
    
    
         return ans;      
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<vector<int>> findSum(vector<T>v1,vector<T>v2,T s)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<vector<int>>ans;
     
    
- 
    
     
    
    
         int m=min((long long)(v1.size()*v2.size()),(long long)12345678);
     
    
- 
    
     
    
    
     
          ans.reserve(m);
     
    
- 
    
     
    
    
     
          vector<int>tmp(2);
     
    
- 
    
     
    
    
     
          vector<pair<T,int>>v3=sortWithId(v2);
     
    
- 
    
     
    
    
         sort(v2.begin(), v2.end(),cmp<T>);
     
    
- 
    
     
    
    
         for(int i=0;i<v1.size();i++)
     
    
- 
    
     
    
    
     
          {
     
    
- 
    
     
    
    
             auto it1=lower_bound(v2.begin(), v2.end(), s-v1[i]);
     
    
- 
    
     
    
    
             auto it2=upper_bound(v2.begin(), v2.end(), s-v1[i]);
     
    
- 
    
     
    
    
     
              tmp[0]=i;
     
    
- 
    
     
    
    
             for(auto j=it1;j<it2;j++)
     
    
- 
    
     
    
    
     
              {
     
    
- 
    
     
    
    
     
                  tmp[1]=v3[j-v2.begin()].second;
     
    
- 
    
     
    
    
     
                  ans.push_back(tmp);
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //枚举2个vector的两数之和
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<T> everySum(vector<T>&v1,vector<T>&v2)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<T>ans;
     
    
- 
    
     
    
    
     
          ans.resize(v1.size()*v2.size());
     
    
- 
    
     
    
    
         int k=0;
     
    
- 
    
     
    
    
         for(int i=0;i<v1.size();i++)for(int j=0;j<v2.size();j++)ans[k++]=v1[i]+v2[j];
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //判断有序数组中有多少个不同的数
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      int getDifNum(vector<T>v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         int ans=1;
     
    
- 
    
     
    
    
         for(int i=1;i<v.size();i++)ans+=(v[i]!=v[i-1]);
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //收缩计数,把[1 1 4 4 4]变成[(1,2)(4,3)]
     
    
- 
    
     
    
    
     
      template<typename T>
     
    
- 
    
     
    
    
     
      vector<pair<T,int>> fshr(vector<T>v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<pair<T,int>>ans;
     
    
- 
    
     
    
    
         if(v.size()==0)return ans;
     
    
- 
    
     
    
    
         sort(v.begin(),v.end());
     
    
- 
    
     
    
    
     
          ans.resize(getDifNum(v));
     
    
- 
    
     
    
    
     
          ans[0]=make_pair(v[0],1);
     
    
- 
    
     
    
    
         for(int i=1,j=0;i<v.size();i++)
     
    
- 
    
     
    
    
     
          {
     
    
- 
    
     
    
    
             if(v[i]==v[i-1])ans[j].second++;
     
    
- 
    
     
    
    
             else ans[++j]=make_pair(v[i],1);
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //提取pair数组的first
     
    
- 
    
     
    
    
     
      template<typename T1,typename T2>
     
    
- 
    
     
    
    
     
      vector<T1> fdraw(vector<pair<T1,T2>>v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<T1>ans(v.size());
     
    
- 
    
     
    
    
         for(int i=0;i<v.size();i++)ans[i]=v[i].first;
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      //提取pair数组的second
     
    
- 
    
     
    
    
     
      template<typename T1,typename T2>
     
    
- 
    
     
    
    
     
      vector<T2> fdraw2(vector<pair<T1,T2>>v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
          vector<T2>ans(v.size());
     
    
- 
    
     
    
    
         for(int i=0;i<v.size();i++)ans[i]=v[i].second;
     
    
- 
    
     
    
    
         return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      class Solution {
     
    
- 
    
     
    
    
     
      public:
     
    
- 
    
     
    
    
         int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
     
    
- 
    
     
    
    
     
              vector<int> v1 = everySum(A,B),v2 = everySum(C,D);
     
    
- 
    
     
    
    
     
              vector<pair<int,int>>v3=fshr(v1),v4=fshr(v2);
     
    
- 
    
     
    
    
     
              vector<int> v5=fdraw(v3),v6=fdraw(v4);
     
    
- 
    
     
    
    
     
              vector<int> v7=fdraw2(v3),v8=fdraw2(v4);
     
    
- 
    
     
    
    
     
              vector<vector<int>> ans = findSum(v5,v6,0);
     
    
- 
    
     
    
    
             int res=0;
     
    
- 
    
     
    
    
             for(int i=0;i<ans.size();i++)res+=v7[ans[i][0]]*v8[ans[i][1]];
     
    
- 
    
     
    
    
             return res;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      };
     
    
 力扣 136. 只出现一次的数字(基于计算的搜索)
题目:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
 输出: 1
 示例 2:
输入: [4,1,2,1,2]
 输出: 4
代码:
  
   - 
    
     
    
    
     
      class Solution {
     
    
- 
    
     
    
    
     
      public:
     
    
- 
    
     
    
    
     	int singleNumber(vector<int>& nums) {
     
    
- 
    
     
    
    
     		int ans = 0;
     
    
- 
    
     
    
    
     		for (auto it = nums.begin(); it != nums.end(); it++)ans ^= *it;
     
    
- 
    
     
    
    
     		return ans;
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     
      };
     
    
 
力扣 137. 只出现一次的数字 II(基于计算的搜索)
题目:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
 输出: 3
 示例 2:
输入: [0,1,0,1,0,1,99]
 输出: 99
代码:
  
   - 
    
     
    
    
     
      class Solution {
     
    
- 
    
     
    
    
     
      public:
     
    
- 
    
     
    
    
     	long long yiHuoAtBase3(long long a, long long b)
     
    
- 
    
     
    
    
     
      	{
     
    
- 
    
     
    
    
     		for (long long k = 1; k <= b; k *= 3){
     
    
- 
    
     
    
    
     
      			a -= (a / k % 3 - (a / k + b / k) % 3)*k;
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		return a;
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     	int singleNumber(vector<int>& nums) {
     
    
- 
    
     
    
    
     		long long ans1 = 0, ans2 = 0;
     
    
- 
    
     
    
    
     		for (auto it = nums.begin(); it != nums.end(); it++){
     
    
- 
    
     
    
    
     			long long tem = *it;
     
    
- 
    
     
    
    
     			if (tem >= 0){
     
    
- 
    
     
    
    
     
      				ans1 = yiHuoAtBase3(ans1, tem);
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     			else{
     
    
- 
    
     
    
    
     
      				ans2 = yiHuoAtBase3(ans2, -tem);
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		return ans1-ans2;
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     
      };
     
    
 力扣 260. 只出现一次的数字 III(基于计算的搜索)
题目:
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
示例 :
输入: [1,2,1,3,2,5]
 输出: [3,5]
 注意:
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
 你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
代码:
  
   - 
    
     
    
    
     
      class Solution {
     
    
- 
    
     
    
    
     
      public:
     
    
- 
    
     
    
    
     	vector<int> singleNumber(vector<int>& nums) {
     
    
- 
    
     
    
    
     		int k, s, s1, s2;
     
    
- 
    
     
    
    
     
      		s = 0;
     
    
- 
    
     
    
    
     		for (int i = 0; i < nums.size(); i++)s ^= nums[i];
     
    
- 
    
     
    
    
     
      		s = s & -s;
     
    
- 
    
     
    
    
     
      		s1 = 0, s2 = 0;
     
    
- 
    
     
    
    
     		for (int i = 0; i < nums.size(); i++)
     
    
- 
    
     
    
    
     
      		{
     
    
- 
    
     
    
    
     			if (s&nums[i])s1 ^= nums[i];
     
    
- 
    
     
    
    
     			else s2 ^= nums[i];
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     
      		vector<int>ans;
     
    
- 
    
     
    
    
     
      		ans.insert(ans.end(), s1);
     
    
- 
    
     
    
    
     
      		ans.insert(ans.end(), s2);
     
    
- 
    
     
    
    
     		return ans;
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     
      };
     
    
 力扣 268. 缺失数字(基于计算的搜索)
题目:
给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1]
 输出: 2
 示例 2:
输入: [9,6,4,2,3,5,7,0,1]
 输出: 8
 说明:
 你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?
代码:
   
    - 
     
      
     
     
      
       class Solution {
      
     
- 
     
      
     
     
      
       public:
      
     
- 
     
      
     
     
      	int missingNumber(vector<int>& nums) {
      
     
- 
     
      
     
     
      		int n = nums.size();
      
     
- 
     
      
     
     
      		int ans = 0;
      
     
- 
     
      
     
     
      		for (int i = 1; i <= n; i++)ans ^= (i^nums[i - 1]);
      
     
- 
     
      
     
     
      		return ans;
      
     
- 
     
      
     
     
      
       	}
      
     
- 
     
      
     
     
      
       };
      
     
  
文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/nameofcsdn/article/details/116016266
- 点赞
- 收藏
- 关注作者
 
             
           
评论(0)