LeetCode: Two Sum

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, and you may not use the same element twice.

"""1. 两重循环暴力搜索,236 ms
时间复杂度: O(n^2);空间复杂度:O(1),没占用额外的存储空间

std::vector::push_back
Adds a new element at the end of the vector, after its current last element.
This effectively increases the container size by one, which causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.
"""
#include <iostream>
#include <unordered_map>
#include <vector>

using namespace std;

vector<int> twoSum(vector<int>& nums, int target) {
    vector<int> result;
    for (int i = 0; i<nums.size(); i++)
    {
        for (int j = i + 1; j<nums.size(); j++)
        {
            if (nums[i] + nums[j] == target)
                //or nums[j] == target - nums[i]
            {
                result.push_back(i);
                result.push_back(j);
                return result;
            }
        }
    }
}

int main()
{
    static const int myints[] = { 3, 2, 4 };
    vector<int> nums;
    nums.assign(myints, myints + 3);
    int target = 6;
    vector<int> result = twoSum(nums, target);
    cout << result[0] << result[1] << endl;
    system("pause");
}

更快的算法需要用到哈希表,先复习一下算法导论(只记录一些基本概念和结论,性能分析书上写的比较清楚了):
数组的直接寻址,可以在O(1)的时间访问任意元素。但是直接寻址法可能浪费了存储空间,因为实际需要存储的关键字集合T可能少于全域U,而U也可能非常大,使得存储变得不可能。
散列函数可以缩小需要处理的下标范围。将关键字为 K的元素放到 h(k) 中,也就是利用散列函数 h, 根据关键字 k计算出槽的位置。函数 h将关键字域 U映 射到散列表 T[0,1,…,m−1]的槽位上,这样需要处理的下表就是0:m-1。
好的散列函数特点:每个关键字都等可能地散列到 m个槽位的任何一个之中去,并与其他的关键字已被散列到哪一个槽位中无关(简单一致散列)。
常见的散列方式如除法散列法:h(k)=k mod m。两个关键字可能映射到同一槽上,这种情况称发生了碰撞。此时可以将散列到同一槽中的所有元素都放在一个链表中(chaining)。查找,插入和删除的平均时间复杂度都是O(1)。另一种碰撞处理是开放寻址法,对于每一个关键字 k,使用开放寻址法的探查 ,使用开放寻址法的探查 序列为:h(k,0) , h(k,1) ,∙∙∙, h(k,m − 1)
当散列表逐渐填满时,每个表位最终都可以被考虑为用来插入新关键字的槽。

"""2. Two-pass Hash Table, 15 ms
主要考虑利用哈希表来将(前面对j的循环)查找时间从O(n)降低到O(1)。这样整体的时间复杂度会降低到O(n),哈希表的空间复杂度为O(n)。

c++参考
http://www.cplusplus.com/reference/unordered_map/unordered_map/find/
http://en.cppreference.com/w/cpp/container/unordered_map
"""
#include <iostream>
#include <unordered_map>
#include <vector>

using namespace std;

vector<int> twoSum(vector<int>& nums, int target)
{
    vector<int> result;
    unordered_map<int, int> map;
    for (int i = 0; i < nums.size(); i++)
    {
        map.insert({ nums[i], i });
    }

    for (int i = 0; i < nums.size(); i++)
    {
        int complement = target - nums[i];
        auto j = map.find(complement);
        if (j != map.end()) #注意处理异常
        {
            int j_index = j->second;

            if (j_index != i)
            {
                result.push_back(i);
                result.push_back(j_index);
                return result;
            }
        }
    }
}

int main()
{
    int myints[] = { 3, 2, 3 };
    vector<int> nums;
    nums.assign(myints, myints + 3);
    int target = 6;
    vector<int> result = twoSum(nums, target);
    cout << result[0] << result[1] << endl;

    std::unordered_map<int, char> example = { { 1, 'a' }, { 2, 'b' }, {2, 'c'} };
    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << search->first << " " << search->second << '\n';
    }
    else {
        std::cout << "Not found\n";
    }

    std::unordered_map<int, char> map = { { 1, 'a' }, { 1, 'b' }, { 1, 'd' }, { 2, 'b' } };
    auto range = map.equal_range(2);
    cout << range.first->first;

    system("pause");
}
"""3. One-pass Hash Table, 6 ms, beats 76.26%
上面用了两个循环,可以用一个循环同时做构建哈希表和进行查找这两件事。
"""
#include <iostream>
#include <unordered_map>
#include <vector>

using namespace std;

vector<int> twoSum(vector<int>& nums, int target)
{
    vector<int> result;
    unordered_map<int, int> map;
    for (int i = 0; i < nums.size(); i++)
    {
        map.insert({ nums[i], i });

        int complement = target - nums[i];
        auto j = map.find(complement);
        if (j != map.end())
        {
            int j_index = j->second;

            if (j_index != i)
            {
                result.push_back(i);
                result.push_back(j_index);
                return result;
            }
        }
    }
}

int main()
{
    int myints[] = { 3, 2, 3 };
    vector<int> nums;
    nums.assign(myints, myints + 3);
    int target = 6;
    vector<int> result = twoSum(nums, target);
    cout << result[0] << result[1] << endl;

    system("pause");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值