Problem
Given an array of integers, find two numbers such that they add up to aspecific target number. The function twoSum should return indices of the two numbers such thatthey add up to the target, where index1 must be less than index2. Please notethat your returned answers (both index1 and index2) are NOT zero-based. Example
numbers=[, , , ], target= return [, ] Note
You may assume that each input would have exactly one solution Challenge
Either of the following solutions are acceptable: O(n) Space, O(nlogn) Time
O(n) Space, O(n) Time

题解1 - 哈希表

找两数之和是否为target, 如果是找数组中一个值为target该多好啊!遍历一次就知道了,我只想说,too naive... 难道要将数组中所有元素的两两组合都求出来与target比较吗?时间复杂度显然为 O(n2), 显然不符题目要求。找一个数时直接遍历即可,那么可不可以将两个数之和转换为找一个数呢?我们先来看看两数之和为target所对应的判断条件—— xi+xj=target, 可进一步转化为 xi=target−xj, 其中 i 和 j 为数组中的下标。一段神奇的数学推理就将找两数之和转化为了找一个数是否在数组中了!可见数学是多么的重要...

基本思路有了,现在就来看看怎么实现,显然我们需要额外的空间(也就是哈希表)来保存已经处理过的 xj(注意这里并不能先初始化哈希表,否则无法排除两个相同的元素相加为 target 的情况), 如果不满足等式条件,那么我们就往后遍历,并把之前的元素加入到哈希表中,如果target减去当前索引后的值在哈希表中找到了,那么就将哈希表中相应的索引返回,大功告成!

C++:

class Solution {
public:
/*
* @param numbers : An array of Integer
* @param target : target = numbers[index1] + numbers[index2]
* @return : [index1+1, index2+1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &nums, int target) {
vector<int> result;
const int length = nums.size();
if ( == length) {
return result;
} // first value, second index
unordered_map<int, int> hash(length);
for (int i = ; i != length; ++i) {
if (hash.find(target - nums[i]) != hash.end()) {
result.push_back(hash[target - nums[i]]);
result.push_back(i + );
return result;
} else {
hash[nums[i]] = i + ;
}
} return result;
}
};

JAVA:

public class Solution {
/*
* @param numbers : An array of Integer
* @param target : target = numbers[index1] + numbers[index2]
* @return : [index1 + 1, index2 + 1] (index1 < index2)
*/
public int[] twoSum(int[] numbers, int target) {
if (numbers == null || numbers.length == 0) return new int[]{0, 0}; Map<Integer, Integer> hashmap = new HashMap<Integer, Integer>();
int index1 = 0, index2 = 0;
for (int i = 0; i < numbers.length; i++) {
if (hashmap.containsKey(target - numbers[i])) {
index1 = hashmap.get(target - numbers[i]);
index2 = i;
return new int[]{1 + index1, 1 + index2};
} else {
hashmap.put(numbers[i], i);
}
} return new int[]{0, 0};
}
}

源码分析

  1. 异常处理。
  2. 使用 C++ 11 中的哈希表实现unordered_map映射值和索引。Python 中的dict就是天然的哈希表。
  3. 找到满足条件的解就返回,找不到就加入哈希表中。注意题中要求返回索引值的含义。

复杂度分析

哈希表用了和数组等长的空间,空间复杂度为 O(n), 遍历一次数组,时间复杂度为 O(n).

题解2 - 排序后使用两根指针

但凡可以用空间换时间的做法,往往也可以使用时间换空间。另外一个容易想到的思路就是先对数组排序,然后使用两根指针分别指向首尾元素,逐步向中间靠拢,直至找到满足条件的索引为止。

C++:

class Solution {
public:
/*
* @param numbers : An array of Integer
* @param target : target = numbers[index1] + numbers[index2]
* @return : [index1+1, index2+1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &nums, int target) {
vector<int> result;
const int length = nums.size();
if ( == length) {
return result;
} // first num, second is index
vector<pair<int, int> > num_index(length);
// map num value and index
for (int i = ; i != length; ++i) {
num_index[i].first = nums[i];
num_index[i].second = i + ;
} sort(num_index.begin(), num_index.end());
int start = , end = length - ;
while (start < end) {
if (num_index[start].first + num_index[end].first > target) {
--end;
} else if(num_index[start].first + num_index[end].first == target) {
int min_index = min(num_index[start].second, num_index[end].second);
int max_index = max(num_index[start].second, num_index[end].second);
result.push_back(min_index);
result.push_back(max_index);
return result;
} else {
++start;
}
} return result;
}
};

源码分析

  1. 异常处理。
  2. 使用length保存数组的长度,避免反复调用nums.size()造成性能损失。
  3. 使用pair组合排序前的值和索引,避免排序后找不到原有索引信息。
  4. 使用标准库函数排序。
  5. 两根指针指头尾,逐步靠拢。

复杂度分析

遍历一次原数组得到pair类型的新数组,时间复杂度为 O(n), 空间复杂度也为 O(n). 标准库中的排序方法时间复杂度近似为 O(nlogn), 两根指针遍历数组时间复杂度为 O(n).

2 Sum的更多相关文章

  1. LeetCode - Two Sum

    Two Sum 題目連結 官網題目說明: 解法: 從給定的一組值內找出第一組兩數相加剛好等於給定的目標值,暴力解很簡單(只會這樣= =),兩個迴圈,只要找到相加的值就跳出. /// <summa ...

  2. Leetcode 笔记 113 - Path Sum II

    题目链接:Path Sum II | LeetCode OJ Given a binary tree and a sum, find all root-to-leaf paths where each ...

  3. Leetcode 笔记 112 - Path Sum

    题目链接:Path Sum | LeetCode OJ Given a binary tree and a sum, determine if the tree has a root-to-leaf ...

  4. POJ 2739. Sum of Consecutive Prime Numbers

    Sum of Consecutive Prime Numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20050 ...

  5. BZOJ 3944 Sum

    题目链接:Sum 嗯--不要在意--我发这篇博客只是为了保存一下杜教筛的板子的-- 你说你不会杜教筛?有一篇博客写的很好,看完应该就会了-- 这道题就是杜教筛板子题,也没什么好讲的-- 下面贴代码(不 ...

  6. [LeetCode] Path Sum III 二叉树的路径和之三

    You are given a binary tree in which each node contains an integer value. Find the number of paths t ...

  7. [LeetCode] Partition Equal Subset Sum 相同子集和分割

    Given a non-empty array containing only positive integers, find if the array can be partitioned into ...

  8. [LeetCode] Split Array Largest Sum 分割数组的最大值

    Given an array which consists of non-negative integers and an integer m, you can split the array int ...

  9. [LeetCode] Sum of Left Leaves 左子叶之和

    Find the sum of all left leaves in a given binary tree. Example: 3 / \ 9 20 / \ 15 7 There are two l ...

  10. [LeetCode] Combination Sum IV 组合之和之四

    Given an integer array with all positive numbers and no duplicates, find the number of possible comb ...

随机推荐

  1. linux 内核移植和根文件系统的制作

    1.1 Linux内核基础知识 在动手进行Linux内核移植之前,非常有必要对Linux内核进行一定的了解,下面从Linux内核的版本和分类说起. 1.1.1  Linux版本 Linux内核的版本号 ...

  2. setjmp和longjmp

    此文是学习 C专家编程 中的笔记. setjmp和longjmp是C语言所独有的,它们部分弥补了C语言有限的转移能力. 函数说明(来自wiki百科): int setjmp(jmp_buf env) ...

  3. JOptionPane如何自定义按钮绑定事件

    JOptionPane如何自定义按钮绑定事件 2018年01月29日 19:27:10 阅读数:475 摘自:https://blog.csdn.net/m0_37355951/article/det ...

  4. Spark的广播变量模块

    有人问我,如果让我设计广播变量该怎么设计,我想了想说,为啥不用zookeeper呢? 对啊,为啥不用zookeeper,也许spark的最初设计哲学就是尽量不使用别的组件,他有自己分布式内存文件系统, ...

  5. 巧用 git rebase 将某一部分 commit 复制到另一个分支

    一.为什么需要将一个 commit 复制到其他分支上去呢? 在我们的实际开发的过程中,我们的项目中会存在多个分支. 在某些情况下,可能需要将某一个分支上的 commit 复制到另一个分支上去.   二 ...

  6. [转]ORA-12516, TNS:listener could not find available handler with matching protocol stack

    转至:http://blog.csdn.net/MichaelSrc/article/details/6760247 1.查看当前连接进程数 SQL>select count(*) from v ...

  7. Docker 三架马车

    1. Docker Compose 我们前面的课程讲到过两个容器之间通过名字进行互联互通的话可以通过link参数来关联,这种做法比较麻烦,更好的方式是使用Docker Compose来定义一个 YAM ...

  8. 动态变更Repeater控件HeaderTemplate列名

    本博文,Insus.NET教你动态实现变更Repeater控件HeaderTemplate列名.一般情况之下,是不需要动态变更,只有动态有Repeater控件不变情况之下,来显示多种数据源进行绑定.这 ...

  9. 简单介绍Jenkins&持续集成

    1.定义 持续集成(Continuous integration),简称CI. 随着软件项目复杂度的增加,就会对集成和确保软件组件能够在一起工作提出了更多的要求-要早集成.常集成. CI不是一项软件开 ...

  10. linode出现以下报错

    Linode Manager 报错 系统重新安装后 解决办法执行  rm -rf ~/.ssh/known_hosts 再继续执行:ssh root@72.14.189.163