赞
踩
数组中同一个元素不能使用两遍:比如[5, 5],因为他们的索引不同,所以可以5 + 5
因为我们每次要从数组中找两个数。因此一个很简单的思路是:
i
和j
,分别代表要找的两个数nums[i] + nums[j] == target
是否成立另外为了防止重复技术,我们需要在第一层循环中让i
从0开始,到n - 2
结束(确保能够取到下一个数作为j
;在第二层循环中让j
从i + 1
开始,到n - 1
结束)
C++
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { int i = 0, j = 0; for (i = 0; i + 1 < nums.size(); ++i) { int find = target - nums[i]; for (j = i + 1; j < nums.size(); ++j) { if(nums[j] == find){ return {i, j}; } } } return {}; } };
首先,任何优化的思路不外乎[减少重复]
从暴力中可以知道,逻辑上我们是先定下来一个数,然后从数组中往后找另一个值是否存在。但是其实我们在找第二个树的过程中重复扫描了数组多次。
举个例子,对于nums = [2,3,8,4], target = 9
,我们先确定下来第一个树是2
,然后从后扫描搭配最后一个数,检测是否有7
。发现没有,再决策第一个数为 3 的情况,这时候我们应该利用前一次扫描的结果来帮助我们快速判断是否存在 6,而不是再重新进行一次扫描。
这是直观的优化思路,不难想到可以使用哈希表进行存储。以数值为 key,数值的下标为 value。
C++
class Solution { public: vector<int> twoSum(vector<int>& nums, int t) { std::unordered_map<int, int> map; int n = nums.size(); for (int i = 0; i < n; ++i) { map[nums[i]] = i; } for (int i = 0; i < n; ++i) { int a = nums[i], b = t - a; if(map[a] == i){ map.erase(a); // 优化点(下一次遍历的时候可以加快速度; 而且这个key不能重复使用) } if(map.count(b)){ return {i, map[b]}; } } return {}; } };
golang
func twoSum(nums []int, target int) []int {
hashTable := map[int]int{}
for i, v := range nums {
if p, ok := hashTable[target - v]; ok{
return []int{p, i}
}
hashTable[v] = i;
}
return nil
}
方案对比
题目 | 核心思路 |
---|---|
leetcode:1. 两数之和—>无序数组中选出两个数,令其和= target,返回相应索引 Two Sum | 先固定一个数(枚举),然后找下一个数是否存在(哈希优化) |
leetcode:15. 三数之和–>无序数组中选出三个数,令其和= target,返回所有方案(去重) 3Sum | 先排序,然后定下第一个数(枚举),然后左右指针找另外两个数,如果找到了sum=target的数就去重然后继续找(二分优化) |
leetcode:18. 四数之和—>无序数组中选出四个数,令其和= target,返回所有方案(去重) 4Sum | 先排序,然后先固定第一个数(枚举剪枝),然后固定第二个数(枚举剪枝),最后右指针找另外两个数(去重) |
lintcode:89 · K数之和—>无序数组中选出k个数,令其和 == target,一共有多少方案 | 因为k不固定,所以写成指针会很难写,因此需要回溯或者动态规划(背包问题) |
leetcode:16. 三数之和—>无序数组中选出三个数,最接近target的sum是什么 3Sum Closest | 先排序,然后固定第一个数(枚举),然后左右指针找另外两个数组,如果找到了sum==target就直接返回,如果找不到就缩小窗口以逼近target(二分优化) |
leetcode:259. 三数之和–>无序数组中选出三个数,其和< target,返回所有的方案个数(不去重) 3Sum Smaller | 先排序,然后固定第一个数(枚举),然后双指针碰撞。将所有符合条件的[l,r]区间都算到结果里面。 |
leetcode:454. 四数之和—>从四个无序数组中各选出一个数,令其和为0,一共有多少种方法(不去重) | 先枚举两个数组中的元素之和,同时统计出现的次数(map);然后统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数 |
不同的结构中找是否存在满足要求(和为target)的两个数
题目 | 核心思路 |
---|---|
leetcode:1. 两数之和—>无序数组中选出两个数,令其和= target,返回相应索引 Two Sum | 先定义下一个数,然后找下一个数是否存在(哈希优化) |
leetcode:167. 两数之和—>有序数组中选出两个数,令其和= target,返回相应索引 Two Sum II - Input array is sorted | 双指针(一个指向0,一个指向num.size - 1),不断缩小滑动窗口 |
leetcode:170 两数之和—>接收数据流,数据流中能否选出两个数,令其和= target Two Sum III - Data structure design | 用map记录出现次数,然后遍历map,找有没有对应的target - val |
leetcode:653. 两数之和—>二叉搜索树中是否存在和= target的两个数 Two Sum IV - Input is a BST | 用set辅助,看当前节点是否满足要求(target - val),如果不满足,就去左右子树中查找 |
K数之和
题目 | 核心思路 |
---|---|
lintcode:89 · 无序(可重复)数组中选出k个数,令其和 == target,一共有多少种组合 | 因为k不固定,所以写成指针会很难写,因此需要回溯或者动态规划:从左到右尝试,[pos…)上还可以选k个数,还剩下rest空间 |
leetcode:39. 无序(不重复)数组中选出一些数,令其和=target,返回所有可能的组合(每个数可以使用无限次) | 因为不知道要选几个数,所以不可以指针或者迭代;因为需要返回方案而不是方案个数,所以用回溯—如果用递归的话会很麻烦,需要沿着二维表深搜 |
leetcode:113. 二叉树找到路径(从根到叶),令其和=target,返回所有可能的组合 | 先判断当前节点是否满足,然后去左右子树找,找完之后,返回上一个结点时,需要把该结点从path 中移除 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。