首先明确一点,这个方面的问题设计到的知识点是数组的查找的问题。对于类似的这样的查找操作的具体办法就是三种解决方法:
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 twoSum(vector& nums, int target)
{
unordered_map mapping;
vector 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 > threeSum(vector& nums, int target)
{
vector > 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 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& 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 > fourSum(vector& nums, int target)
{
vector > 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 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
l++;
}
}//while
}//for
}//for
}
对于4-sum的算法其实可以用hash表做一个优化,就是先用hash表存元数组中的任意两个元素的和,然后在对这个新的hash使用2-sum的线性查询,所以总的时间复杂度是O(N2)。具体的算法分析这里分享一个连接:
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 int main(void) { /* 选择排序算法 原理:从数组中 找出最小的元素然后交换位置: */ int a[10] = {9,5,10,7, ...
从数组中找出所有组合为s的数
java版本 package numCombine; /** * 从数组中找出所有组合为s的数 * @author root * */ public class NumComberAll { publ ...
数组中找出最小的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 ...
随机推荐
angular2系列教程(五)Structural directives、再谈组件生命周期
今天,我们要讲的是structural directives和组件生命周期这两个知识点.structural directives顾名思义就是改变dom结构的指令.著名的内建结构指令有 ngIf, n ...
iOS 创建模型时自动生成属性
转载 mark666(简书作者), 链接:http://www.jianshu.com/p/63ee533a7705 我们在创建模型的时候,常常要写一大堆恶心的@property(nonatomic, ...
Linux Kernel代码艺术——系统调用宏定义
我们习惯在SI(Source Insight)中阅读Linux内核,SI会建立符号表数据库,能非常方便地跳转到变量.宏.函数等的定义处.但在处理系统调用的函数时,却会遇到一些麻烦:我们知道系统调用函数 ...
[转]Theano下用CNN(卷积神经网络)做车牌中文字符OCR