在数组中找几个数的和等于某个数[LeetCode]
首先明确一点,这个方面的问题设计到的知识点是数组的查找的问题。对于类似的这样的查找操作的具体办法就是三种解决方法:
1.暴力算法,多个for循环,很高的时间复杂度
2.先排序,然后左右夹逼,但是这样会破坏原始数组的下表
3.利用Hash表,直接定位元素,很少的时间复杂度
TwoSum
先来看看最简单的,在一个数组中找两个数的和等于某个数。
这个题目最简简单的方法就是暴力法,所需的时间复杂度是O(n2),但是这是不允许的,所以一个O(n)的方法就是利用Hash表存储数据,这样能够把查找的时间降低下来。使用到的工具就是unordered_map。在这个hash表中,key是数组的数字本身,value是数组数字的下标值。这样只需要把原数组扫描一遍,对于每一个数组中的值,求target与数组元素的差值,然后把这个差值作为key到hash表中找对应的value。
但是注意这样的值:
3 2 4 target=6
这样会产生三组值满足:(3,3)(2,4)(4,2)所以要规定一下:第二个通过hash得到的下标值一定要比第一个下标值大才可以。
vector<int> twoSum(vector<int>& nums, int target)
{
unordered_map<int, int> mapping;
vector<int> result; for(int i = 0; i < nums.size(); i++)
{
mapping[nums[i]] = i;
} for(int i = 0; i < nums.size(); i++)
{
const int gap = target - nums[i]; if(mapping.find(gap) != mapping.end() && mapping[gap] > i)
{
result.push_back(i + 1);
result.push_back(mapping[gap] + 1);
}
} return result;
}
find函数,在找到的时候会返回一个指向该元素的iterator,如果没有找到会返回一个end。如果找到了,可以通过operator[]来访问这个元素。
对于2-sum的算法,暴力算法的时间复杂度是O(n2),Hash表的时间复杂度是O(n),排序然后两边夹逼的时间复杂度是排序的时间复杂度加上左右夹逼的时间复杂度:O(NlogN)+O(N)=O(NlogN)。
ThreeSum
对于三个数的和问题,暴力的算法就是使用三个for循环,这样的话时间复杂度是O(n3),所以一个好的改进就是先对原始的数组排序,然后使用两边夹逼的方法。但是要注意一些细节的问题:
1.具体的实现方法是,先固定一个,然后就成了2Sums的两边夹逼方法。
2.原始的数组是允许重复的,但是得到的solution是不允许重复的,所以要做一些合理的去重处理。防止-1,-1,-1,2,2这样的数组会得到-1,-1,2和-1,-1,2两组一样的结果。
vector<vector<int> > threeSum(vector<int>& nums, int target)
{
vector<vector<int> > result; if(nums.size() < 3)
return result; for(int i = 0; i < nums.size() - 2; i++)
{
int j = i + 1;
int k = nums.size() - 1; if(i > 0 && nums[i] == nums[i-1])
continue; while(j < k)
{
int sum = nums[i] + nums[j] + nums[k];
if(sum < target)
{
j++;
}
else if(sum > target)
{
k--;
}
else
{
vector<int> temp;
temp.push_back(nums[i]);
temp.push_back(nums[j]);
temp.push_back(nums[k]); result.push_back(temp);
j++;
k--; //去重,防止最后的结果有重复的三元组
while(nums[j] == nums[j-1] && nums[k] == nums[k+1] && j < k)
{
j++;
}
}
}//while
}//for return result;
}
算法的时间复杂度是O(NlogN)+O(N2),所以总的时间复杂度是O(N2)。
ThreeSumClosest
再看一个很类似的题目:找最接近给定值的那三个数,并输出这三个数的和。
用的方法仍然是先排序,然后利用两边夹逼的方法。
int threeSumClosest(vector<int>& nums, int target)
{
int min_gap = 65535;
int result; sort(nums.begin(), nums.end()); for(int i = 0; i < nums.size() - 2; i++)
{
int k = nums.size() - 1;
int j = i + 1; while(j < k)
{
int sum = nums[i] + nums[j] + nums[k];
int gap = abs(sum - target); if(gap < min_gap)
{
result = sum;
min_gap = gap;
} if(sum < target)
{
j++;
}
else
{
k--;
} }//while
}//for return result;
}
FourSum
这个问题还是延续前面的那种方法,先排序,然后利用左右夹逼。这样的话排序的时间复杂度是O(NlogN),左右夹逼的时间复杂度是O(N3),所以总的时间复杂度是O(N3)。但是这个FourSum比其他的难点在于:要仔细的对待去重的问题,不然会得到很多重复一样的答案。
vector<vector<int> > fourSum(vector<int>& nums, int target)
{ vector<vector<int> > result;
if(nums.size() < 4)
return result; sort(nums.begin(), nums.end()); for(int i = 0; i < nums.size() - 3; i++)
{
if(i > 0 && nums[i] == nums[i-1])
continue; for(int j = i + 1; j < nums.size() - 2; j++)
{
if(j > 1 && nums[j] == nums[j - 1])
continue; int l = j + 1;
int k = nums.size() - 1; while(l < k)
{
int sum = nums[i] + nums[j] + nums[l] + nums[k];
if(sum < target)
{
l++;
}
else if(sum > target)
{
k--;
}
else
{
vector<int> tmp;
tmp.push_back(nums[i]);
tmp.push_back(nums[j]);
tmp.push_back(nums[l]);
tmp.push_back(nums[k]); result.push_back(tmp);
l++;
k--; while(nums[l]==nums[l-1]&&nums[k]==nums[k+1]&&l<k)
l++;
}
}//while }//for
}//for
}
对于4-sum的算法其实可以用hash表做一个优化,就是先用hash表存元数组中的任意两个元素的和,然后在对这个新的hash使用2-sum的线性查询,所以总的时间复杂度是O(N2)。具体的算法分析这里分享一个连接:
烟客旅人:http://tech-wonderland.net/blog/summary-of-ksum-problems.html
在数组中找几个数的和等于某个数[LeetCode]的更多相关文章
- 3sum(从数组中找出三个数的和为0)
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...
- 用C#写一个函数,在一个数组中找出随意几个值相加等于一个值 与迭代器对比
算法!用C#写一个函数,在一个数组中找出随意几个值相加等于一个值比如,数组{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20} 要找出那些数相加等 ...
- Leetcode33--->Search in Rotated Sorted Array(在旋转数组中找出给定的target值的位置)
题目: 给定一个旋转数组,但是你不知道旋转位置,在旋转数组中找出给定target值出现的位置:你可以假设在数组中没有重复值出现 举例: (i.e., 0 1 2 4 5 6 7 might becom ...
- 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数
今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...
- C语言 选择排序算法原理和实现 从数组中 找出最小的元素然后交换位置
#include <stdio.h> int main(void) { /* 选择排序算法 原理:从数组中 找出最小的元素然后交换位置: */ int a[10] = {9,5,10,7, ...
- 从数组中找出所有组合为s的数
java版本 package numCombine; /** * 从数组中找出所有组合为s的数 * @author root * */ public class NumComberAll { publ ...
- C语言:对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中。-在数组中找出最小值,并与第一个元素交换位置。
//对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中. #include <stdio.h& ...
- 数组中找出最小的K个数
题目 给出一个数组,找出K个最小的值 例如给出数组{5,2,4,3,1},给定K值3,则输出结果为{2,3,1} 程序 先给出第一个版本的程序 public static void printKNum ...
- 如何求出数组中最小(或者最大)的k个数(least k问题)
输入n个整数,如何求出其中最小的k个数? 解法1. 当然最直观的思路是将数组排序,然后就可以找出其中最小的k个数了,时间复杂度以快速排序为例,是O(nlogn): 解法2. 借助划分(Partitio ...
随机推荐
- BZOJ 1179 [Apio2009]Atm(强连通分量)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1179 [题目大意] 给出一张有向带环点权图,给出一些终点,在路径中同一个点的点权只能累 ...
- uva 10003 Cutting Sticks (区间dp)
本文出自 http://blog.csdn.net/shuangde800 题目链接: 打开 题目大意 一根长为l的木棍,上面有n个"切点",每个点的位置为c[i] 要按照一 ...
- saiku中过滤窗口优化及隐藏异常报错
问题一:当取消自动查询后,点击该维度应弹出过滤条件窗口,实际无反应,只有执行一次查询后再点击该维度,才能弹出过滤条件窗口 解决办法:打开WorkspaceDropZone.js文件,找到selecti ...
- ubuntu FTP服务安装
//安装vsftp apt-get install vsftpd -y //增加账号 //1 查找 nologin位置 /usr/sbin/nologin useradd -d /alidata/ww ...
- SQL Server存储过程和游标有关实例以及相关网址
内含游标的存储过程实例 第一种写法 GO BEGIN IF (object_id('PT_FAULT_REPORT', 'P') is not null) drop proc PT_FAULT_REP ...
- CloseHandle(),TerminateThread(),ExitThread()的区别
线程的handle用处:线程的handle是指向“线程的内核对象”的,而不是指向线程本身.每个内核对象只是内核分配的一个内存块,并且只能由内核访问.该内存块是一种数据结构,它的成员负责维护对象的各种信 ...
- cocos2d-X-3.X 场景与层
1场景与层的相关函数 1. void runWithScene(Scene * scene). 该函数可以运行场景.只能在启动第一个场景时调用该函数.如果已经有一个场景运行,则不能调用该函数. 2. ...
- Spark源码学习2
转自:http://www.cnblogs.com/hseagle/p/3673123.html 在源码阅读时,需要重点把握以下两大主线. 静态view 即 RDD, transformation a ...
- Spring——AOP(面向切面编程)@AspectJ注解方式
一.什么是AOP? AOP: (Aspect Oriented Programming)即面向切面编程. 试想这样的场景:项目中需要在业务方法执行完打印日志记录.最笨的办法就是在每个方法核心业务执行完 ...
- UVALive 6709 - Mosaic 二维线段树
题目链接 给一个n*n的方格, 每个方格有值. 每次询问, 给出三个数x, y, l, 求出以x, y为中心的边长为l的正方形内的最大值与最小值, 输出(maxx+minn)/2, 并将x, y这个格 ...