美文网首页
0015-三数之和

0015-三数之和

作者: liyoucheng2014 | 来源:发表于2019-01-20 21:14 被阅读0次

三数之和

方案一


基于两数之和计算
如果nums[i] > 0则不需要管后面

C-源代码


int compareInt(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

void two_sum(int *nums, int left, int right, int target, int **results, int *count) {
    while (left < right) {
        int diff = target - nums[left];
        if (diff < nums[right]) {
            while (--right > left && nums[right] == nums[right + 1]) {
                
            }
        } else if (diff > nums[right]) {
            while (++left < right && nums[left] == nums[left - 1]) {
                
            }
        } else {
            results[*count] = malloc(3 * sizeof(int));
            results[*count][0] = -target;
            results[*count][1] = nums[left];
            results[*count][2] = nums[right];
            (*count)++;
            
            while (++left < right && nums[left] == nums[left - 1]) {}
            while (--right > left && nums[right] == nums[right + 1]) {}
        }
    }
}


int** threeSum(int* nums, int numsSize, int* returnSize) {
    if (numsSize < 3) {
        return NULL;
    }
    
    qsort(nums, numsSize, sizeof(*nums), compareInt);
    
    *returnSize = 0;
    int **results = malloc(sizeof(int *) * (((numsSize * (numsSize - 1) * (numsSize - 2))) / (3 * 2 * 1)));
    for (int i = 0; i < numsSize; i++) {
        if ((i == 0 && nums[i] <= 0) || ((i > 0 && nums[i] != nums[i - 1]) && nums[i] <= 0)) {
            two_sum(nums, i + 1, numsSize - 1, -nums[i], results, returnSize);
        }
    }
    
    return results;
}

void test_0015()
{
    int arr[6] = { -1, 0, 1, 2, -1, -4 };
//    int arr[4] = { 1, 2, -2, -1 };
    int count = 0;
    int **ret = threeSum(arr, 4, &count);
    
    if (ret) {
        for (int i = 0; i < count; i++) {
            int *temp = ret[i];
            printf("%d->%d->%d\n",temp[0],temp[1],temp[2]);
        }
        
    }
}

方案二


对原数组进行排序,然后开始遍历排序后的数组,这里注意不是遍历到最后一个停止,而是到倒数第三个就可以了。这里我们可以先做个剪枝优化,就是当遍历到正数的时候就break,为啥呢,因为我们的数组现在是有序的了,如果第一个要fix的数就是正数了,那么后面的数字就都是正数,就永远不会出现和为0的情况了。然后我们还要加上重复就跳过的处理,处理方法是从第二个数开始,如果和前面的数字相等,就跳过,因为我们不想把相同的数字fix两次。对于遍历到的数,用0减去这个fix的数得到一个target,然后只需要再之后找到两个数之和等于target即可。我们用两个指针分别指向fix数字之后开始的数组首尾两个数,如果两个数和正好为target,则将这两个数和fix的数一起存入结果中。然后就是跳过重复数字的步骤了,两个指针都需要检测重复数字。如果两数之和小于target,则我们将左边那个指针i右移一位,使得指向的数字增大一些。同理,如果两数之和大于target,则我们将右边那个指针j左移一位,使得指向的数字减小一些

C++-源代码


#include <iostream>
#include <queue>
#include <unordered_map>

using namespace std;

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        
        vector<vector<int>> res;
        
        // 对原数组进行排序
        sort(nums.begin(), nums.end());
        
        if (nums.empty() || nums.back() < 0 || nums.front() > 0) {
            
            return {};
        }
        
        for (int k = 0; k < nums.size(); ++k) {
            
            // 当遍历到正数的时候就break
            if (nums[k] > 0) {
                
                break;
            }
            
            if (k > 0 && nums[k] == nums[k - 1]) {
                
                continue;
            }
            
            // 对于遍历到的数,用0减去这个fix的数得到一个target
            int target = 0 - nums[k];
            int i = k + 1;
            int j = nums.size() - 1;
            while (i < j) {
                
                // 用两个指针分别指向fix数字之后开始的数组首尾两个数,如果两个数和正好为target,则将这两个数和fix的数一起存入结果中
                if (nums[i] + nums[j] == target) {
                    
                    res.push_back({nums[k], nums[i], nums[j]});
                    // 检测重复数字
                    while (i < j && nums[i] == nums[i + 1]) {
                        
                        ++i;
                    }
                    
                    // 检测重复数字
                    while (i < j && nums[j] == nums[j - 1]) {
                        
                        --j;
                    }
                    
                    ++i;
                    --j;
                }
                // 如果两数之和小于target,则我们将左边那个指针i右移一位
                else if (nums[i] + nums[j] < target) {
                    
                    ++i;
                }
                // 如果两数之和大于target,则我们将右边那个指针j左移一位
                else {
                    
                    --j;
                }
            }
        }
        
        return res;
    }
};

参考Grandyang

相关文章

  • 0015-三数之和

    三数之和 方案一 基于两数之和计算如果nums[i] > 0则不需要管后面 C-源代码 方案二 对原数组进行排序,...

  • 0018-四数之和

    四数之和 方案一 基本类似0015-三数之和,需要手动进行去重复处理。主要可以进行的有三个地方,首先在两个for循...

  • algrithrom

    求和问题,双指针解决 done 两数之和 三数之和 最接近三数之和 四数之和 链表反转问题 done 链表反转 链...

  • LeetCode 第18题:四数之和

    1、前言 2、思路 采用三数之和的思路,原本三数之和可以分解为:数组中的一个数 + 此数右边的数求两数之和,那么四...

  • 两数之和&三数之和&四数之和&K数之和

    今天看了一道谷歌K数之和的算法题,忽然想起来之前在力扣上做过2、3、4数之和的题,觉得很有必要来整理一下。其实2、...

  • 两数之和,三数之和

    转载:https://www.cnblogs.com/DarrenChan/p/8871495.html 1. 两...

  • 双指针总结

    左右指针 主要解决数组中的问题:如二分查找 盛最多水的容器 三数之和 四数之和 最接近三数之和 快慢指针 主要解决...

  • 【LeetCode通关全记录】15. 三数之和

    【LeetCode通关全记录】15. 三数之和 题目地址:15. 三数之和[https://leetcode-cn...

  • leetcode top100

    1.求两数之和(数组无序) 2.求电话号码的字母组合 3.三数之和 4.两数之和(链表)

  • 纯C手撕leetcode-基本数据结构-hash table

    Hash table纯C实现两数之和和Hashtable 三数之和https://leetcode-cn.com/...

网友评论

      本文标题:0015-三数之和

      本文链接:https://www.haomeiwen.com/subject/scyfjqtx.html