【Leetcode】 1.two sum unordered_map 关联容器

来源:互联网 发布:软件ac管理控制器 编辑:程序博客网 时间:2024/05/16 01:50

001.Two Sum[E]

1.题目

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution.

Example:

Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9,return [0, 1].
实现:

Hashmap

最后一种是比较聪明的做法,用hashmap,hashmap是内部存储方式为哈希表的map结构,哈希表可以达到查找O(1),哈希表的介绍可以看这里, C++实现Hashmap的方式,这里用unordered_map关联容器,可以实现键值对应。

class Solution {public:    vector<int> twoSum(vector<int>& nums, int target) {        //vector<int> result;        unordered_map<int,int> mymap;        int res;        for(int i = 0;i < nums.size();i++)        {            res = target - nums[i];            unordered_map<int,int>::iterator it = mymap.find(res);            if(it != mymap.end())            {                return vector<int>({it->second,i});            }            mymap[nums[i]] = i;        }    }};




1.介绍

最近使用到一个c++的容器——unordered_map,它是一个关联容器,内部采用的是hash表结构,拥有快速检索的功能。

1.1 特性

  1. 关联性:通过key去检索value,而不是通过绝对地址(和顺序容器不同)
  2. 无序性:使用hash表存储,内部无序
  3. Map : 每个值对应一个键值
  4. 键唯一性:不存在两个元素的键一样
  5. 动态内存管理:使用内存管理模型来动态管理所需要的内存空间

1.2 Hashtable和bucket

由于unordered_map内部采用的hashtable的数据结构存储,所以,每个特定的key会通过一些特定的哈希运算映射到一个特定的位置,我们知道,hashtable是可能存在冲突的(多个key通过计算映射到同一个位置),在同一个位置的元素会按顺序链在后面。所以把这个位置称为一个bucket是十分形象的(像桶子一样,可以装多个元素)。可以参考这篇介绍哈希表的文章

这里写图片描述

所以unordered_map内部其实是由很多哈希桶组成的,每个哈希桶中可能没有元素,也可能有多个元素。

2. 模版

template < class Key,                                    // unordered_map::key_type           class T,                                      // unordered_map::mapped_type           class Hash = hash<Key>,                       // unordered_map::hasher           class Pred = equal_to<Key>,                   // unordered_map::key_equal           class Alloc = allocator< pair<const Key,T> >  // unordered_map::allocator_type           > class unordered_map;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

主要使用的也是模板的前2个参数<键,值>(需要更多的介绍可以点击这里)

unordered_map<const Key, T> map;
  • 1

2.1 迭代器

unordered_map的迭代器是一个指针,指向这个元素,通过迭代器来取得它的值。

unordered_map<Key,T>::iterator it;(*it).first;             // the key value (of type Key)(*it).second;            // the mapped value (of type T)(*it);                   // the "element value" (of type pair<const Key,T>) 
  • 1
  • 2
  • 3
  • 4

它的键值分别是迭代器的first和second属性。

it->first;               // same as (*it).first   (the key value)it->second;              // same as (*it).second  (the mapped value) 
  • 1
  • 2

3. 功能函数

3.1 构造函数

unordered_map的构造方式有几种: 
- 构造空的容器 
- 复制构造 
- 范围构造 
- 用数组构造

3.1.2示例代码

// constructing unordered_maps#include <iostream>#include <string>#include <unordered_map>using namespace std;typedef unordered_map<string,string> stringmap;stringmap merge (stringmap a,stringmap b) {  stringmap temp(a); temp.insert(b.begin(),b.end()); return temp;}int main (){  stringmap first;                              // 空  stringmap second ( {{"apple","red"},{"lemon","yellow"}} );       // 用数组初始  stringmap third ( {{"orange","orange"},{"strawberry","red"}} );  // 用数组初始  stringmap fourth (second);                    // 复制初始化  stringmap fifth (merge(third,fourth));        // 移动初始化  stringmap sixth (fifth.begin(),fifth.end());  // 范围初始化  cout << "sixth contains:";  for (auto& x: sixth) cout << " " << x.first << ":" << x.second;  cout << endl;  return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

输出结果:

sixth contains: apple:red lemon:yellow orange:orange strawberry:red
  • 1
  • 2

3.2 容量操作

3.2.1 size

size_type size() const noexcept;
  • 1
  • 2

返回unordered_map的大小

3.2.2 empty

bool empty() const noexcept;
  • 1
  • 2

- 为空返回true 
- 不为空返回false,和用size() == 0判断一样。

3.3 元素操作

3.3.1 find

iterator find ( const key_type& k );
  • 1
  • 2

查找key所在的元素。 
- 找到:返回元素的迭代器。通过迭代器的second属性获取值 
- 没找到:返回unordered_map::end

3.3.2 insert

插入有几种方式: 
- 复制插入(复制一个已有的pair的内容) 
- 数组插入(直接插入一个二维数组) 
- 范围插入(复制一个起始迭代器和终止迭代器中间的内容) 
- 数组访问模式插入(和数组的[]操作很相似)

具体的例子可以看后面示例代码。

3.3.3 at

mapped_type& at ( const key_type& k );
  • 1
  • 2

查找key所对应的值 
- 如果存在:返回key对应的值,可以直接修改,和[]操作一样。 
- 如果不存在:抛出 out_of_range 异常.

mymap.at(“Mars”) = 3396; //mymap[“Mars”] = 3396

3.3.4 erase

擦除元素也有几种方式:

  • 通过位置(迭代器)

    iterator erase ( const_iterator position );
    • 1
    • 2
  • 通过key

    size_type erase ( const key_type& k );
    • 1
    • 2
  • 通过范围(两个迭代器)

    iterator erase ( const_iterator first, const_iterator last );
    • 1
    • 2

3.3.5 clear

void clear() noexcept
  • 1
  • 2

清空unordered_map

3.3.6 swap

void swap ( unordered_map& ump );
  • 1
  • 2

交换两个unordered_map(注意,不是交换特定元素,是整个交换两个map中的所有元素)

3.3.7 示例代码

// unordered_map::insert#include <iostream>#include <string>#include <unordered_map>using namespace std;void display(unordered_map<string,double> myrecipe,string str){    cout << str << endl;    for (auto& x: myrecipe)        cout << x.first << ": " << x.second << endl;    cout << endl;}int main (){    unordered_map<string,double>    myrecipe,    mypantry = {{"milk",2.0},{"flour",1.5}};    /****************插入*****************/    pair<string,double> myshopping ("baking powder",0.3);    myrecipe.insert (myshopping);                        // 复制插入    myrecipe.insert (make_pair<string,double>("eggs",6.0)); // 移动插入    myrecipe.insert (mypantry.begin(), mypantry.end());  // 范围插入    myrecipe.insert ({{"sugar",0.8},{"salt",0.1}});    // 初始化数组插入(可以用二维一次插入多个元素,也可以用一维插入一个元素)    myrecipe["coffee"] = 10.0;  //数组形式插入    display(myrecipe,"myrecipe contains:");    /****************查找*****************/    unordered_map<string,double>::const_iterator got = myrecipe.find ("coffee");    if ( got == myrecipe.end() )        cout << "not found";    else        cout << "found "<<got->first << " is " << got->second<<"\n\n";    /****************修改*****************/    myrecipe.at("coffee") = 9.0;    myrecipe["milk"] = 3.0;    display(myrecipe,"After modify myrecipe contains:");    /****************擦除*****************/    myrecipe.erase(myrecipe.begin());  //通过位置    myrecipe.erase("milk");    //通过key    display(myrecipe,"After erase myrecipe contains:");    /****************交换*****************/    myrecipe.swap(mypantry);    display(myrecipe,"After swap with mypantry, myrecipe contains:");    /****************清空*****************/    myrecipe.clear();    display(myrecipe,"After clear, myrecipe contains:");    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

输出结果:

myrecipe contains:salt: 0.1milk: 2flour: 1.5coffee: 10eggs: 6sugar: 0.8baking powder: 0.3found coffee is 10After modify myrecipe contains:salt: 0.1milk: 3flour: 1.5coffee: 9eggs: 6sugar: 0.8baking powder: 0.3After erase myrecipe contains:flour: 1.5coffee: 9eggs: 6sugar: 0.8baking powder: 0.3After swap with mypantry, myrecipe contains:flour: 1.5milk: 2After clear, myrecipe contains:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

3.4 迭代器和bucket操作

3.4.1 begin

  iterator begin() noexcept;  local_iterator begin ( size_type n );
  • 1
  • 2
  • 3
  • begin() : 返回开始的迭代器(和你的输入顺序没关系,因为它的无序的)
  • begin(int n) : 返回n号bucket的第一个迭代器

3.4.2 end

  iterator end() noexcept;  local_iterator end( size_type n );
  • 1
  • 2
  • 3
  • end(): 返回结束位置的迭代器
  • end(int n) : 返回n号bucket的最后一个迭代器

3.4.3 bucket

size_type bucket ( const key_type& k ) const;
  • 1
  • 2

返回通过哈希计算key所在的bucket(注意:这里仅仅做哈希计算确定bucket,并不保证key一定存在bucket中!)

3.4.4 bucket_count

size_type bucket_count() const noexcept;
  • 1
  • 2

返回bucket的总数

3.4.5 bucket_size

size_type bucket_size ( size_type n ) const;
  • 1

返回第i个bucket的大小(这个位置的桶子里有几个元素,注意:函数不会判断n是否在count范围内)

3.4.6 示例代码

// unordered_map::bucket_count#include <iostream>#include <string>#include <unordered_map>using namespace std;int main (){    unordered_map<string,string> mymap =    {        {"house","maison"},        {"apple","pomme"},        {"tree","arbre"},        {"book","livre"},        {"door","porte"},        {"grapefruit","pamplemousse"}    };    /************begin和end迭代器***************/    cout << "mymap contains:";    for ( auto it = mymap.begin(); it != mymap.end(); ++it )        cout << " " << it->first << ":" << it->second;    cout << endl;    /************bucket操作***************/     unsigned n = mymap.bucket_count();    cout << "mymap has " << n << " buckets.\n";    for (unsigned i=0; i<n; ++i)    {        cout << "bucket #" << i << "'s size:"<<mymap.bucket_size(i)<<" contains: ";        for (auto it = mymap.begin(i); it!=mymap.end(i); ++it)            cout << "[" << it->first << ":" << it->second << "] ";        cout << "\n";    }    cout <<"\nkey:'apple' is in bucket #" << mymap.bucket("apple") <<endl;    cout <<"\nkey:'computer' is in bucket #" << mymap.bucket("computer") <<endl;    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

输出结果:

mymap contains: door:porte grapefruit:pamplemousse tree:arbre apple:pomme book:livre house:maisonmymap has 7 buckets.bucket #0's size:2 contains: [book:livre] [house:maison]bucket #1's size:0 contains:bucket #2's size:0 contains:bucket #3's size:2 contains: [grapefruit:pamplemousse] [tree:arbre]bucket #4's size:0 contains:bucket #5's size:1 contains: [apple:pomme]bucket #6's size:1 contains: [door:porte]key:'apple' is in bucket #5key:'computer' is in bucket #6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

最后

unordered_map常用的功能函数介绍就这么多了,还有一些比较不常用的功能的介绍,可以参考这里

原创粉丝点击