LeetCode 1. Two Sum

9 篇文章 0 订阅
2 篇文章 0 订阅

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.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

因为题目已经假设只有唯一解,所以不考虑有重复数字的情况。

解法一:
暴力搜索,穷举。时间复杂度O(n^2),空间复杂度O(1)。

解法二:
空间换时间。换个方向想,题目就是求目标值target和其中一个数A的差B在数组中的位置。维护数组中每个元素到索引的映射的最佳方法是什么? 一个哈希表,那么我就利用一个HashMap建立数组中数值和下标的关系。在一次迭代中,先在HashMap中寻找该差值是否存在,如果不存在就把数A及其下标存入HashMap;若是存在,就意味着已经得到最后的结果了。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, size_t> hashMap;
        vector<int> result;
        for (int i = 0; i < nums.size(); i++)
        {
            int remain = target - nums[i];
            auto findIt = hashMap.find(remain);
            if (findIt == hashMap.end())
            {
                hashMap.insert({ nums[i],i });
            }
            else
            {
                result.push_back(findIt->second);
                result.push_back(i);
            }
        }
        return result;
    }
};

时间复杂度、空间复杂度都是O(n)。

解法三:排序+二分查找
先对数组排序。排序后将双指针指向头部与尾部元素,进行迭代。如果双指针指向元素之和大于目标和,则将尾部指针向前移一位,反之则将头部指针向后移一位,直到双指针指向元素之和等于目标和,记录这两个元素的值。
(排序非常直接的就意味着二分搜索。一次查一半,所以刚开始只用到了二分搜索。但是有个问题,二分搜索的步子太大,可能把目标值跳过,那么还要借鉴双指针的全盘扫描的特点。)
存在的问题:
排序的效率?
排序的如何得到正确的索引?
复制一份数组进行排序,然后用原数组查找得到索引。我在此使用的是multiset,利用它本身有序的特性。(以为不含重复数,但是提交时有测试用例不通过)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {

        multiset<int> orderSet(nums.cbegin(), nums.cend());
        vector<int> rsNum, result;
        auto beg = orderSet.begin();
        auto end = orderSet.end();
        --end;
        while (beg != end)
        {
            if (*beg + *end == target)
            {
                rsNum.push_back(*beg);
                rsNum.push_back(*end);
                break;
            }
            else if (*beg + *end > target)
            {
                --end;
            }
            else
            {
                ++beg;
            }
        }
        for (int i = 0,j=0; i < nums.size(); i++)
        {
            if (nums[i] == *beg || nums[i] == *end)
            {
                ++j;
                result.push_back(i);
                if (j == 2)break;
            }
        }
        return result;
    }
};  
//这道题使用map的话可能会更简洁

补上multimap版本:
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        multimap <int, size_t> orderMap;
        vector<int> result;
        for (int i = 0; i < nums.size(); i++)
        {
            orderMap.insert({ nums[i],i });
        }
        auto beg = orderMap.begin();
        auto end = orderMap.end();
        --end;
        while (beg != end)
        {
            if (beg->first + end->first == target)
            {
                result.push_back(beg->second);
                result.push_back(end->second);
                break;
            }
            else if (beg->first + end->first > target)
            {
                --end;
            }
            else
            {
                ++beg;
            }
        }
        return result;
    }
};

总结综合结果来看,第二种方法是最快的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值