2sum问题,给定一个数组,一个确定的数target,在该数组中寻找两个数使得其和等于target,并返回这两个数在数组中的索引。(题目假设只有一个解的情况下实际上多个解也是可以完成的,只需要开一个装vector<int>的vector,然后把每次符合条件的vectorpush进去就好了)
两个for循环,搞定,代码如下(C++):
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for(int i=0;i<nums.size();i++)
{
for(int j=i+1;j<nums.size();j++)
{
if(nums[i]+nums[j]==target){
return vector<int>{i,j};
}
}
}
}
};
这是我脑子里最先想到的想法,后来看别人写的博客,发现还有其他的优化方法。我找的这个博主的想法是:先把给定的数组排序(排序之前先把这个数组复制一份,便于最后根据数据找索引),设定两个指针,一个指向头部,一个指向尾部,然后利用局部逼近的原则,如果求和比target大,则尾部指针往前跳,=target,跳出循环,<target,头部指针往后跳。JS代码如下:
var twoSum = function(nums, target) {
var temp = nums.slice(0); //上述的复制数组的作用
nums = nums.sort(function(a,b){return a-b;});
var i = 0;
var j = nums.length - 1;
while(nums[i] + nums[j] != target){
if(nums[i] + nums[j] > target){
j--;
}else{
i++;
}
}
i = temp.indexOf(nums[i]);
j = temp.lastIndexOf(nums[j]);
var index = new Array(i, j);
index = index.sort(function(a,b){return a-b;});
return index;
};
3sum问题:给定一个数组,找出三个数a,b,c使得a+b+c=0,返回所有的满足情况的a,b,c的组合,不能重复。
暴力不可取,不能利用三个for来解决问题吧,而且这样做还是不能避免重复的问题。
思路:(这个时候就可以随便排序了,我们需要的是数而跟数的索引无关)首先排序,然后用一个for循环遍历,遍历到的数据记为第i个,用两个指针分别指向i+1和length-1,与2sum相同,三数求和之后与0作比较,在pleft<pright的情况下根据与target的比较依次移动指针,满足条件则push进容器里面。实际还是转换了一下转化为2sum问题,先固定一个数,也就是所说的i,再一次移动两个指针,也就是2sum问题。代码如下(JAVA):
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
//处理不满足题意的情况
if(nums == null || nums.length<3)
return result;
//排序
Arrays.sort(nums);
//实现遍历,固定一个数i
for(int i=0; i<nums.length-2; i++){
if(i==0 || nums[i] > nums[i-1]){
int j=i+1;//pleft指针
int k=nums.length-1;//pright指针
while(j<k){
//如果满足条件,则添加进去
if(nums[i]+nums[j]+nums[k]==0){
List<Integer> l = new ArrayList<Integer>();
l.add(nums[i]);
l.add(nums[j]);
l.add(nums[k]);
result.add(l);
//此时需要同时移动两个指针
j++;
k--;
//消除重复
while(j<k && nums[j]==nums[j-1])
j++;
while(j<k && nums[k]==nums[k+1])
k--;
}
//处理小于的情况,移动pleft
else if(nums[i]+nums[j]+nums[k]<0){
j++;
}
//处理大于的情况,移动pright指针
else{
k--;
}
}
}
}
return result;
}
}
4sum问题:给定一个数组,在该数组中找到a,b,c,d四个数,使得a+b+c+d=target,返回所有的这四个数的组合,不允许重复。同3sum,转换为2sum一样,也要逐一实现把4sum转换为3sum再转换为3sum来解决这个问题。首先老规矩,排序,然后在设定两个指针,固定两个数,然后再设定两个指针,移动指针来找到4个满足条件的数,其间涉及到去重问题。代码如下(JAVA):
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> lists=new ArrayList<List<Integer>>();
//处理不满足题目条件时候的情况
if (nums.length<4){
return lists;
}
//进行数组排序
Arrays.sort(nums);
for (int i=0;i<nums.length-3;i++){
if(i>0&&nums[i]==nums[i-1]){
continue;
}
//固定两个数i和j,用两个移动的数start和end来遍历数组(i为主要固定者,j为次要固定者)
for (int j=i+1;j<nums.length-2;j++){
int start = j+1;
int end = nums.length-1;
while (start<end){
int sum = nums[i]+nums[j]+nums[start]+nums[end];
if (sum==target){
List<Integer> newlist= Arrays.asList(nums[i], nums[j], nums[start], nums[end]);
if (!lists.contains(newlist)){
lists.add(newlist);
}
start++;
end--;
}
else if(sum<target){
start++;
}
else
{
end--;
}
}
}
}
return lists;
}
}
简单总结了一下,便于以后快速回顾