leetcode 3 sum closest算法

题目出处


给定一个数组arr和一个目标值target,查找三个数a, b c, 使他们的各a+b+c与target的差距最小, 返回 a+b+c。
假设数组中满足要求的就只有一组数据。
如: 给定的数组为:[-1,  1, 2, -4], target = 1,
     由于离target 1最小的三个数为[-1, 2, 1]其差距为1. 即(-1 + 1 + 2) - 1 = 1;


分析
很类似于3Sum的算法。 3sum算法地址: http://blog.csdn.net/net_wolf_007/article/details/51788475
不同的点是3sum求的是各为0的3个数,这就使得3个数中要么都为0,要么必须有正有负。
而这道题目是要3个数的和与目标值最小,就没有正负之分。所以就不需要对此进行判断。

同时这道题目中要求只返回一个值,所以当判断为0时,就是要求的值,就可以停止查找。


算法(与3 sum比较改变的地方)
先对数组进行排序
min_gap = arr[0] + arr[1] + arr[2] - target;
定义三个指针: i, j, k
i: 从排序后的数组开始移动。
k: 从数组的最后往前移动。
j: 在[i, k]之间移动
如果i, j, k对应的数之和为sum;
          计算gap = sum - target;
如果gap== 0, 得到一个解,直接返回 target。
如果gap 小于 min_gap , 更新min_gap
如果gap > 0: 移动k
如果gap < 0: 移动j

如果 j > k: 则移动i, 并重新定义 k, j.
同时对算法作两点优化来减少比较的次数
     k :没必要每次都从最后元素开始移动,所以需要记录k的最后位置。
      (去掉: 由于没有正负之分)i: 没必要移动最后, 要以i > 0 为终点。

代码

int threeSumClosest(vector<int>& nums, int target) {
        if(nums.size() < 3) return 0;
        sort(nums.begin(), nums.end()); 
        // 初始化最小的差值
        int min_gap =  nums[0] + nums[1] + nums[2] - target; 
        
        int last = nums.size()-1;
        for(int i = 0; i < nums.size()-2; i++){
            if(i > 0 && nums[i] == nums[i-1]) continue;
            int j = i + 1;
            int k = last;
            while(j < k){
                if(j > i+1 && nums[j] == nums[j-1]) {j += 1;continue;}
                int gap = nums[i] + nums[j] + nums[k]-target; 
                
                if(gap == 0) return target;//0为最小值。
                
                if(abs(gap) < abs(min_gap)){
                    min_gap = gap;
                }
                if(gap < 0) j += 1;
                else{
                    k -= 1;
                    if(j == i+1) last = k;
                } 
            }
        }
        return target + min_gap;
    }


猜你喜欢

转载自blog.csdn.net/net_wolf_007/article/details/51804630