C++——map相关的oj题

前言:菜鸟写博客给自己看,我是菜鸟。

1:随机链表的复制

1.1题目要求:

1.2解题思路:

可以分两步来实现代码

①先将示例1链表中的val值以及next的指向关系深拷贝到另一个新的链表当中

②再处理新链表中,random的指向关系。

思考

第①步是很容易实现的,那么如何处理新链表中random的指向关系呢?这时候可以试着用map去解决。

map<key,T>

map<key,T>的底层是红黑树,其内部的数据是使用pair<key,T>存储键值对数据(这里的key,T是数据类型),键值对是一一对应/映射的关系。举一个简单的例子:

"苹果" <-> "apple"

"橘子" <-> "orange" 

其中,key是不可修改的,而T是可修改的。

分析

在第①步创建新节点的同时,将新节点与旧节点通过map<Node*,Node*> 建立键值对的关系,这样就得到了新旧节点间的映射关系。

更进一步的,再仔细想想如何处理新链表中random的指向关系呢?

新节点->random = 旧节点->random  吗? 显然不是,题目要求构造一个全新的链表,这样的指向关系,会使得新旧链表的random指向同一个节点。

因此不是 新节点->random = 旧节点->random ,而是 新节点->random = 旧节点->random所映射的节点,可以通过map函数中的operator[]来实现。

总结

在第①步创建链表的同时,将新旧节点通过map<Node*,Node*>建立映射关系。

在第②步中,可以通过映射关系,例如 旧13节点的random 指向 7节点,那么 新13节点 可以通过 旧13节点的random 先找到 旧7节点,再根据 map<Node*,Node*> 建立的映射关系,找到 新7节点 ,从而建立正确的指向关系

1.3实现代码:

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        map<Node*,Node*> copymap;
        Node* copyhead = nullptr;
        Node* 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;
            }
            copymap[cur] = copytail;
            cur = cur->next;
        }

        Node* copy = copyhead;
        cur = head;
        while(cur)
        {
            if(cur->random == nullptr)
            {
                copy->random = nullptr;
            }
            else
            {
                copy->random = copymap[cur->random];
            }
            cur = cur->next;
            copy = copy->next;
        }
        return copyhead;
    }
};

2:前K个高频单词

2.1题目要求:

前言:这是一道综合应用stl的题目,难度对于新人(博主)来说有点大,本题涉及一些对先前知识的查漏补缺。

2.2解题思路:

思路

👉:首先应该想到的是:创建一个map<string,int>  CountMap 来统计每个单词出现的个数。

👉:map类会自动将数据按照 key(前一个数据类型)来排列,即此时 CountMap 中的数据是按照 string(对应首字母的ascii码值)来排序。

👉:但是题目要求是出现次数多的在前,因此我们需要对map中的数据做处理

👉:将map中的数据拷贝到vector中,并排列得到我们想要的顺序

👉:最后再输出vector中前k个字母。

注:上述还涉及很多细节问题,在2.3中再做讨论。

2.3实现代码:

class Solution {
public:
    struct compare
    {
        bool operator()(const pair<string,int>& x1,const pair<string,int>& x2)
        {
            return x1.second > x2.second || (x1.second == x2.second && x1.first < x2.first);
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        //统计每个字母出现的次数
        map<string,int> CountMap;
        for(auto& e : words)
        {
            CountMap[e]++;
        }

        //将map中的数据拷贝到vector中进行比较
        vector<pair<string,int>> v(CountMap.begin(),CountMap.end());//按字符串顺序排列
        
        //默认的比较方式不满足我们的要求,因此需要自己写一个仿函数来实现
        stable_sort(v.begin(),v.end(),compare());

        //取前K个单词,并存放到 str 中作为返回值
        vector<string> str;
        for(int i = 0; i<k; i++)
        {
            str.push_back(v[i].first);
        }
        
        return str;
    }
};

将代码逐一拆分解释:

        map<string,int> CountMap;
        for(auto& e : words)
        {
            CountMap[e]++;
        }

该段代码用于统计每个字母出现的次数,通过map类(map<string,int>)来记录单词与出现字数之间的映射关系。

map<key,T>  map类会按照key默认进行排序

        vector<pair<string,int>> v(CountMap.begin(),CountMap.end());//按字符串顺序排列
        stable_sort(v.begin(),v.end(),compare());

因为map类的默认排序不满足题给要求,因此我们需要新创建一个vector类,来保存map类中的数据。

★★★:在map类中,iterator的返回类型是:pair<Key,T>。因此在创建 vector类时,默认参数为:pair<string,int>

问:这里为什么不用sort?而是用stale_sort,二者有什么区别?

:编译不通过是一回事,更重要的是,排序的稳定性!

复习:排序分为稳定排序和不稳定排序,两者的区别在于:原本的数据如果已经满足排序要求,当前排序算法会不会改变原先的排列顺序,改变->不稳定排序;不改变->稳定排序

稳定排序:冒泡排序、插入排序、归并排序

不稳定排序:希尔排序、快速排序、堆排序等

其次:stable_sort 默认排序不满足我们的要求,因此需要自己写一个仿函数来实现我们所需的排序,如下:

    struct compare
    {
        bool operator()(const pair<string,int>& x1,const pair<string,int>& x2)
        {
            return x1.second > x2.second;
        }
    };

compare() 涉及匿名对象调用的问题,可以通过两种方式来让stable_sort来调用我们的函数,一种是实例化compare对象,通过实例化的对象来调用,例如

        compare com;
        stable_sort(v.begin(),v.end(),com); 

此时不需要加括号,还有一种就是图中代码所写的匿名对象来调用。

注1:大多数时候,我们是不用写第三个参数的,只不过有些时候因为默认参数不满足我们的要求,因此这种时候需要通过仿函数来满足自己的要求。

注2:operator(),这个在优先队列一节中也曾使用过。

        vector<string> str;
        for(int i = 0; i<k; i++)
        {
            str.push_back(v[i].first);
        }

此时v中的数据已经按题目要求进行排序,只需将前k个字母插入到 str 当中即可得到最终答案。

3:单词识别

3.1题目要求

3.2解题思路

个人感想:对于博主而言,一道里程碑级的题目

思路

①:需要输入一句英文句子   

string sentence; 
getline(cin,sentence);

②:因为string遍历句子识别的是一个个字母,因此接下来做的是识别单词,并将单词存入到vector<string>当中

string tmp;    //临时存放识别完成的单词
vector<string> v;//将识别成功的单词存入到v中
for(int i = 0; i < sentence.size(); i++)
{
    //....
    //....
}

在遍历sentence[i]的过程中会遇到三中情况:

:为小写字母,此时直接 tmp.push_back(sentence[i]);

:为大写字母,转为小写后再 tmp.push_back(sentence[i]);

:其他,则说明此时一个单词已经识别完毕,即tmp中存储的是一个完整的单词,那么直接v.push_back(tmp); tmp.clear; 不要忘了清空tmp,为下一次识别做准备。

重复上述 Ⅰ、Ⅱ、Ⅲ 直至循环结束。

③:从这一步开始就和 第2题 的思路一模一样,创建 map<string,int> CountMap 记录每个单词出现的次数,将数据暂存进新的vector,并自己写一个满足题目要求的仿函数进行排序,最后再遍历输出目标结果

3.3实现代码

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

struct Com
{
    bool operator()(const pair<string,int>& x1,const pair<string,int>& x2)
    {
        return x1.second > x2.second;
    }
};

int main() {
    //输入一个英文句子
    string sentence;
    getline(cin,sentence);


    //将字母一一存到vector当中
    vector<string> v;
    string tmp;
    for(int i = 0; i < sentence.size(); i++)
    {
        if(sentence[i] >='a' && sentence[i] <= 'z')
        {
            tmp.push_back(sentence[i]);
        }else if (sentence[i] >='A' && sentence[i] <= 'Z') //大小写转换
        {
            sentence[i]+=32;
            tmp.push_back(sentence[i]);
        }
        else 
        {
            v.push_back(tmp);
            tmp.clear();//清空tmp,为了下一次能够识别单词
        }
    }
    //统计字母出现的次数
    map<string,int> CountMap;
    for(auto& e : v)
    {
        CountMap[e]++;
    }

    //将map中的数据默认是按key排列的,因此需要重新排列,保存到vector中进行重新排列
    vector<pair<string,int>> v2(CountMap.begin(),CountMap.end());
    stable_sort(v2.begin(),v2.end(),Com());//默认的函数不满足我们的排序,因此需要自己写一个仿函数,并且通过匿名对象调用

    //最后遍历排列好的vector 输出最终答案
    for(int i = 0; i < v2.size(); i++)
    {
        cout << v2[i].first << ":" << v2[i].second << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值