力扣刷题 DAY_19 三指针

leetcode 15

链接:力扣 

题目:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

示例:

输入:nums = [-1, 0, 1, 2, -1, -4],

输出:[ [-1, 0, 1], [-1, -1, 2] ]

思路:

先来看一道经典的双指针问题:在一个有序的序列nums中求两个不同的数使得nums[i] + nums[j] == c (c是一个常数)。

这道题目使用two points解决。设置一个left指针在序列最左端(即下标0)。设置一个right指针在序列最右端(即下标nums.size() - 1)。然后计算当前nums[left] + nums[right]的值。如果nums[left] + nums[right] < c,则把left右移一位;如果nums[left] + nums[right] > c,则把right左移一位;如果nums[left] + nums[right] == c,说明找到了我们需要的二元组,记录下这个二元组后把left右移一位并且把right左移一位。一直重复这个过程,直到left = right结束。

while (left < right) {
    if (nums[left] + nums[right] < c) {
        left++;
    }
    else if (nums[left] + nums[right] > c) {
        right--;
    }
    else {
        //找到这个二元组,输出
        left++;
        right--;
    }
}

再来看这道三指针的问题。我们先对序列非递减排序,然后用for循环遍历,对于当前元素nums[i],在后面的序列 i + 1 ~ len - 1 中再使用双指针的方法求解使 nums[left] + nums[right] == 0 - nums[i]成立的元组即可。

但是在本题中,我们有一些细节需要处理:

(1)对于非递减的序列,如果当前元素nums[i] > 0,说明之后的元素都比0大了,无论再怎么组合不可能等于0。此时直接退出循环。

(2)本题所给序列中有重复元素,但是要求结果中不需要重复元素。本题得一大难点是怎么去重?最优的方法是在遍历的时候进行去重。这里我们利用到一点:对于有序序列,相等元素一定是连续出现的。对于当前元素nums[i],如果在它的前面的一位已经出现过相等元素,我们直接跳过这次循环进入下一次,这样我们得以消除nums[i]的计算重复。消除nums[left]和nums[right]的计算重复也是用的相同思路。在找到nums[left] + nums[right] == 0 - nums[i]时,我们记录下这次的三元组,然后循环判断nums[left]是否等于它后面的一个元素,如果相等一直往后移动;循环判断nums[right]是否等于它前面的一个元素,如果相等一直往前移动。如此得以消除所有的重复。

参考代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int> > result;
        int len = nums.size();
        for (int i = 0; i < len; i++) {
            if (nums[i] > 0) {
                break;
            }
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i + 1, right = len - 1;
            while (left < right) {
                if (nums[left] + nums[right] == 0 - nums[i]) {
                    result.push_back({nums[i], nums[left], nums[right]});
                    while(left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    right--;
                    left++;
                }
                else if (nums[left] + nums[right] > 0 - nums[i]) {
                    right--;
                }
                else {
                    left++;
                }
            }
        }
        return result;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于力扣刷C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷中,使用 string 可以方便地处理字符串相关的问。 9. 注意边界条件:在力扣刷中,边界条件往往是解决问的关键。需要仔细分析目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值