
系列文章目录
一、随机链表的复制
要深拷贝一个链表,比较简单,但是在该题目中,要处理random的指向问题就比较困难。
有没有一个办法使我们找到拷贝链表random的指向.
思路:使用kv关系,建立原节点和拷贝节点的kv关系。

有了kv关系,那么拷贝链表的random就可以很容易的找到它要指向的节点。
例如: 第二个节点13的random就是对应原节点的random的value:

如果指向空nullptr那么要而外判断:
class Solution {
public:
Node* copyRandomList(Node* head) {
//使用map建立源节点和拷贝节点的映射关系
map<Node*,Node*> nodeMap;
Node* copyhead = nullptr,* copytail = nullptr;
Node* cur = head;
while(cur)
{
//如果拷贝头节点为空,创建头节点
if(copyhead == nullptr)
{
copyhead = copytail = new Node(cur->val);
}
else
{
copytail->next = new Node(cur->val);
copytail = copytail->next;
}
//原节点和拷贝节点建立kv关系
nodeMap[cur] = copytail;
cur = cur->next;
}
//处理random
cur = head;
Node* copy = copyhead;
while(cur)
{
if(cur->random == nullptr) //为空就指向空
{
copy->random = nullptr;
}
else //不为空就指向random对应的拷贝节点
{
copy->random = nodeMap[cur->random];
}
cur = cur->next;
copy = copy->next;
}
return copyhead;
}
};
二、环形链表
环形链表||
思路:使用set的特性,set具有去重的特性,我们遍历节点的指针,如果节点的指针插入失败说明有重复的节点,这时说明链表带环,失败的节点即入口点。如果都插入成功,说明不带环。
利用set.insert()的返回值进行判断,是否插入成功。(关于返回值的详解在[map的介绍部分有详解])

环形链表|

class Solution {
public:
bool hasCycle(ListNode *head) {
set<ListNode*> nodeSet;
ListNode* cur = head;
while(cur)
{
auto ret = nodeSet.insert(cur);
if(ret.second == false)
{
return true;
}
cur = cur->next;
}
return false;
}
};
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
set<ListNode*> nodeSet;
ListNode* cur = head;
while(cur)
{
auto ret = nodeSet.insert(cur);
if(ret.second == false)
{
return cur;
}
cur = cur->next;
}
return nullptr;
}
};
三、俩个数组的交集
介绍一下什么是交集和差集。
交集:俩个数相同
差集:俩个数中小的那个就是差集
要找数组中的交集和差集:

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进行去重+排序
//然后遍历俩个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;
}
};
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
//不去重
multiset<int> s1(nums1.begin(),nums1.end());
multiset<int> s2(nums2.begin(),nums2.end());
//先利用set进行排序
//然后遍历俩个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;
}
};
交集和差集在同步服务中很常见:
差集进行同步。交集进行比对。
四、前K个高频单词
题目中较麻烦的就是,处理不同的单词,相同的频率,要按照字典序排序。
这里我们先处理好按照频率排序:
由于map是按string排序而不是频率,所以要按照int排序
但是标准库中的sort只支持随即迭代器。而map是双向迭代器。


所以我们将map的数据存到vector中 :
class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
map<string,int> countMap;
for(const auto& e : words)
countMap[e]++; //统计单词出现的次数
//由于map是按string排序而不是频率,所以要按照int排序
//但是标准库中的sort只支持随即迭代器。而map是双向迭代器。
//所以我们将map的数据存到vector中
vector<pair<string,int>> v(countMap.begin(),countMap.end());
sort(v.begin(),v.end());
}
};
但是pair是否支持比较大小呢?是支持的,但是会按照first成员进行比较:

所以我们要自己写仿函数,进行比较。然后将前K个高频的单词放入一个数组。
class Solution {
public:
struct Compare
{
bool operator()(const pair<string,int>& p1, const pair<string,int>& p2)
{
return p1.second > p2. second;
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
map<string,int> countMap;
for(const auto& e : words)
countMap[e]++; //统计单词出现的次数
//由于map是按string排序而不是频率,所以要按照int排序
//但是标准库中的sort只支持随即迭代器。而map是双向迭代器。
//所以我们将map的数据存到vector中
vector<pair<string,int>> v(countMap.begin(),countMap.end());
sort(v.begin(),v.end(),Compare()); //按照次数进行排序
//放入数组
vector<string> strV;
for(int i = 0; i < k; i++)
{
strV.push_back(v[i].first);
}
return strV;
}
};
但是这样不符合预期:

我们可以通过打印来查看:
//降序 >
sort(v.begin(),v.end(),Compare()); //按照次数进行排序
for(const auto& e : v )
cout << e.first << ":" << e.second << endl;
cout <<endl;
//放入数组

发现当次数相同时,单词并未按照字典序排序。
这里有俩种解决方案:
1、实际上我们在最开始,使用map统计时就是按照单词字典序排序的。由于sort的底层是自省排序(即快排),是一种不稳定的排序。会打乱原有的字典序顺序。
算法库中实际上还有一种稳定排序:stable_sort
将sort改为stable_sort即可。
stable_sort(v.begin(),v.end(),Compare()); //按照次数进行排序
2、修改仿函数逻辑,在同时比较次数相同时,进行单词字典序的比较:
struct Compare
{
bool operator()(const pair<string,int>& p1, const pair<string,int>& p2)
{
return p1.second > p2. second ||
(p1.second == p2.second && p1.first < p2.first);
}
};





1030

被折叠的 条评论
为什么被折叠?



