LeetCode 遍历技巧 | 15. 3Sum

/*
 * Leetcode15. 3Sum
 * Funtion: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
 * Example:
    Input: given array S = [-1, 0, 1, 2, -1, -4],
    Output: [
              [-1, 0, 1],
              [-1, -1, 2]
            ]
            注意:当输入为[0,0,0]时,输出为[[0,0,0]]
    Input:[1,1,-2]Expected:[[-2,1,1]]
    Input:[3,0,-2,-1,1,2]Expected:[[-2,-1,3],[-2,0,2],[-1,0,1]]
    Input:[-4,-2,1,-5,-4,-4,4,-2,0,4,0,-2,3,1,-5,0]Expected:[[-5,1,4],[-4,0,4],[-4,1,3],[-2,-2,4],[-2,1,1],[0,0,0]]
    Input:113个数[8,5,12,3,-2,-13,-8,-9,-8,10,-10,-10,-14,-5,-1,-8,-7,-12,4,4,10,-8,0,-3,4,11,-9,-2,-7,-2,3,-14,-12,1,-4,-6,3,3,0,2,-9,-2,7,-8,0,14,-1,8,-13,10,-11,4,-13,-4,-14,-1,-8,-7,12,-8,6,0,-15,2,8,-4,11,-4,-15,-12,5,-9,1,-2,-10,-14,-11,4,1,13,-1,-3,3,-7,9,-4,7,8,4,4,8,-12,12,8,5,5,12,-7,9,4,-12,-1,2,5,4,7,-2,8,-12,-15,-1,2,-11]
    Output:117个解
 * Author: LKJ
 * Date:2016/7/29
 * Hint:遍历所有组合一一比较会超时,遍历其中一个元素,另外两个二分查找左右逼近
*/
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>

using namespace std;


/*
//单纯遍历,当数组大的时候会超时
class Solution {
public:
    vector< vector<int> > threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int len = nums.size();
        vector<int> preAns;
        vector< vector<int> > ans;
        for(int i = 0; i < len-2; i++){
            for(int j = i+1; j < len-1; j++){
                for(int k = j+1; k < len; k++){
                    if((nums[i] + nums[j] + nums[k]) == 0){
                        if(nums[k] < 0) break;
                        preAns.clear();
                        preAns.push_back(nums[i]);
                        preAns.push_back(nums[j]);
                        preAns.push_back(nums[k]);
                        //避免重复
                        int flag = 0;
                        for(int m = 0; m < ans.size(); m++){
                            if(ans[m] == preAns){
                                flag = 1;
                                break;
                            }
                        }
                        if(flag == 0){
                            ans.push_back(preAns);
                        }
                    }
                }
            }
            if(nums[i] > 0)  break;
        }
        return ans;
    }
};*/


//输入113个数,耗时0.428s,仍然超时,在此基础上修改,需要减枝,跳过重复元素,剪掉了大部分循环,终于AC了
class Solution {
public:
    vector< vector<int> > threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int len = nums.size();
        int zeronum = 0;
        vector<int> preAns;
        vector< vector<int> > ans;

        for(int i = 0; i < len-1; i++){
            if(nums[i] == 0){
                zeronum = i;
                break;
            }
            if((nums[i-1] < 0) && nums[i+1] > 0){
                zeronum = i;
                break;
            }
        }
        for(int i = 0; i <= zeronum; i++){
            if(i > 0 && nums[i] == nums[i - 1]) continue; // 跳过重复元素
            for(int j = len-1; j >= zeronum; j--){//i,j相等的情况不会出现,因为k总是介于他们之间
                if(j < len-1 && nums[j] == nums[j + 1]) continue; // 跳过重复元素
                for(int k = i+1; k < j; k++){
                    if(k > i+1 && nums[k] == nums[k - 1]) continue; // 跳过重复元素
                    if((nums[i] + nums[j] + nums[k]) == 0){
                        preAns.clear();
                        preAns.push_back(nums[i]);
                        preAns.push_back(nums[k]);
                        preAns.push_back(nums[j]);

                        ans.push_back(preAns);
                    }
                }
            }
        }
        return ans;
    }
};

int main(){
    int myarr[113] = {8,5,12,3,-2,-13,-8,-9,-8,10,-10,-10,-14,-5,-1,-8,-7,-12,4,4,10,-8,0,-3,4,11,-9,-2,-7,-2,3,-14,-12,1,-4,-6,3,3,0,2,-9,-2,7,-8,0,14,-1,8,-13,10,-11,4,-13,-4,-14,-1,-8,-7,12,-8,6,0,-15,2,8,-4,11,-4,-15,-12,5,-9,1,-2,-10,-14,-11,4,1,13,-1,-3,3,-7,9,-4,7,8,4,4,8,-12,12,8,5,5,12,-7,9,4,-12,-1,2,5,4,7,-2,8,-12,-15,-1,2,-11};
    vector<int> myin(myarr,myarr+113);

    vector< vector<int> > myout;
    Solution SA;

    myout = SA.threeSum(myin);


    cout<<"VecOUT:"<<myout.size()<<endl;
    for(unsigned int i = 0; i < myout.size(); i++){
        for(vector<int>::iterator itt = myout[i].begin() ;itt!=myout[i].end();itt++){
            cout<<*itt<<"     ";
        }
        cout<<endl;
    }
    cout<<endl;

    cout<<endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值