在数组中找几个数的和等于某个数[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 ...
随机推荐
- Servlet的运行方式
通常我们运行servlet需要在web.xml配置文件中,注册我们写好的servlet以及其对应的访问路径. 在学习web开发中,有一种不需要配置便可以直接对servlet进行配置的方式,在web.x ...
- openstack 的 policy 问题。
想写nova的policy的实现, 但是发现网上,有人写的很不错了. ref: http://blog.csdn.net/hackerain/article/details/8241691 但是,po ...
- 【转】Ubuntu Linux 下文件名乱码(无效的编码)的快速解决办法
原博文地址:http://www.cnblogs.com/york-hust/archive/2012/07/07/2580388.html 文件是在WIndows 下创建的,Windows 的文件名 ...
- Saiku图表导出时中文显示问题的解决方法
Saiku图表导出时png,jpg,pdf三种格式的中文显示都有问题,目前找到一种不太完善的解决方法(中文可以显示但不清晰),需要修改Saiku项目下的ExporterResource.java文件, ...
- NPOI 辅助类
using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; using S ...
- 微信小程序环境搭建
第一步 IDE下载 Win版链接: https://pan.baidu.com/s/1gfAy18n 第二步 破解 最新下载链接: https://pan.baidu.com/s/1gfAy18n ...
- gridview中使用href调用javascript
传递参数(多个)可用以下两种方法: 方法一: <asp:TemplateField HeaderText="列名1"> <ItemTemplate> < ...
- android入门——UI(1)
一.使用TextView ImageView Button EditView做出登录页面 <?xml version="1.0" encoding="utf-8&q ...
- Oracle中如何判断字符串是否全为数字,以及从任意字符串中提取数字
本文介绍了判断字符串是否全为数字的4种办法,另外还介绍了一个translate函数的小技巧,从任意字符串中提取数字(调用2次translate函数).这个办法是一个公司同事发现的,用起来很方便,但理解 ...
- vs2013 中HTML页 无法在设计窗口中查看的解决
VS2013不支持HTML文件的解决办法: 1.将html文件重命名为aspx即可.不需要创建项目,直接拖进vs即可. 2.打开VS菜单->工具->选项->文本编辑器->文件扩 ...