LeetCode : Intersection of Two Arrays II 两个向量去重问题 求交集,并集,差集

std :: set_intersection:两个排序范围的交叉点(交集)

 

构造一个从result指向的位置开始的排序范围,其中包含两个已排序范围 [ first1,last1 ) 和 [ first2,last2)的集合交集。

两组的交集仅由两组中存在的元素形成。 函数复制的元素始终来自第一个范围,顺序相同。

使用operator <作为第一个版本比较元素,comp作为第二个版本。 如果(!(a <b)&&!(b <a))或 如果(!comp(a,b)&&!comp(b,a)),则认为两个元素a和b是等价的。

范围中的元素应根据相同的标准(操作符<或comp)进行排序。 结果范围也根据此进行排序。

格式:

default (1)
template <class InputIterator1, class InputIterator2, class OutputIterator>
  OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1,
                                   InputIterator2 first2, InputIterator2 last2,
                                   OutputIterator result);
custom (2)
template <class InputIterator1, class InputIterator2,
          class OutputIterator, class Compare>
  OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1,
                                   InputIterator2 first2, InputIterator2 last2,
                                   OutputIterator result, Compare comp);

相当于:

template <class InputIterator1, class InputIterator2, class OutputIterator>
  OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1,
                                   InputIterator2 first2, InputIterator2 last2,
                                   OutputIterator result)
{
  while (first1!=last1 && first2!=last2)
  {
    if (*first1<*first2) ++first1;
    else if (*first2<*first1) ++first2;
    else {
      *result = *first1;
      ++result; ++first1; ++first2;
    }
  }
  return result;
}

 

一定谨记:两个区间必须是有序区间(从小到大),所以在intersection前务必对取交集的对象a和b进行sort

 

结果

将迭代器输出到存储结果序列的范围的初始位置。
指向的类型应支持从第一个范围分配元素的值。

补偿(comp)

二进制函数,接受输入迭代器指向的类型的两个参数,并返回一个可转换为bool的值。返回的值表示第一个参数是否被认为是在它定义的特定严格弱顺序中的第二个参数之前。
该函数不得修改其任何参数。
这可以是函数指针或函数对象。

范围不得重叠。

事例:

#include <iostream>     // std::cout
#include <algorithm>    // std::set_intersection, std::sort
#include <vector>       // std::vector

int main() {
	int first[] = { 5,10,15,20,25 };
	int second[] = { 50,40,30,20,10 };
	std::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0
	std::vector<int>::iterator it;

	std::sort(first, first + 5);     //  5 10 15 20 25
	std::sort(second, second + 5);   // 10 20 30 40 50

	it = std::set_intersection(first, first + 5, second, second + 5, v.begin());
	// 10 20 0  0  0  0  0  0  0  0
	v.resize(it - v.begin());                      // 10 20

	std::cout << "The intersection has " << (v.size()) << " elements:\n";
	for (it = v.begin(); it != v.end(); ++it)
		std::cout << ' ' << *it;
	std::cout << '\n';

	return 0;
}

 

set_intersection()返回一个迭代器,指向并集的下一个元素的地址。

 

 

让我们看下原题:

给定两个数组,编写一个函数来计算它们的交集。

Example 1:

Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2,2]

Example 2:

Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [4,9]

注意:

结果中的每个元素应该出现在两个数组中显示的次数。
结果可以是任何顺序。

优化:

如果给定的数组已经排序怎么办? 你会如何优化你的算法?
如果nums1的尺寸与nums2的尺寸相比较小怎么办? 哪种算法更好?
如果nums2的元素存储在磁盘上,并且内存有限,以致您无法一次将所有元素加载到内存中,该怎么办?

 

代码分析:

#include <iostream>
#include <vector>
#include <unordered_map>
//#include <allocators>
#include <algorithm>
#include <iterator>
using namespace std;

//最常规的方法:先排序,然后循环比较
//class Solution {
//public:
//	vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
//		sort(nums1.begin(), nums1.end());
//		sort(nums2.begin(), nums2.end());
//		int n1 = (int)nums1.size(), n2 = (int)nums2.size();
//		int i1 = 0, i2 = 0;
//		vector<int> res;
//		while (i1 < n1 && i2 < n2) {
//			if (nums1[i1] == nums2[i2]) {
//				res.push_back(nums1[i1]);
//				i1++;
//				i2++;
//			}
//			else if (nums1[i1] > nums2[i2]) {
//				i2++;
//			}
//			else {
//				i1++;
//			}
//		}
//		return res;
//	}
//};

//自己的尝试:想要利用一个中间数组,判断有多少相同的数(数组对应下标元素),例如i=2,a[2]++,则可以知道有几个元素等于2。
//失败了,因为同一个向量里面也有相同元素。o(╥﹏╥)o
//class Solution {
//public:
//	vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
//		int arr_[1000];
//		for (int i = 0; i < nums1.size(); i++)
//			arr_[i] = 0;
//		for (int i = 0; i < nums1.size(); i++)
//		{
//			arr_[nums1[i]]++;
//		}
//		for (int i = 0; i < nums2.size(); i++)
//		{
//			arr_[nums2[i]]++;
//		}
//		int num_arr = 0;
//		for (int i = 0; i < nums1.size(); i++)
//		{
//			if (arr_[i] == 2)
//				num_arr++;
//		}
//
//		vector<int> arr_copy;
//		for (int i = 0; i < (nums1.size() > nums2.size() ? nums1.size() : nums2.size()); i++)
//		{
//			if (arr_[i] == 2)
//				arr_copy.push_back(i);
//		}
//
//		return arr_copy;
//
//	}
//};


//利用set_intersection()函数求排序范围交叉点,然后去重
class Solution {
public:
	vector<int> intersect(vector<int>& a, vector<int>& b) {
		sort(a.begin(), a.end());
		sort(b.begin(), b.end());
		std::vector<int>::iterator it = set_intersection( a.begin(), a.end(), b.begin(), b.end(), a.begin() );
		int num = it - a.begin();                  //num=2
		a.resize(num);
		//a.resize(it - a.begin()); 
		//a.erase(set_intersection(a.begin(), a.end(), b.begin(), b.end(), a.begin()), a.end());
		return a;
	}
};

//利用无序映射,键值通常用于唯一标识元素
//class Solution {
//public:
//	vector<int> intersect(vector<int>& a, vector<int>& b) {
//		unordered_map<int, int> ctr;
//		vector<int> out;
//		for (int i : a)
//			ctr[i]++;
//		for (int i : b)
//			if (ctr[i]-- > 0)
//				out.push_back(i);
//		return out;
//	}
//};

//class Solution {
//public:
//	vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
//		unordered_map<int, int> dict;
//		vector<int> res;
//		for (int i = 0; i < (int)nums1.size(); i++) dict[nums1[i]]++;
//		for (int i = 0; i < (int)nums2.size(); i++)
//			if (--dict[nums2[i]] >= 0) res.push_back(nums2[i]);
//		return res;
//	}
//};



int main()
{
	vector<int> nums1{ 4,9,5};
	vector<int> nums2{ 9,4,9,8,4};
	Solution sol;
	
	
	for (auto i : sol.intersect(nums1, nums2))
		cout << i << " ";
	cout << endl;

	return 0;
}

能进行算术运算的迭代器只有随即访问迭代器,要求容器元素存储在连续内存空间里,vector,string,deque的迭代器是有加减法的,但是map,set,multimap,multiset的迭代器是没有加减法的,list也不可以 。
该知识点是在刷leetcode347题时想到的。

里面值得注意的点:

1.巧妙运用自减运算符

#include <iostream>
using namespace std;
int main()
{
	int a = 2 ;
	if(a--==2)
		cout << a <<endl;
	return 0;
}

输出:1

我的写法好像也可以这样改进。。。我用的数组,他用的映射。

 

 

 

迭代器的算术操作

1.ter+n    iter-n

可以对迭代器对象加上或减去一个整型值.这样做将产生一个新的迭代器,其位置在iter所指元素之前(加法)或之后(减法)n个元素的位置.加或减之后的结果必须指向iter所指vector中的某个元素,或者是vector末端的后一个元素.加上或减去的值的类型应该是vector的size_type或difference_type类型

2.iter1-iter2

该表达式用来计算两个迭代器对象的距离,该距离是名为difference_type的signed类型的值,这里的difference_type类型类似于size_type类型,也是由vector定义的.difference_type是signed类型,因为减法运算可能产生负数的结果.该类型可以保证足够大以存储任何两个迭代器对象间的距离.iter1与iter2两者必须都指向同一vector中的元素,或者指向vector末端之后的下一个元素.

可以用迭代器算术操作来移动迭代器直接指向某个元素,例如,下面语句直接定义于vector的中间元素:

vector<int>::iterator mid= vi.begin() + vi.size()/2;

迭代器加上一个整型值就是产生一个新的迭代器,指向其后的n个位置,假设vi.size()返回十个元素,那么上面得到的就是第六个元素.

上述代码用来初始化mid,使其指向vi中最靠近正中间的元素.这种直接计算迭代器的方法,与用迭代器逐个元素自增操作到达中间元素的方法是等价的,但前者效率要高很多.

注意:任何改变vector长度的操作都会使已存在的迭代器失效.例如,在调用push_back之后,就不能再信赖指向vector的迭代器的值了.

如果采用下面的方法来计算mid会产生什么结果?

vector<int>::iterator mid=( vi.begin()+vi.end() )/2;

将两个迭代器相加,没有这种运算,上面说了,迭代器的算术操作仅有将两个迭代器相减,算出两个迭代器之间的距离.上面的程序会导致编译错误
 

 

更多函数:  std::set_difference() 求两个排序范围的差异

                    std::set_union() 求两个排序范围的并集

                    std::merge() 合并排序范围              

                    std::set_symmetric_difference() 求两个排序范围的对等差分 ( or )

给出两个集合 (如集合 A = {1, 2, 3} 和集合 B = {2, 3, 4})

而数学术语 "对等差分" 的集合就是指由所有只在两个集合其中之一的元素组成的集合(A △ B = C = {1, 4}).

对于传入的额外集合 (如 D = {2, 3}), 你应该安装前面原则求前两个集合的结果与新集合的对等差分集合 (C △ D = {1, 4} △ {2, 3} = {1, 2, 3, 4}).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值