LeetCode 力扣:15.3Sum + 16.3Sum Closest + 18.4Sum 排序 + 双指针遍历 题目+算法分析+Cpp解答

15.3Sum

排序 + 双指针遍历:

​ 首先,将给定的数组进行排序(从小到大的顺序)。

​ 遍历排序后的数组中的每一个数,如果这个数之前已经讨论过了则可以跳过。

​ 将取出的数作为“目标”,使用双指针在排序后的数组中找另外的两个数:

​ 一个左指针指向该取出的数的后一个数,即此时的最低位。

​ 另一个右指针指向数组的最后一个数,即此时的最高位。

​ 由于数组已经是从小到大进行排序了,所有令此时的三个数的和为 sum:

  • 如果 sum > 0,说明右指针指向的数太大,要向左移,即使得所指的数变小(如果向左移后的数和之前一样大则需要继续向左移);
  • 如果 sum < 0,说明左指针指向的数太小,要向右移,即使得所指的数变大(如果向右移后的数和之前一样大则需要继续向右移);
  • 如果 sum = 0,说明找到答案,并让左指针和右指针都向中间靠拢,看有没有新的答案。
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int len = nums.size();
        vector<vector<int>> ans;
        sort(nums.begin(),nums.end());
        for(int i=0;i<len-2;i++){
            if(i > 0 && nums[i-1] == nums[i])
                continue;
            int left = i+1,right = len-1;
            while(left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(sum > 0)
                    while(left < --right && nums[right] == nums[right+1]);
                else if(sum < 0)
                    while(++left < right && nums[left-1] == nums[left]);
                else{
                    vector<int> temp = {nums[i],nums[left],nums[right]};
                    ans.push_back(temp);
                    while(++left < right && nums[left] == nums[left-1]);
                    while(left < --right && nums[right] == nums[right+1]);
                }
            }
        }
        return ans;
    }
};

16.3Sum Closest

排序 + 双指针遍历:

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int len = nums.size();
        int ans = nums[0] + nums[1] + nums[2];
        sort(nums.begin(),nums.end());
        for(int i = 0; i < len-2; i++ ){
            if( i > 0 && nums[i] == nums[i-1])
                continue;
            int left = i+1,right = len-1;
            while(left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(abs(ans - target) > abs(sum - target))
                    ans = sum;
                if(sum > target)
                    while(left < --right && nums[right] == nums[right+1]);
                else if(sum < target)
                    while(++left < right && nums[left] == nums[left-1]);
                else
                    return sum;
            }
        }
        return ans;
    }
};

18.4Sum

排序 + 双指针遍历:

​ 类似 3Sum 那道题,都是一个套路,只是多了一层循环。

​ 增加了几个判断可以提高程序性能:

  • 如果此时最小的四个数相加还比目标数值大,那么可以直接跳出循环。
  • 如果此时遍历的第 i 个数和最大的三个数相加还比目标数值小,那么可以直接进入下一轮循环(使得第 i 个数变大)。
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> ans;
        int len = nums.size();
        sort(nums.begin(),nums.end());
        for(int i=0;i<len-3;i++){
            if(i > 0 && nums[i] == nums[i-1])
                continue;
            if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3] > target)
                break;
            if(nums[i]+nums[len-1]+nums[len-2]+nums[len-3] < target)
                continue;
            for(int j=i+1;j<len-2;j++){
                if(j > i+1 && nums[j] == nums[j-1])
                    continue;
                int left = j+1,right = len-1;
                while(left < right){
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if(sum > target)
                        while(left < --right && nums[right] == nums[right+1]);
                    else if(sum < target)
                        while(++left < right && nums[left] == nums[left-1]);
                    else{
                        ans.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
                        while(left < --right && nums[right] == nums[right+1]);
                        while(++left < right && nums[left] == nums[left-1]);
                    }
                }
            }
        }
        return ans;
    }
};
发布了36 篇原创文章 · 获赞 5 · 访问量 5230

猜你喜欢

转载自blog.csdn.net/qq_43413123/article/details/104988832