【力扣一轮】15.三数之和 && 18.四数之和

15.三数之和

思路

刚开始是准备用之前的方法哈希进行查找。但是题目中说到不能有重复的元素值。所以直接看视频讲解。

视频用到双指针法。先对整个数组进行排序,接着对数组每个元素遍历。

如果第一个元素就大于0,那么直接返回空。因为正数列表怎么加都不能为0。

left和right以及当前遍历的数值,如果三者相加为正,则说明要减少其和,right要向左移动;如果三者相加为负,则说明要增加其和,left要向右移动。

那么去重操作怎么做?

👇

Q1=》判断numbers[i]==numbers[i+1]还是numbers[i]==numbers[i-1]?

A1=》前者如果contine,会把有重复的元素的结果集给筛掉。而后者则不会。(不理解,作为复习点,先记住。)

Q2=》遍历的退出条件是什么?

A2=》因为是不重复的,所以要用不重复的索引,那就是left<right。遇到边界性问题,可以代入尝试,再选择退出条件。

接下来就是操作逻辑。left和right。去重操作逻辑:和当前遍历数值去重逻辑一致。判断条件是

对于right,如果right>left && nums[right]==nums[right-1],则right--;

对于left,若right>left && nums[left] == nums[left+1],则left++;

伪代码

对数组排序
//剪枝
判断首元素是否>0
   	如果大于0
    	则不满足题意,直接退出
遍历数组的每个元素
    //去重
    如果有重复元素
    	直接继续走
    新建left指针
    新建right指针
    当left<right指针时
    	如果三者相加<0
    		left指针右移
    	如果三者相加>0
    		right指针左移
    	如果三者相加为0
    		将当前这三个元素作为数组添加到最后的结果集中
    		循环判断left指针是否和下一个元素重复,直到不重复为止
    			如果重复
    				left指针右移
    		循环判断right指针是否和下一个元素重复,直到不重复为止
    			如果重复
    				right指针左移
    		找到答案后,双指针同时收缩
返回结果集  				

实际代码

vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> vtvt;
        sort(nums.begin(), nums.end());
        if (nums[0] > 0) {
            return vtvt;
        }
        for (int i = 0; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i + 1;
            int right = nums.size() - 1;
            while (left < right) {
                if (nums[i] + nums[left] + nums[right] < 0) {
                    left++;
                } else if (nums[i] + nums[left] + nums[right] > 0) {
                    right--;
                } else {
                    vector<int> temp;
                    temp.push_back(nums[i]);
                    temp.push_back(nums[left]);
                    temp.push_back(nums[right]);
                    vtvt.push_back(temp);
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }

                    // 找到答案时,双指针同时收缩
                    right--;
                    left++;
                }
            }
        }
        return vtvt;
    }

18.四数之和

思路

和三数之和一致,不过因为多了一个数字,所以有两层循环,对应的剪枝和去重有两次。

剪枝:去除掉本来就不符合要求的元素。对于外层循环中的元素,如果符合target>0 && nums[k]>0 && nums[k]>target则直接退出该循环。对于内层中的元素,因为到了内层,要把ik看作整体,所以如果符合nums[k]+nums[i]>target && target > 0 && nums[i]>0,则直接退出循环。

去重:对于重复的元素不再遍历,要求继续循环到不重复的元素。对于外层元素,则为k>0 && nums[k]==nums[k-1] 则继续循环到下一个不重复的元素。对于内层元素,则为i>k+1 && nums[i]==nums[i-1]

其它的则与三数之和一致。伪代码如下。

伪代码

对数组排序
外层循环
	//剪枝
    判断首元素是否>target && target>0 && 索引k>0
    	如果符合条件,则退出循环
    //去重
    判断元素和之前的元素是否重复
	    如果重复,则继续循环
    去重
    内层循环
        //剪枝
        判断内层循环元素+外层循环元素是否>target && target>0 && 内层索引是否大于外层索引
            如果大于0
                则不满足题意,直接退出
        //去重
        如果有重复元素
            直接继续走
        新建left指针
        新建right指针
        当left<right指针时
            如果三者相加<0
                left指针右移
            如果三者相加>0
                right指针左移
            如果三者相加为0
                将当前这三个元素作为数组添加到最后的结果集中
                循环判断left指针是否和下一个元素重复,直到不重复为止
                    如果重复
                        left指针右移
                循环判断right指针是否和下一个元素重复,直到不重复为止
                    如果重复
                        right指针左移
                找到答案后,双指针同时收缩
返回结果集 

实际代码

vector<vector<int>> fourSum(vector<int>& nums, int target) {

        // target = long(target);
        sort(nums.begin(), nums.end());
        vector<vector<int>> vtvt;
        for (int k = 0; k < nums.size(); k++) {
            // 剪枝
            if (k > 0 && target > 0 && nums[k] > 0 && nums[k] > target) {
                break;
            }
            // 去重
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
            for (int i = k + 1; i < nums.size(); i++) {
                // 剪枝
                if (i > k + 1 && target > 0 && nums[i] + nums[k] > target &&
                    nums[i] + nums[k] >= 0) {
                    break;
                }
                // 去重
                if (i > k + 1 && nums[i] == nums[i - 1]) {
                    continue;
                }
                int left = i + 1;
                int right = nums.size() - 1;
                while (left < right) {
                    if ((long)nums[k] + nums[i] + nums[left] + nums[right] >
                        target) {
                        right--;
                    } else if ((long)nums[k] + nums[i] + nums[left] +
                                   nums[right] <
                               target) {
                        left++;
                    } else {
                        vector<int> vt;
                        vt.push_back(nums[k]);
                        vt.push_back(nums[i]);
                        vt.push_back(nums[left]);
                        vt.push_back(nums[right]);
                        vtvt.push_back(vt);
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return vtvt;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你的铭称

随缘惜缘不攀缘。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值