【LeetCode & 剑指offer刷题】数组题3:3Sum(系列) + 4sum

【LeetCode & 剑指offer刷题】数组题3:3Sum(系列) + 4sum

【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

3Sum

Given an array   nums   of   n   integers, are there elements   a ,   b ,   c   in   nums   such that   a   +   b   +   c   = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
 
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

C++
 
//问题:找数组中和为0的三元组
//方法:排序后,扫描数组,转化为2sum问题
//2sum对应一个循环,3sum对应两重循环,4sum对应三重循环
//O(n^2)
#include <algorithm>
class Solution
{
public :
    vector < vector < int >> threeSum ( vector < int >& a )
    {
        vector < vector < int >> res ;
        int n = a . size ();
        if ( n < 3 ) return res ;
       
        sort (a.begin(), a.end()); //排序
 
        //扫描a[i],后面在用leftright首尾两指针扫描
        for ( int i = 0 ; i < n && a [ i ]<= 0 ; i ++) //第一个数只能是负数或0,加此判断以节省时间,如果不加次判断,则i<n-2即可
        {
            int target = - a [ i ]; //将第一个数的相反数定为2sum的target 
            int left = i+1//i=0~n-3
            int right = n-1;
 
            while ( left < right ) //用两个指针分别从a[i+1]和整个数组末尾开始向中间扫描 ,找到所有可以满足和为-a[i]的数对
            {
                int sum = a [ left ] + a [ right ];
                if ( sum < target ) left ++; //仅移动前面指针
                else if ( sum > target ) right --; //仅移动后面指针
                else //满足3sum要求
                {
                    res . push_back ( { a [ i ], a [ left ], a [ right ]});   //将满足的三元组push到结果向量中(也可以用vector<int>{a[i], a[left], a[right]})
 
                    while ( left < right && a [ left + 1 ] == a [ left ]) left ++; //以免第二个数重复
                    while ( left < right && a [ right - 1 ] == a [ right ]) right --; //以免第三个数重复
                    left ++; // 前后指针都移动,下一次判断
                    right --;
                }
            }
            while ( i + 1 < n && a [ i + 1 ] == a [ i ]) i ++; //以免第一个数重复
        }
       
        return res ;
    }
};
/*注:
也可用set避免重复
set<vector<int>> res;
...
vector<vector< int >> (res.begin(), res.end());//用迭代器将set转为vector
*/
 
16 .   3Sum Closest
Given an array   nums   of   n   integers and an integer   target , find three integers in   nums  such that the sum is closest to  target . Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
Given array nums = [-1, 2, 1, -4], and target = 1.
 
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

 
/*
问题:离目标值最近的三数之和
方法:排序后,扫描 a[i], 后面在用 left right 首尾两指针扫描
*/
class Solution
{
public :
    int threeSumClosest ( vector < int >& nums , int target )
    {
        if ( nums . size ()< 3 ) return 0 ;
       
        int closest = nums [ 0 ] + nums [ 1 ] + nums [ 2 ];
        int diff = abs ( closest - target );
        sort (nums.begin(), nums.end()); //排序
       
        //扫描a[i],后面在用leftright首尾两指针扫描
        for ( int i = 0 ; i < nums . size () - 2 ; i ++)   //i=0~n-3(n-2,n-1 分别为 left right 占着 )
        {
            int left = i + 1 , right = nums . size () - 1 ; // left = i+1, right=n-1
           
            while ( left < right )
            {
                int sum = nums [ i ] + nums [ left ] + nums [ right ];
                int newDiff = abs ( sum - target );
                if ( newDiff <  diff ) // 更新 diff sum
                {
                    diff = newDiff ;
                    closest = sum ;
                }
               
                if ( sum < target ) left ++; // 调节指针
                else right --;
            }
        }
        return closest ;
    }
};
 
18. 4Sum
Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
The solution set must not contain duplicate quadruplets.
Example:
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
 
A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

Seen this question in a real interview before?   Yes No
 
 
/*
问题:找与目标值相等的 4 个数
三重循环即可
set 可避免重复结果
*/
class Solution
{
public :
    vector < vector < int >> fourSum ( vector < int > & nums , int target )
    {
        if ( nums . size () < 4 ) return vector < vector < int >>(); // 或者用 {{}}
       
        set <vector<int>> res;
        sort ( nums . begin (), nums . end ());
       
        // 扫描 a[i],a[j] 后面接 left,right 两个指针
        for ( int i = 0 ; i < int ( nums . size () - 3 ); i ++)
        {
            for ( int j = i + 1 ; j < int ( nums . size () - 2 ); j ++)
            {
    //            if (j > i + 1 && nums[j] == nums[j - 1]) continue; // 遇到重复数时不执行下面语句,如果用 set 可以不进行此判断
               
                int left = j + 1, right = nums.size() - 1//i=0~n-4,j=i+1~n-3
                while ( left < right )
                {
                    int sum = nums [ i ] + nums [ j ] + nums [ left ] + nums [ right ];
                    if ( sum == target )
                    {
                        vector < int > out { nums [ i ], nums [ j ], nums [ left ], nums [ right ]};
                        res . insert ( out ); // set, 当有重复结果时,插入会失败
                        left ++; right --;
                    }
                    else if ( sum < target ) left ++;
                    else right --;
                }
            }
        }
        return vector < vector < int >>( res . begin (), res . end ()); //set转化为vector输出
    }
};
 

 

posted @ 2019-01-05 13:46 wikiwen 阅读( ...) 评论( ...) 编辑 收藏
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值