set和map的使用

1. set的使用

set是Key模型的二叉搜索树,它不仅能排序还能去重,底层实际上是用红黑树实现的。

注意:set的普通迭代器和const迭代器都不支持对Key的修改。

因为源码用的都是const_iterator。

1.1 插入

void test_set1()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);


	// 排序 + 去重 
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10;
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

image-20220730181742140

1.2 查找

erase得配合find使用。find如果没找到会返回end。set.find是按照二叉搜索树的性质来查找,时间复杂度是O(1)。而算法库里的find是暴力查找,时间复杂度是O(n)。

void test_set2()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	set<int>::iterator pos = s.find(20);  // O(logN)
	if (pos != s.end())
	{
		cout << "set.find找到了" << endl;
	}

	pos = find(s.begin(), s.end(), 2); // O(N)
	if (pos != s.end())
	{
		cout << "find找到了" << endl;
	}
}

image-20220730183037852

1.3 删除

eras是从集合容器中移除单个元素或一组元素[first,last)。

如果没有找到pos就删除会出问题。所以删除时要加条件判断。而如果是直接用一个值去删除比如s.erase(3),编译器会自己去调用find,如果在就删除(返回删除的个数),不在就不会做任何事情(删除失败返回0)。

void test_set3()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	cout << s.erase(3) << endl;
	cout << s.erase(30) << endl;

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>::iterator pos = s.find(3);
	if (pos != s.end())
		s.erase(pos);

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	/*int x;
	while (cin >> x)
	{
		set<int>::iterator pos = s.find(x);
		if (pos != s.end())
		{
			s.erase(pos);
			cout << "删除" << x << "成功" << endl;
		}
		else
		{
			cout << x << "不在set中" << endl;
		}

		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}*/

    // count在容器中搜索与val相等的元素,并返回匹配的数量。 
    // count是为了支持multiset版本的set
    // 对于普通set而言,因为集合容器中的所有元素都是唯一的,所以函数只能返回1(如果找到了元素)或0(否则)。
	if (s.count(5))
	{
		cout << "5在" << endl;
	}

	if (s.find(5) != s.end())
	{
		cout << "5在" << endl;
	}
}

image-20220730184336678

1.4 lower_bound

void test_set4()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(9);

	// 返回>= val得位置迭代器  3返回3位置  6 返回7位置
	/*set<int>::iterator lowIt = s.lower_bound(3); 存在
	lowIt = s.lower_bound(6); 不存在*/
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	// 要求删除>=x的所有值
	int x;
	cin >> x;
	set<int>::iterator lowIt = s.lower_bound(x);
	s.erase(lowIt, s.end());

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

image-20220730185234632

1.5 upper_bound

因为erase从集合容器中移除单个元素或一组元素([first,last)])。

void test_set5()
{
	set<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(9);

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	// 返回>x位置的迭代器  -》 都是返回 7位置的迭代器
	//set<int>::iterator upIt = s.upper_bound(5);  // 存在
	//upIt = s.upper_bound(6); // 不存在

	// 删除x <=  <= y的区间 删除 [x,y]
    // 因为erase的区间是[first,last)
    int x, y;
	cin >> x >> y;
	auto leftIt = s.lower_bound(x);  // [
	auto rightIt = s.upper_bound(y); // )
    // 输入3 7区间为[3,9)包含[3,7]
	s.erase(leftIt, rightIt);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

image-20220730191122507

1.6 multiset

multiset用法和set一样,唯一不同是允许键值冗余。排序不去重。

这里count的作用就体现出来了。

void test_set6()
{
	multiset<int> s;
	s.insert(4);
	s.insert(5);
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);
	s.insert(3);
	s.insert(3);
	s.insert(3);
	s.insert(3);

	// 排序 
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10;
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << s.count(1) << endl;
	cout << s.erase(1) << endl;
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	// 多个x的话,find返回中序第一个x
	auto pos = s.find(3);
	while (pos != s.end())
	{
		cout << *pos << " ";
		++pos;
	}
	cout << endl;
}

image-20220730194725519

2. 两个数组的交集

349. 两个数组的交集

image-20220730200352456

image-20220730200326185

3. map的使用

map是KV模型的二叉搜索树。

3.1 插入及其遍历

插入的是一个键值对,返回的也是一个键值对,iterator就是指向value_type的指针。

image-20220730201939998

void test_map1()
{
	map<string, string> dict;

	// pair构造函数
	dict.insert(pair<string, string>("sort", "排序"));
	pair<string, string> kv("insert", "插入");
	dict.insert(kv);

	// make_pair函数模板自动推导类型
	dict.insert(make_pair("left","左边"));

	// C++11 再讲
	//dict.insert({ "right", "右边" });

	// 遍历
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << " "; // it->operator*()
		//cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

	for (const auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

image-20220730202818540

3.2 统计水果出现次数

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

	/*map<string, int> countMap;
	for (auto& str : arr)
	{
		map<string, int>::iterator it = countMap.find(str);
		if (it != countMap.end())
		{
			it->second++;
		}
		else
		{
			countMap.insert(make_pair(str, 1));
		}
	}*/

	//map<string, int> countMap;
	//for (auto& str : arr)
	//{
	//	//pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str, 1));
	//	auto ret = countMap.insert(make_pair(str, 1));
	//	if (ret.second == false)
	//	{
	//		ret.first->second++;
	//	}
	//}

	map<string, int> countMap;
	for (auto& str : arr)
	{
		countMap[str]++;
	}

	for (const auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

insert单元素版本(1)返回一个元素对pair,pair::first被设置为一个迭代器,指向新插入的元素或映射中具有相同键值的元素。 如果插入了新元素,则pair::second设置为true;如果已经存在等价的键,则设置为false。

image-20220730204112634

3.3 operator[]

image-20220730205801212

image-20220730210502869

multimap不支持operator[],因为一个key对应多个value。

3. 前k个高频单词

692. 前K个高频单词

image-20220801091018560

class Solution {
public:
    typedef map<string,int>::iterator CountIter;
    struct IterCompare
    {
        bool operator()(CountIter it1, CountIter it2)
        {
            return it1->second > it2->second;
        }
    };
    
    vector<string> topKFrequent(vector<string>& words, int k) {
        //按key排好序且统计对应的出现次数
		map<string,int> countMap;
        for(auto& str : words)
        {
            countMap[str]++;
        }
        
        //将map数据节点的迭代器放入vector
        vector<CountIter> v;
        CountIter it = countMap.begin();
        while(it != countMap.end())
        {
            v.push_back(it);
            ++it;
        }
        //因为stable_sort只支持随机迭代器且是稳定的排序
        //按出现次数排序,如果次数相同按照字典序排序
        stable_sort(v.begin(), v.end(), IterCompare());
        
        //录入排序好的结果--单词
        vector<string> ret;
        for(size_t i = 0; i < k; ++i)
        {
            ret.push_back(v[i]->first);
        }
        
        return ret;
    }
};

第二种方法:

class Solution {
public:    
    vector<string> topKFrequent(vector<string>& words, int k) {
        //按key排好序且统计对应的出现次数
		map<string,int> countMap;
        for(auto& str : words)
        {
            countMap[str]++;
        }
        
        //再用multimap按出现次数排序,排降序
        //multimap遇到相等的值会插入到右边
        multimap<int,string,great<int>> sortMap;
        for(auto& kv : countMap)
        {
            sortMap.insert(make_pair(kv.second, kv.first));
        }
        
        //录入排序好的结果--单词
        vector<string> ret;
        auto it = sortMap.begin();
        for(size_t i = 0; i < k; ++i)
        {
            ret.push_back(it->second);
            ++it;
        }
        
        return ret;
    }
};


    //再用multimap按出现次数排序,排降序
        //multimap遇到相等的值会插入到右边
        multimap<int,string,great<int>> sortMap;
        for(auto& kv : countMap)
        {
            sortMap.insert(make_pair(kv.second, kv.first));
        }
        
        //录入排序好的结果--单词
        vector<string> ret;
        auto it = sortMap.begin();
        for(size_t i = 0; i < k; ++i)
        {
            ret.push_back(it->second);
            ++it;
        }
        
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuucho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值