1. 两数之和

难度:简单
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109

只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

1. 循环暴力求解

通过两层for循环遍历各种组合求解,时间复杂度O(n2)O(n^2)O(n2)。用时296ms296 ms296ms

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for (int i = 0; i < nums.size(); i++) {
            for (int j = i + 1; j < nums.size(); j++) {
                if (nums[i] + nums[j] == target) {
                    return {i, j};
                }
            }
        }
        return {};
    }
};

2. 使用哈希查找

使用std::unordered_map<int, int>容器保持已经遍历的数据,再计算新数据时,再容器中查找是否有匹配值,使复杂度降低为O(n)O(n)O(n)。用时8ms8ms8ms

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        std::unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            int key = target - nums[i];
            auto itr = map.find(key);
            if (itr == map.end()) {
                map.emplace(nums[i], i);
            } else {
                return {i, itr->second};
            }
        }
        return {};
    }
};

3. 官方题解

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

4. CPP容器[1]

容器(container)是用于存放数据的类模板。可变数组、链表、平衡二叉树等数据结构在STL中都被实现为容器。容器在实例化时,需要指明容器中存放元素的类型,其既可以存放基本的类型(int、double、string等)的变量,也可以存放对象,当元素变量被插入容器中时,实际插入的是变量或者对象的一个复制品。
STL中的许多算法(模板函数),如排序、查找等,在执行过程中会对容器中的元素进行比较,通常使用<<<运算符,因此,被放入容器中的对象所属类最好重载======<<<运算符,以使得两个对象用======<<<比较时是有定义的。
容器有顺序容器关联容器

4.1 顺序容器

顺序容器有:可变动态数组vector、双端队列deque和双向链表list。是因为元素在容器中的位置和元素的值无关,即容器不是排序的,在指定位置插入,元素就会位于什么位置。

4.2 关联容器

关联容器有:setmultisetmapmultimap。 关联容器内的元素是排序的,在插入元素时,容器会按一定的排序规则将元素放到适当的位置,因此插入元素时不能指定位置。默认情况下,关联容器中的元素是从小到大排序的(或按关键字从小到大排序),而且是用<<<运算符比较元素或者关键字,因此关联容器在查找时具有很好的性能。

4.3 容器适配器

STL在两类容器的基础上屏蔽了一部分功能,突出或者增加了另一部分功能,实现了三种容器适配器:栈stack、队列queue和优先队列priority_queue

4.4 容器成员函数

所有容器(包括容器适配器)都有的成员函数有两个:

  • int size()
  • bool empty()

顺序容器和关联容器都有的成员函数:

  • begin();
  • end();
  • rbegin();
  • rend();
  • erase(...);
  • clear();

顺序容器还有以下常用成员函数:

  • front();
  • back();
  • push_back();
  • pop_back();
  • insert(...)

5. unordered_map[2]

unordered_map是STL提供的4中无序关联容器的一种,不会像map容器一样对存储的元素或者对象进行排序,因此unordered_mapmap只有一点不同,即map容器中数据是有序,而unordered_map中的数据是无序的。由于unordered_map容器底层采用的哈希表存储数据,该结构本身不具有对数据的排序功能,所以容器内部不会自动对存储的键值进行排序。

6. hash_map[3]

hash_map是基于hash table(哈希表)的,哈希表的最大的优点是把数据存储和查找消耗的时间大大降低,几乎是常数时间,而代价是消耗较多的内存,在许多情况小减小耗时更加重要。
其基本原理是,使用一个下标范围较大的数组来存储元素。可以设计一个函数(哈希函数,也叫散列函数),使得每个元素的关键字都与一个函数值(即数组小标,hash值)相对应,于是用这个数组单元来存储这个元素。但是不能保证每个元素的关键字与函数值都是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了"冲突",因此"直接定址"和"解决冲突"是哈希表的两大特点。
hash_map中直接地址使用hash函数生成,解决冲突,用比较函数解决。当关键字生成函数值对应区域只存储一个元素时,查找只有一次比较,因此查询会快很多。由此可见,要实现哈希表,和用户相关的是:hash函数和比较函数,这两个参数是使用hash_map时需要指定的参数。

template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
class _EqualKey = equal_to<_Key>,
class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class hash_map
{
        ...
}

从STL的声明中可以看出,hash_map的构造函数提供了缺省的hash函数和比较函数,支持基础的数据类型,如下。如果用户使用自定义数据类型时,就必须自定义hash函数和比较函数。

struct hash<char*>
struct hash<const char*>
struct hash<char> 
struct hash<unsigned char> 
struct hash<signed char>
struct hash<short>
struct hash<unsigned short> 
struct hash<int> 
struct hash<unsigned int>
struct hash<long> 
struct hash<unsigned long>

7. reference

[1] http://c.biancheng.net/view/331.html
[2] http://c.biancheng.net/view/7231.html
[3] https://blog.youkuaiyun.com/yousss/article/details/79541543

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值