剑指 Offer 57. 和为s的两个数字

Posted aaaaaaaWoLan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 57. 和为s的两个数字相关的知识,希望对你有一定的参考价值。

剑指 Offer 57. 和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

限制:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^6

思路一:二分查找,遍历数组元素,遍历时得到target与每个元素的差值,再用二分查找在数组里从当前元素开始向后找差值。

假设某个数组元素为nums[i],差值founder = target - num[i],左边界为nums[i],向后查找founder。因为nums[i]之前的元素都已经被遍历过了,founder如果存在,不可能在nums[i]之前。

在二分查找函数里用一个布尔变量flag来判断是否找到了founder,找到了返回founder,否则返回-1(数组元素大于等于1)

时间复杂度:O(N*logN)

代码:

int BinarySearch(int*nums, int begin, int numsSize, int target, bool flag)
{
    int mid = begin + (end - begin) / 2;
    while (begin <= end)
    {
        mid = begin + (end - begin) / 2;
        if (nums[mid] > target)
        {
            end = mid - 1;
        }
        else if (nums[mid] < target)
        {
            begin = mid + 1;
        }
        else
        {
            flag = true;
            break;
        }
    }

    if (flag == true)
    {
        return nums[mid];
    }
    else
    {
        return -1;
    }
}

int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    if (numsSize == 0)
    {
        *returnSize = 0;
        return NULL;
    }
    
    int result = 0;
    int i = 0;
    while (i < numsSize)
    {
        printf("%d ", i);
        int founder = target - nums[i];

        //如果target与当前数组元素的值小于该数组元素,说明找不到这样的两个元素
        if (founder < nums[i])
        {
            *returnSize = 0;
            return NULL;
        }
        else
        {
            result = BinarySearch(nums, i, numsSize, founder, false);

            if (result == -1)//没找到,继续查找
            {
                i++;
                continue;
            }
            else//找到了
            {
                break;
            }
        }
    }

    //循环结束还没有找到
    if (result == -1)
    {
        *returnSize = 0;
        return NULL;
    }

    *returnSize = 2;
    int*ret = (int*)malloc(sizeof(int) * (*returnSize));
    ret[0] = nums[i];
    ret[1] = result;

    return ret;

}

自认为这个时间复杂度已经够快了,直到看到题解里的双指针、哈希表(只会用C的菜鸡还不懂哈希表)…

**思路二:**双指针遍历,一个指针指向数组左边界,一个指向右边界,类似二分思想

  • 当左指针元素与右指针元素之和大于target时,右指针向左走一步
  • 当两者之和小于target时,左指针向右走一步

代码:

int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    if (numsSize == 0)
    {
        *returnSize = 0;
        return NULL;
    }

    int left = 0;
    int right = numsSize - 1;
    *returnSize = 2;
    int*ret = (int*)malloc(sizeof(int) * (*returnSize));
    while (left <= right)
    {   
        if (nums[left] + nums[right] > target)//和偏大
        right--;
        else if (nums[left] + nums[right] < target)//和偏小
        left++;
        else//找到了
        {
            ret[0] = nums[left];
            ret[1] = nums[right];
            return ret;
        }
    }

    //出循环了说明没有找到
    *returnSize = 0;
    return NULL;
}

以上是关于剑指 Offer 57. 和为s的两个数字的主要内容,如果未能解决你的问题,请参考以下文章

剑指 Offer 57. 和为s的两个数字

剑指 Offer 57. 和为s的两个数字

LeetCode(剑指 Offer)- 57. 和为 s 的两个数字

LeetCode(剑指 Offer)- 57. 和为 s 的两个数字

LeetCode——剑指 Offer 57 和为s的两个数字

算法剑指 Offer 57. 和为s的两个数字