leetcode 15 三数之和 (c++和python)

目录

题目描述:

解题思路:

C++代码:

Python代码:


题目描述:

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

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

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解题思路:

  • 先从小到大排序;
  • 固定一个寻找另外两个数,遍历数组,定三个索引,当前 i = 0视为第一个数字,另外两个分别是L = i+1, R = nums.end()-1;
  • 判断三个数之和是否为0,等于0,则添加记录;如果小于0,则总和过小,L++;如果大于0,R--;

问题的关键是去除重复,情况如下:

(1)i指向重复:当前索引i>0,且与前一个数字相等,重复

比如[-10,-6,-6, 2,4,9], i=1和i=2都是-6,当i=1时,然后通过L和R找后面两个数字,与i=2时,找后面的数字重复了,所以遇到重复的,则不再重复使用,跳过,即不使用i=2,直接用后面的,从i=3开始继续找左右两个数字。

(2)L或者R指向的数字重复:比如[-10,-7,8,8,9,10], 当i=0是,L=2和L=3指向的都是8,重复了,跳过,直接指向后面一个。

C++代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        // 
        int nums_len = nums.size();
        if (nums_len < 3) return {};
        
        // 排序
        sort(nums.begin(), nums.end());

        // 依次将当前数字nums[i]视为第一个数字,在后面寻找其他两个数字
        vector<vector<int>> ans;
        for (int i = 0; i < nums_len-2; i++)
        {
            // 有序数组,第一个数字就大于0
            if (nums[i] > 0) return ans;
            // 当前的数字nums[i]和前面的数字重复,则不再判断,跳过
            if (i > 0 && nums[i] == nums[i-1]) continue;  // i>0必须放前面
            // 
            int L = i+1;
            int R = nums_len-1;
            while (L < R)
            {
                int sum_val = nums[i] + nums[L] + nums[R];
                if (sum_val == 0)
                {
                    ans.push_back({nums[i], nums[L], nums[R]});  // 记录当前合适的,再看看后面是否存在重复的
                    while (L < R && nums[L] == nums[L+1]) L++;  // 去重,取后面索引,有序数组[-10,-6,-6, 2,4,16],当前i=0,L=1,R=5,则L=1时重复了
                    while (L < R && nums[R] == nums[R-1]) R--;  // 去重,取前面索引,有序数组
                    L++;
                    R--;
                }
                else if (sum_val < 0) L++;
                else R--;
            }
        }
        return ans;
    }
};

Python代码:

执行用时:396 ms, 在所有 Python 提交中击败了73.70%的用户

内存消耗:18.7 MB, 在所有 Python 提交中击败了23.58%的用户

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        # 排序
        nums.sort()
        # 长度不够
        nums_len = len(nums)
        if nums_len < 3: return []

        # 固定当前数字为三个数字中的第一个,再寻找其他两个数字
        # 使用左右指针指向nums[i]后面的两端,确认是否符合条件
        # 事情的关键是如何去除重复的
        ans = []
        for i in range(nums_len-2):
            if nums[i] > 0: return ans  # 有序列表,第一数字就大于0,那总和肯定不会等于0
            # 如当前索引i>0,且与前一个数字相等,重复
            # 比如[-10,-6,-6, 2,4,9], 当i=2时,即当前数字是-6,当前数字-6已经在i=1时作为第一个数用过一次了,重复
            if i > 0 and nums[i] == nums[i-1]: continue  # i = i+1,即数字2作为第一个数
            
            L = i+1
            R = nums_len - 1
            while L < R:
                sum_val = nums[i] + nums[L] + nums[R] 
                if sum_val == 0: 
                    ans.append([nums[i], nums[L], nums[R]])   # 找到当前合适的,在确认后面的是否重复。
                    while L<R and nums[L] == nums[L+1]: L = L + 1  # 去重,取后面索引,有序列表[-10,-6,-6, 2,4,16],当前i=0,L=1,R=5,则L=1时重复了
                    while L<R and nums[R] == nums[R-1]: R = R - 1  # 去重,取前面索引,有序列表
                    L = L + 1  # -6用过了,直接跳过2个-6,指向后面的2
                    R = R - 1
                elif sum_val < 0: L = L + 1
                else: R = R - 1
        
        return ans
                    
                

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mr.Q

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值