两数之和等于目标值

1. LeetCode(twoCode)

Given an array of integers, find two numbers such that they add upto a specific target number.

The function twoSum should return indices of the two numbers suchthat they add up to the target, where index1 must be less than index2. Pleasenote that your returned answers (both index1 and index2) are not zero-based.

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

Input: numbers={2,7, 11, 15}, target=9

Output: index1=1,index2=2

2. 问题分析

(1) 暴力求解,检查所有对(n2)数字之和。

(2) 题目中并没有说数组是有序或无序,因此可以先按有序思考,毕竟排序方法太成熟了。若数组元素有序则可以从数组的两端开始求解,若两个数之和大于目标值则后端往前移,若小于则前端往后移,若相等则找到结果程序结束。若前后端相遇则查找失败。显然该方法时间复杂度O(n)。

(3) 若无序,则有两种处理思路:

(3.1) 先对数组进行排序,最快的排序算法O(n),则无序处理代价为O(n) + O(n) = O(n)。

进一步分析:常用的线性时间排序算法计数排序、桶排序等均有一定的限制,如当数组中元素跨度较大时计数排序需要较大的空间开销,桶排序要求元素均匀分布。因此对数组排序常使用快排(O(nlogn)),此时问题求解时间复杂度O(nlogn)。

(3.2) 用哈希存储原始数据。遍历原始数据,当访问数据是w,目标值是t时,在哈希表中查找是否存在t-w,若存在则查找成功;若不存在,则继续遍历,直到找到结果或遍历结束。哈希插入与查找代价均为O(1),因此整体时间复杂度仍是O(n)。

3 实现

3.1 暴力方法

该方法检测n2对元素的和,时间复杂度O(n2)。

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

3.2 先排序再求解1

在这里利用了C++STL中的sort排序函数,从sort源码实现来看其属于快排的优化,详细的请查看sort源代码。该方法时间复杂度O(nlogn)。

struct numStruct
{
      int number;
      int location;
      numStruct(int a = 0, int b = 0):number(a),location(b)
      {
      }
};

boolisLesser(numStruct a, numStruct b)
{
      return a.number < b.number;
}

vector<int>Solution::twoSum(vector<int> &nums, const int target)
{
      vector<int> result;
      int size = nums.size();
      numStruct *data = new numStruct[size];

      for (int i = 0; i < size; ++i)
      {
             data[i].number = nums[i];
             data[i].location = i;
      }
      sort(data, data + size, isLesser);
      int head, tail;
      head = 0;
      tail = size - 1;
      while (head < tail)
      {
             int tempResult = data[head].number+ data[tail].number;
             if (target == tempResult)
             {
                    int loc1, loc2;
                    loc1 = data[head].location +1;
                    loc2 = data[tail].location +1;
                    if (loc1 > loc2)
                    {
                           result.push_back(loc2);
                           result.push_back(loc1);
                    }
                    else
                    {
                           result.push_back(loc1);
                           result.push_back(loc2);
                    }
                    break;
             }
             else if (target < tempResult)
             {
                    --tail;
             }
             else
             {
                    ++head;
             }
      }
      delete []data;
      return result;
}

3.3先排序再求解2

(1) 很多博客里都把使用map当做哈希的方法,实际是错误的。因为map的底层是红黑树而不是哈希,红黑树中序有序。该方法时间复杂度O(nlogn)。

vector<int>Solution::twoSum(vector<int> &nums, const int target)
{
      vector<int> result;
      map<int, int> data;
      int size = nums.size();
      for (int i = 0; i < size; ++i)
      {
             if (!data.count(nums[i]))
             {
                    data.insert(pair<int,int>(nums[i], i));
             }
      }

      for (int i = 0; i < size; ++i)
      {
             if (data.find(target - nums[i]) !=data.end())
             {
                    result.push_back(data[target- nums[i]] + 1);
                    result.push_back(i + 1);
                    break;
             }
      }
      return result;
}

(2) 因为只需要找到一个结果,因此没必要索引全部的数据,上述代码优化为:

vector<int>Solution::twoSum(vector<int> &nums, const int target)
{
      vector<int> result;
      map<int, int> data;
      int size = nums.size();

      for (int i = 0; i < size; ++i)
      {
             if (data.find(target - nums[i]) !=data.end())
             {
                    result.push_back(data[target- nums[i]] + 1);
                    result.push_back(i + 1);
                    break;
             }
           data[nums[i]] = i;
      }
      return result;
}

(3) 又因为红黑树中序有序,因此可以利用中序遍历。中序遍历为:左-中-右,而逆向中序遍历为右-中-左。值得注意的是map中的键值唯一,因此使用multimap来代替map。综上,可以像3.2中那样实现。

vector<int>Solution::twoSum_Map(vector<int> &nums, const int target)
{
      vector<int> result;
      multimap<int, int> data;
      int size = nums.size();
      for (int i = 0; i < size; ++i)
      {
             data.insert(pair<int,int>(nums[i], i));
      }
      multimap<int, int>::iterator it =data.begin();
      multimap<int, int>::reverse_iteratorrit = data.rbegin();
      int items = 0;
      size = data.size();

      while (items++ < size)
      {
             int tempResult = (*it).first +(*rit).first;
             if (target == tempResult)
             {
                    int loc1, loc2;
                    loc1 = (*it).second + 1;
                    loc2 = (*rit).second + 1;
                    if (loc1 > loc2)
                    {
                           result.push_back(loc2);
                           result.push_back(loc1);
                    }
                    else
                    {
                           result.push_back(loc1);
                           result.push_back(loc2);
                    }
                    break;
             }
             else if (target < tempResult)
             {
                    ++rit;
             }
             else
             {
                    ++it;
             }
      }
      return result;
}

3.4 哈希实现方式

unordered_map: 该函数即哈希函数。该方法时间复杂度O(n)。

vector<int>Solution::twoSum1(vector<int> &nums, const int target)
{
      vector<int> result;
      unordered_map<int, int> data;
      int size = nums.size();
      for (int i = 0; i < size; ++i)
      {
             if (data.find(target - nums[i]) !=data.end())
             {
                    result.push_back(data[target- nums[i]] + 1);
                    result.push_back(i + 1);
                    break;
             }
           data[nums[i]] = i;
      }
      return result;
}

4. 效率

在LeetCode系统中,上述代码效率不同。另外需要注意的是虽然使用哈希时间复杂度较低,但是每次插入结点时需要申请空间,因此当n较小时哈希反而比先排序的时间复杂度为O(nlogn)的算法慢。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-28 13:05:39

两数之和等于目标值的相关文章

给定数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X

题目:给定数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X 思路一: 1,先采用归并排序对这个数组排序, 2,然后寻找相邻<k,i>的两数之和sum,找到恰好sum>x的位置,如果sum=x则返回true, 3,找到位置后,保持i不变,从k处向前遍历,直到找到A[k]+A[i]等于x,并返回TRUE,如果找不到,则返回false. 论证步骤3:当前找到的位置恰好A[k]+A[i]>x,且前一位置的sum<x: 所以A[i]前面的数(不包括A[i])无论取哪两个数都

两数之和等于x

算法导论第2.3-7的习题中要求给出一个运行时间为O(nlgn)的算法,这个算法的功能是能在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在两个其和等于x的元素. 方法一:都知道在一个有序的序列中使用二分查找的时间复杂度是O(lgn).首先排序,那么我们可以枚举集合S中的每一个元素,然后使用二分查找算法查找x-y(y是S中的一个元素),那么这个算法的时间复杂度是O(nlgn). 方法二:仍然是首先排序,然后我们用x减去S中的每一个元素,产生的数列存放于数组B,原来S中的n歌数存

给定一个数组,求两数之和等于某个值

public static void main(String[] args) { int[] intArr = {1, 3, 5, 8, 9, 12}; int sum = 10; int right = intArr.length - 1; for (int i=0; i < intArr.length; ) { if (right == i) { throw new IllegalArgumentException("未获取到有效取和值"); } if (sum == int

LeetCode刷题8——两数之和

一.要求 二.背景 数组: 数组是在程序设计中,为了处理方便,把具有相同类型的若干元素按有序的形式组织起来的一种形式.抽象地讲,数组即是有限个类型相同的元素的有序序列.若将此序列命名,那么这个名称即为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素.而用于区分数组的各个元素的数字编号则被称为下标,若为此定义一个变量,即为下标变量 三.思路 (1)挨个找两数之和等于目标值,并找对应两个数的索引,当两个数相等的时候 修改代码后运行成功 (2)进阶版:如果是三个数之和呢 原文地址:https

leetcode T1 两数之和详解

两数之和 题目描述 给定一个整数数组 nums?和一个目标值 target,请你在该数组中找出和为目标值的那?两个?整数,并返回他们的数组下标.你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 示例 给定 nums = [2, 7, 11, 15], target = 9,因为 nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1] 详细题解 暴力枚举 暴力法的思路很简单:遍历数组nums的每一个元素nums[i],在[i+1, ...,

leetcode_01两数之和

题目描述给定一个整型数组,要求返回两个数的下标,使得两数之和等于给定的目标值,要求同一个下标不能使用两次.数据保证有且仅有一组解. 样例 给定数组 nums = [2, 7, 11, 15],以及目标值 target = 9, 由于 nums[0] + nums[1] = 2 + 7 = 9, 所以 return [0, 1]. 思路一 暴力破解 代码 #include <iostream> using namespace std; class Solution { public: int*

167. Two Sum II - Input array is sorted两数之和

1. 原始题目 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值(index1 和 index2)不是从零开始的. 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素. 示例: 输入: numbers = [2, 7, 11, 15], target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 .因此 in

LeetCode | No.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, and you may not use the same element twice. 给定一个整数数组nums和一个目标值target,请你在该数

【算法C++】检测数组里是否有两个数之和等于某个数

问题: 检测数组里是否有两个数之和等于某个数 解决方法一:先将数组排序,然后从两头开始遍历 数组排序后,从左端开始取最小值,从右端取最大值, 判断两者之和与目标的大小: 1. 等于时,输出两个数: 2. 大于时,右端移到第2个数,继续判断: 3. 小于时,左端移到第2个数,继续判断. #include <iostream> #include <string> #include <algorithm> using namespace std; void fun1(int