嗨,我是云邊有個稻草人,與你分享C++領域專業知識(*^▽^*)
《C++》本篇文章所屬專欄—持續更新中—歡迎訂閱—
?
目錄
一、序列式容器和關聯式容器
二、set系列的使用
2.1?set和multiset參考?檔
2.2 set類的介紹
2.3 set的構造和迭代器
2.4 set的增刪查
2.5 insert和迭代器遍歷使用樣例
2.6 find和erase使用樣例
【erase+find+count】?
【lower_bound+upper_bound】?
2.7 multiset和set的差異
2.8?349. 兩個數組的交集 - 力扣(LeetCode)
2.9?142. 環形鏈表 II - 力扣(LeetCode)
三、map系列的使用
3.1 map和multimap參考文檔
3.2 map類的介紹
3.3 pair類型介紹
3.4 map的構造
3.5 map的增刪查
3.6?構造遍歷及增刪查使?樣例
3.7?map的數據修改+map的迭代器和[ ]功能樣例
【應用1】?
【應用2】
3.8?multimap和map的差異
3.9?138. 隨機鏈表的復制 - 力扣(LeetCode)
3.10?692. 前K個高頻單詞 - 力扣(LeetCode)
正文開始——
一、序列式容器和關聯式容器
前?我們已經接觸過STL中的部分容器如:string、vector、list、deque、array、forward_list等,這些容器統稱為序列式容器,因為邏輯結構為線性序列的數據結構,兩個位置存儲的值之間?般沒有緊密的關聯關系,比如交換?下,其依舊是序列式容器。順序容器中的元素是按他們在容器中的存儲位置來順序保存和訪問的。
關聯式容器也是用來存儲數據的,與序列式容器不同的是,關聯式容器邏輯結構通常是?線性結構, 兩個位置有緊密的關聯關系,交換?下,其存儲結構就被破壞了。序列容器中的元素是按關鍵字來保存和訪問的。關聯式容器有map/set系列和unordered_map/unordered_set系列。 本章節講解的map和set底層是紅?樹,紅?樹是?棵平衡?叉搜索樹。
set是key搜索場景的結構, map是key/value搜索場景的結構。
二、set系列的使用
2.1?set和multiset參考?檔
<set> - C++ Reference
2.2 set類的介紹
set的聲明如下,T就是set底層關鍵字的類型,也就是我們上面說的key
- set默認要求T支持小于比較,如果不支持或者想按自己的需求走可以自行實現仿函數傳給第二個模版參數
- set底層存儲數據的內存是從空間配置器申請的,如果需要可以自己實現內存池,傳給第三個參數。
- ?般情況下,我們都不需要傳后兩個模版參數。
- set底層是用紅黑樹實現,增刪查效率是 ,迭代器遍歷是走的搜索樹的中序,所以是有序的。 O(logN)
- 前?部分我們已經學習了vector/list等容器的使用,STL容器接口設計,高度相似,所以這?我們就不再?個接??個接?的介紹,?是直接帶著?家看?檔,挑?較重要的接?進行介紹。
2.3 set的構造和迭代器
set的構造我們關注以下幾個接口即可。
set?持正向和反向迭代遍歷,遍歷默認按升序順序,因為底層是?叉搜索樹,迭代器遍歷走的中序;支持迭代器就意味著?持范圍for,set的iterator和const_iterator都不?持迭代器修改數據,修改關鍵字數據破壞了底層搜索樹的結構。
// empty (1) ?參默認構造
explicit set (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());// range (2) 迭代器區間構造
template <class InputIterator>
set (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());// copy (3) 拷?構造
set (const set& x);// initializer list (5) initializer 列表構造
set (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());// 迭代器是?個雙向迭代器
iterator -> a bidirectional iterator to const value_type// 正向迭代器
iterator begin();
iterator end();// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();
2.4 set的增刪查
set的增刪查關注以下?個接?即可:
Member types
key_type -> The first template parameter (T)
value_type -> The first template parameter (T)// 單個數據插?,如果已經存在則插?失敗
pair<iterator,bool> insert (const value_type& val);// 列表插?,已經在容器中存在的值不會插?
void insert (initializer_list<value_type> il);// 迭代器區間插?,已經在容器中存在的值不會插?
template <class InputIterator>
void insert (InputIterator first, InputIterator last);// 查找val,返回val所在的迭代器,沒有找到返回end()
iterator find (const value_type& val);// 查找val,返回Val的個數
size_type count (const value_type& val) const;// 刪除?個迭代器位置的值
iterator erase (const_iterator position);// 刪除val,val不存在返回0,存在返回1
size_type erase (const value_type& val);// 刪除?段迭代器區間的值
iterator erase (const_iterator first, const_iterator last);// 返回?于等val位置的迭代器
iterator lower_bound (const value_type& val) const;// 返回?于val位置的迭代器
iterator upper_bound (const value_type& val) const;
2.5 insert和迭代器遍歷使用樣例
#include<set>
#include<iostream>using namespace std;int main()
{//去重+升序排序set<int> s1;//去重+排降序(傳一個大于的仿函數)set<int, greater<int>> s2;s2.insert(1);s2.insert(4);s2.insert(-2);s2.insert(100);//使用迭代器set<int>::iterator it = s2.begin();//auto it = s2.begin();while (it != s2.end()){cout << *it << " ";it++;}cout << endl;//使用范圍for打印for (auto e : s2){cout << e << " ";}cout << endl;//支持插入一段initializer_list列表值,已經存在的值插入失敗s2.insert({ 2, 3, 4, 5 });for (auto e : s2){cout << e << " ";}cout << endl;//set里面存如string類型的值set<string> strset = { "sort","animal","list","young" };//遍歷strset比較ASCII碼大小進行插入,注意這里并不是比較字符串的長度//注意下面e最好使用引用,set里面存的是string類型,多次的拷貝構造e會降低效率,不想改變就加上const即可for (const auto& e : strset){cout << e << " ";}cout << endl;return 0;
}
2.6 find和erase使用樣例
erase刪除成功就返回1,刪除失敗就返回0?
【erase+find+count】?
#include<iostream>
#include<set>using namespace std;int main()
{set<int> s = { 1,4,0,34,12,56 };for (auto e : s){cout << e << " ";}cout << endl;//1.利用迭代器進行刪除,刪除最小值s.erase(s.begin());for (auto e : s){cout << e << " ";}cout << endl;//2.直接輸入x,刪除xint x = 0;cin >> x;//erase的返回值幫助我們去判斷是否刪除成功int num = s.erase(x);if (num == 0){cout << x << "不存在!" << endl;}for (auto e : s){cout << e << " ";}cout << endl;//3.先查找再利用迭代器去刪除int y = 0;cin >> y;auto pos = s.find(y);if (pos != s.end())s.erase(pos);elsecout << "不存在!" << endl;for (auto e : s){cout << e << " ";}cout << endl;// 算法庫的查找 O(N),全部進行遍歷auto pos1 = find(s.begin(), s.end(), x);// set??實現的查找 O(logN),按照平衡二叉樹的特點進行尋找auto pos2 = s.find(x);// 利?count間接實現快速查找cin >> x;if (s.count(x)){cout << x << "在!" << endl;}else{cout << x << "不存在!" << endl;}return 0;
}
【lower_bound+upper_bound】?
#include<iostream>
#include<set>using namespace std;int main()
{set<int> s = { 10,20,35 ,40 ,50 ,65 ,70 ,80 ,90 };for (int i = 1; i < 10; i++){s.insert(i * 10);}for (auto e : s){cout << e << " ";}cout << endl;// 實現查找到[itlow,itup)包含[30, 60]區間],注意[itlow,itup)左閉右開// 返回 >= 30auto itlow = s.lower_bound(30);// 返回 > 60auto itup = s.upper_bound(60);//刪除這段區間的值s.erase(itlow, itup);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}
2.7 multiset和set的差異
multiset和set的使用基本完全類似,主要區別點在于multiset?持值冗余,那么 insert/find/count/erase都圍繞著支持值冗余有所差異,具體參看下?的樣例代碼理解。
#include<iostream>
#include<set> using namespace std;int main()
{//相比set不同的是,multiset是排序,但是不去重multiset<int> s = { 1,4,3,4,6,4,8,3,0 };for (auto e : s){cout << e << " ";}cout << endl;//multiset相比于set不同的是,里面可以存在多個x,find查找中序里面的第一個xint x = 0;cin >> x;//返回的是pos位置的迭代器,返回的是中序里面的第一個xauto pos = s.find(x);while (pos != s.end() && *pos == x){cout << *pos << " ";++pos;}cout << endl;// 相比set不同的是,count會返回x的實際個數cout << s.count(x) << endl;//相?set不同的是,erase給值時會刪除所有的xs.erase(x);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}
2.8?349. 兩個數組的交集 - 力扣(LeetCode)
class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {set<int> s1(nums1.begin(), nums1.end());set<int> s2(nums2.begin(), nums2.end());// 因為set遍歷是有序的,有序值,依次?較// ?的++,相等的就是交集vector<int> ret;auto it1 = s1.begin();auto it2 = s2.begin();while (it1 != s1.end() && it2 != s2.end()){if (*it1 < *it2){it1++;}else if (*it1 > *it2){it2++;}else{ret.push_back(*it1);it1++;it2++;}}return ret;}
};
2.9?142. 環形鏈表 II - 力扣(LeetCode)
數據結構初階階段,我們通過證明?個指針從頭開始??個指針從相遇點開始?,會在??點相遇, 理解證明都會很?煩。這?我們使?set查找記錄解決?常簡單?便,這?體現了set在解決?些問題時的價值,完全是降維打擊。
快速判斷一個值在不在,下面類似的算法很有用
class Solution {
public:ListNode* detectCycle(ListNode* head) {set<ListNode*> s;ListNode* cur = head;while (cur){//如果cur在s.count的返回值是1,則表明帶環,返回值是0是插入即可if(s.count(cur))return cur;//入環節點elses.insert(cur);cur=cur->next;}return nullptr;}
};
三、map系列的使用
3.1 map和multimap參考文檔
<map> - C++ Reference
3.2 map類的介紹
map的聲明如下,Key就是map底層關鍵字的類型,T是map底層value的類型,set默認要求Key?持?于?較,如果不?持或者需要的話可以自行實現仿函數傳給第?個模版參數,map底層存儲數據的 內存是從空間配置器申請的。?般情況下,我們都不需要傳后兩個模版參數。map底層是用紅黑樹實現,增刪查改效率是 O(logN) ,迭代器遍歷是走的中序,所以是按key有序順序遍歷的。
3.3 pair類型介紹
map底層的紅?樹節點中的數據,使?pair(類模版)存儲鍵值對數據。
typedef pair<const Key, T> value_type;
template <class T1, class T2>
struct pair
{typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair() : first(T1()), second(T2()){}pair(const T1& a, const T2& b) : first(a), second(b){}template<class U, class V>pair(const pair<U, V>& pr) : first(pr.first), second(pr.second){}
};
template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{return (pair<T1, T2>(x, y));
}
3.4 map的構造
map的構造我們關注以下?個接?即可。
map的?持正向和反向迭代遍歷,遍歷默認按key的升序順序,因為底層是?叉搜索樹,迭代器遍歷? 的中序;?持迭代器就意味著?持范圍for,map?持修改value數據,不?持修改key數據,修改關鍵 字數據,破壞了底層搜索樹的結構。
// empty (1) ?參默認構造
explicit map(const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());// range (2) 迭代器區間構造
template <class InputIterator>
map(InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type & = allocator_type());// copy (3) 拷?構造
map(const map& x);
// initializer list (5) initializer 列表構造
map(initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());// 迭代器是?個雙向迭代器
iterator->a bidirectional iterator to const value_type// 正向迭代器
iterator begin();
iterator end();// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();
3.5 map的增刪查
map的增刪查關注以下?個接?即可: map增接?,插?的pair鍵值對數據,跟set所有不同,但是查和刪的接?只?關鍵字key跟set是完全類似的,不過find返回iterator,不僅僅可以確認key在不在,還找到key映射的value,同時通過迭代還可以修改value
Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair<const key_type,mapped_type>// 單個數據插?,如果已經key存在則插?失敗,key存在相等value不相等也會插?失敗
pair<iterator,bool> insert (const value_type& val);// 列表插?,已經在容器中存在的值不會插?
void insert (initializer_list<value_type> il);// 迭代器區間插?,已經在容器中存在的值不會插?
template <class InputIterator>
void insert (InputIterator first, InputIterator last);// 查找k,返回k所在的迭代器,沒有找到返回end()
iterator find (const key_type& k);// 查找k,返回k的個數
size_type count (const key_type& k) const;// 刪除?個迭代器位置的值
iterator erase (const_iterator position);// 刪除k,k存在返回0,存在返回1
size_type erase (const key_type& k);// 刪除?段迭代器區間的值
iterator erase (const_iterator first, const_iterator last);// 返回?于等k位置的迭代器
iterator lower_bound (const key_type& k);// 返回?于k位置的迭代器
const_iterator lower_bound (const key_type& k) const;
3.6?構造遍歷及增刪查使?樣例
#include<iostream>
#include<map>
#include<string>using namespace std;int main()
{//轉換成多參數的直接構造kv1pair<string, string> kv1 = { "sky","天空" };//正常情況下是這樣的,先構造kv1對象,再用initializer list (5) initializer 列表構造//map<string, string> dict = { kv1 };//這里是pair的多參數的構造的轉換,以前的單參數是直接構造,這里省略了上面的步驟map<string, string> dict = { {"left","左邊"},{"right","右邊"},{"list","列表"},{"animal","動物"} };auto it = dict.begin();while (it != dict.end()){cout << (*it).first << ":"<<(*it).second << endl;// map的迭代基本都使?operator->,這?省略了?個->// 第?個->是迭代器運算符重載,返回pair*,第?個箭頭是結構指針解引?取pair數據//cout << it->first << ":"<<it->second << endl;//cout << it.operator->()->first << ":" << it->second << endl;it++;}cout << endl;//范圍for,為什么這里使用引用?for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}cout << endl;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// insert插?pair對象的4種?式,對?之下,最后?種最?便pair<string, string> kv2("one","一");dict.insert(kv2);//匿名對象去插入dict.insert(pair<string, string>("num", "數字"));//前兩個都是創建pair的對象,有名和匿名的區別dict.insert(make_pair("two", "二"));//多參數也支持隱式類型轉換dict.insert({ "three", "三" });for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}cout << endl;//結構化綁定,將dict里面的值分別賦值給k和v,C++17才開始支持的for (const auto& [k,v] : dict){cout << k << ":" << v << endl;}//經典的key/value場景,通過一個值去找另一個值string str;while (cin >> str){auto ret = dict.find(str);if (ret != dict.end()){cout << "->" << ret->second << endl;}else{cout << "不存在!請重新輸入" << endl;}}return 0;
}
//修改map里面的second#include<iostream>
#include<map>
#include<string>using namespace std;int main()
{map<string, string> dict = { {"left","左邊"},{"right","右邊"},{"list","列表"},{"animal","動物"} };//通過迭代器進行修改,但是僅能修改secondfor (auto& e : dict){e.second += "y";cout << e.second << endl;}cout << endl;//通過find進行修改auto ret = dict.find("left");ret->second = "左邊";for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}return 0;
}
3.7?map的數據修改+map的迭代器和[ ]功能樣例
[ ]的底層是用insert實現的,我們先來了解insert?
前?我提到map?持修改mapped_type 數據,不?持修改key數據,修改關鍵字數據,破壞了底層搜索樹的結構。 map第?個?持修改的?式是通過迭代器,迭代器遍歷時或者find返回key所在的iterator修改,map 還有?個?常重要的修改接?operator[],但是operator[]不僅僅?持修改,還?持插?數據和查找數據,所以他是?個多功能復合接?需要注意從內部實現?度,map這?把我們傳統說的value值,給的是T類型,typedef為 mapped_type。?value_type是紅?樹結點中存儲的pair鍵值對值。?常使?我們還是習慣將這?的T映射值叫做value。
Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair<const key_type,mapped_type>
// 查找k,返回k所在的迭代器,沒有找到返回end(),如果找到了通過iterator可以修改key對應的
mapped_type值
iterator find (const key_type& k);// ?檔中對insert返回值的說明
// The single element versions (1) return a pair, with its member pair::first
set to an iterator pointing to either the newly inserted element or to the
element with an equivalent key in the map. The pair::second element in the pair
is set to true if a new element was inserted or false if an equivalent key
already existed.// insert插??個pair<key, T>對象
// 1、如果key已經在map中,插?失敗,則返回?個pair<iterator,bool>對象,返回pair對象
first是key所在結點的迭代器,second是false// 2、如果key不在在map中,插?成功,則返回?個pair<iterator,bool>對象,返回pair對象
first是新插?key所在結點的迭代器,second是true// 也就是說?論插?成功還是失敗,返回pair<iterator,bool>對象的first都會指向key所在的迭代器
// 那么也就意味著insert插?失敗時充當了查找的功能,正是因為這?點,insert可以?來實現operator[]
// 需要注意的是這?有兩個pair,不要混淆了,?個是map底層紅?樹節點中存的pair<key, T>,另
?個是insert返回值pair<iterator,bool>pair<iterator,bool> insert (const value_type& val);
mapped_type& operator[] (const key_type& k);
// operator的內部實現
mapped_type& operator[] (const key_type& k)
{
// 1、如果k不在map中,insert會插?k和mapped_type默認值,同時[]返回結點中存儲
mapped_type值的引?,那么我們可以通過引?修改返映射值。所以[]具備了插?+修改功能
// 2、如果k在map中,insert會插?失敗,但是insert返回pair對象的first是指向key結點的
迭代器,返回值同時[]返回結點中存儲mapped_type值的引?,所以[]具備了查找+修改的功能
pair<iterator, bool> ret = insert({ k, mapped_type() });
iterator it = ret.first;
return it->second;
}
【應用1】?
#include<iostream>
#include<map>
#include<string>using namespace std;int main()
{map<string, string> dict;//不存在,插入{"insert",string()},value中插入的是string()的默認值dict["insert"];//不存在,成功插入,返回的是value的引用,可以完成修改dict["list"] = "列表";//修改dict["list"] = "列表,清單";//查找,已存在就返回已存在list結點迭代器中value的引用cout << dict["list"] << endl;return 0;
}
【應用2】
int main()
{// 利?find和iterator修改功能,統計?果出現的次數string arr[] = { "蘋果", "西?", "蘋果", "西?", "蘋果", "蘋果", "西?","蘋果", "?蕉", "蘋果", "?蕉" };map<string, int> countMap;for (const auto& str : arr){// 先查找?果在不在map中// 1、不在,說明?果第?次出現,則插?{?果, 1}// 2、在,則查找到的節點中?果對應的次數++auto ret = countMap.find(str);if (ret == countMap.end()){countMap.insert({ str, 1 });}else{ret->second++;}}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;return 0;
}//根據上面學的知識,下面一句代碼就搞定上面代碼的場景,厲害!
int main()
{// 利?[]插?+修改功能,巧妙實現統計?果出現的次數string arr[] = { "蘋果", "西?", "蘋果", "西?", "蘋果", "蘋果", "西?","蘋果", "?蕉", "蘋果", "?蕉" };map<string, int> countMap;for (const auto& str : arr){// []先查找?果在不在map中// 1、不在,說明?果第?次出現,則插?{?果, 0},同時返回次數的引?,++?下就變成1次了// 2、在,則返回?果對應的次數++countMap[str]++;}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;return 0;
}
3.8?multimap和map的差異
multimap和map的使?基本完全類似,主要區別點在于multimap?持關鍵值key冗余,那么 insert/find/count/erase都圍繞著?持關鍵值key冗余有所差異,這?跟set和multiset完全?樣,?如 find時,有多個key,返回中序第?個。其次就是multimap不?持[],因為?持key冗余,[]就只能?持插入了,不能?持修改。
3.9?138. 隨機鏈表的復制 - 力扣(LeetCode)
數據結構初階階段,為了控制隨機指針,我們將拷?結點鏈接在原節點的后?解決,后?拷?節點還得解下來鏈接,?常?煩。這?我們直接讓{原結點,拷?結點}建?映射關系放到map中,控制隨機指針會?常簡單?便,這?體現了map在解決?些問題時的價值,完全是降維打擊。
一開始不理解的,順著下面的代碼思路自己畫圖,當你畫到處理random代碼的時候你就會恍然大悟,泰褲辣!我菜還是得多練
class Solution {
public:Node* copyRandomList(Node* head) {map<Node*, Node*> nodeMap;Node* copyhead = nullptr, * copytail = nullptr;Node* cur = head;while (cur){if (copytail == nullptr){copyhead = copytail = new Node(cur->val);}else{copytail->next = new Node(cur->val);copytail = copytail->next;}// 原節點和拷?節點map kv存儲nodeMap[cur] = copytail;cur = cur->next;}// 處理randomcur = head;Node* copy = copyhead;while (cur){if (cur->random == nullptr){copy->random = nullptr;}else{copy->random = nodeMap[cur->random];}cur = cur->next;copy = copy->next;}return copyhead;}
};
3.10?692. 前K個高頻單詞 - 力扣(LeetCode)
本題?我們利?map統計出次數以后,返回的答案應該按單詞出現頻率由?到低排序,有?個特殊要求,如果不同的單詞有相同出現頻率,按字典順序排序。
解決思路1: ?排序找前k個單詞,因為map中已經對key單詞排序過,也就意味著遍歷map時,次數相同的單詞, 字典序?的在前?,字典序?的在后?。那么我們將數據放到vector中??個穩定的排序就可以實現上?特殊要求,但是sort底層是快排,是不穩定的,所以我們要?stable_sort,他是穩定的。
class Solution {
public:struct Compare{bool operator()(const pair<string, int>& x, const pair<string, int>& y)const{return x.second > y.second;}};vector<string> topKFrequent(vector<string>& words, int k) {map<string, int> countMap;for (auto& e : words){countMap[e]++;}vector<pair<string, int>> v(countMap.begin(), countMap.end());// 仿函數控制降序stable_sort(v.begin(), v.end(), Compare());//sort(v.begin(), v.end(), Compare());// 取前k個vector<string> strV;for (int i = 0; i < k; ++i){strV.push_back(v[i].first);}return strV;}
};
解決思路2: 將map統計出的次數的數據放到vector中排序,或者放到priority_queue中來選出前k個。利?仿函數強?控制次數相等的,字典序?的在前?。
class Solution {
public:struct Compare{bool operator()(const pair<string, int>& x, const pair<string, int>& y)const{return x.second > y.second || (x.second == y.second && x.first <y.first);;}};vector<string> topKFrequent(vector<string>& words, int k) {map<string, int> countMap;for (auto& e : words){countMap[e]++;}vector<pair<string, int>> v(countMap.begin(), countMap.end());// 仿函數控制降序,仿函數控制次數相等,字典序?的在前?sort(v.begin(), v.end(), Compare());// 取前k個vector<string> strV;for (int i = 0; i < k; ++i){strV.push_back(v[i].first);}return strV;}
};
class Solution {
public:struct Compare{bool operator()(const pair<string, int>& x, const pair<string, int>& y)const{// 要注意優先級隊列底層是反的,?堆要實現?于?較,所以這?次數相等,想要字典//序?的在前?要?較字典序?的為真return x.second < y.second || (x.second == y.second && x.first >y.first);}};vector<string> topKFrequent(vector<string>& words, int k) {map<string, int> countMap;for (auto& e : words){countMap[e]++;}// 將map中的<單詞,次數>放到priority_queue中,仿函數控制?堆,次數相同按照字典//序規則排序priority_queue<pair<string, int>, vector<pair<string, int>>, Compare>p(countMap.begin(), countMap.end());vector<string> strV;for (int i = 0; i < k; ++i){strV.push_back(p.top().first);p.pop();}return strV;}
};
完——
花曇り_佐藤千亜妃
現在聽到,依舊喜歡
至此結束——
我是云邊有個稻草人
期待與你的下一次相遇......