【基础算法】和为S的两个数字问题

108 阅读3分钟

🌹作者:云小逸
📝个人主页:云小逸的主页
📝Github:云小逸的Github
🤟motto:要敢于一个人默默的面对自己,==强大自己才是核心==。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天来之前,我们一起面朝大海,春暖花开!==🤟 👏专栏:C++👏 👏专栏:Java语言👏👏专栏:Linux学习👏
👏专栏:C语言初阶👏👏专栏:数据结构👏👏专栏:备战蓝桥杯👏

@TOC


前言

今天我们继续学习算法,加油。这篇文章写的是和为S的两个数字问题。希望这篇可以有幸帮助到你,码字不易,请多多支持。 在这里插入图片描述


题目描述

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

算法思路

方法一:暴力枚举

最容易想到的方法是枚举数组中所有的数对,并判断它们的和是否为 SS。由于数组是递增的,因此我们可以按照下面的方式来枚举所有的数对:

  • 枚举左端点 ii,由于右端点要在 ii 的右侧,因此我们从 i+1i+1 开始枚举右端点 jj
  • 如果当前数对的和等于 SS,则找到了一组解,将其返回。

算法的时间复杂度为 O(n2)O(n^2),其中 nn 是数组的长度。

方法二:哈希表

我们可以先固定一个数 xx,再在数组中查找是否存在 SxS-x。由于我们只需要找到一组解,因此使用哈希表来快速判断一个数是否在数组中出现过。具体地,我们遍历数组中的每个数 xx,如果 SxS-x 在数组中,就找到了一组解。

我们可以将数组中的所有数存入哈希表中,然后对于每个 xx,使用 O(1)O(1) 的时间复杂度判断 SxS-x 是否在哈希表中。

算法的时间复杂度为 O(n)O(n),其中 nn 是数组的长度。

方法三:双指针

由于数组已经排好序了,因此我们可以使用双指针的方法,令左指针 ii 指向数组的起始位置,右指针 jj 指向数组的结束位置。每次计算两个指针指向的数的和 sumsum,并进行如下操作:

  • 如果 sumsum 等于 SS,则找到了一组解。
  • 如果 sumsum 小于 SS,则将左指针 ii 右移一位。
  • 如果 sumsum 大于 SS,则将右指针 jj 左移一位。

算法的时间复杂度为 O(n)O(n),其中 nn 是数组的长度。

C++代码

方法一:暴力枚举

#include <iostream>
#include <vector>

using namespace std;

vector<int> findNumbersWithSum(vector<int>& nums, int target) {
    vector<int> res;
    for (int i = 0; i < nums.size(); ++i) {
        for (int j = i + 1; j < nums.size(); ++j) {
            if (nums[i] + nums[j] == target) {
                res.push_back(nums[i]);
                res.push_back(nums[j]);
                return res;
            }
        }
    }
    return res;
}

int main() {
    vector<int> nums = {1, 2, 3, 4};
    int target = 7;
    vector<int> res = findNumbersWithSum(nums, target);
    if (res.size() == 2) {
        cout << "[" << res[0] << ", " << res[1] << "]" << endl;
    } else {
        cout << "No solution" << endl;
    }
    return 0;
}

方法二:哈希表

#include <iostream>
#include <vector>
#include <unordered_set>

using namespace std;

vector<int> findNumbersWithSum(vector<int>& nums, int target) {
    vector<int> res;
    unordered_set<int> hash_set;
    for (int i = 0; i < nums.size(); ++i) {
        int complement = target - nums[i];
        if (hash_set.count(complement)) {
            res.push_back(complement);
            res.push_back(nums[i]);
            return res;
        }
        hash_set.insert(nums[i]);
    }
    return res;
}

int main() {
    vector<int> nums = {1, 2, 3, 4};
    int target = 7;
    vector<int> res = findNumbersWithSum(nums, target);
    if (res.size() == 2) {
        cout << "[" << res[0] << ", " << res[1] << "]" << endl;
    } else {
        cout << "No solution" << endl;
    }
    return 0;
}

方法三:双指针

#include <iostream>
#include <vector>

using namespace std;

vector<int> findNumbersWithSum(vector<int>& nums, int target) {
    vector<int> res;
    int i = 0, j = nums.size() - 1;
    while (i < j) {
        int sum = nums[i] + nums[j];
        if (sum == target) {
            res.push_back(nums[i]);
            res.push_back(nums[j]);
            break;
        } else if (sum < target) {
            ++i;
        } else {
            --j;
        }
    }
    return res;
}

int main() {
    vector<int> nums = {1, 2, 3, 4};
    int target = 7;
    vector<int> res = findNumbersWithSum(nums, target);
    if (res.size() == 2) {
        cout << "[" << res[0] << ", " << res[1] << "]" << endl;
    } else {
        cout << "No solution" << endl;
    }
    return 0;
}

注意,方法三中可以添加一个判断 i<ji<j 的条件来避免出现重复的解。


最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.把时间尺度拉长,拉长十年看当下

2.不说负面情绪,只描述事实;

3.越专注于过好自己,能量和幸运越会照顾你; 只解决问题,不做没有意义的担心,输了就认;

4.学会原谅自己,要允许自己做错事,允许自己出现情绪波动,我知道你已经很努力很努力在做好了

5.所有你害怕的、想逃避的事情,最终都要面对,既然这样不如选择坦然面对。即使结果不如人愿,没关系,至少这个过程是享受的,而不是一路带着恐惧和害怕。

最后如果觉得我写的还不错,请不要忘记==点赞==✌,==收藏==✌,加==关注==✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚==菜鸟==逐渐成为==大佬==。加油,为自己点赞!