Leetcode梦开始的地方--两数相加

LeetCode 梦开始的地方 ------ 两数之和

文章目录

1. 前言

对于很多程序员来说,LeetCode 是学习算法和数据结构的重要起点。而"两数之和"这道题目,作为 LeetCode 上的经典入门题目之一,对于理解哈希表的应用以及如何高效地解决问题有着重要的意义。本文将带你从零开始,逐步理解并实现这道题目的解决方案。

2. 题目描述

题目来源: LeetCode - 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会有一个有效答案

3. 解题思路

方法一:暴力法

最直接的方法是使用双重循环遍历数组中的所有元素组合,找到满足条件的一对数值。这种方法的时间复杂度为 O(n^2),效率较低。

方法二:哈希表

更高效的解决方案是使用哈希表(字典)。我们可以通过遍历数组一次来查找目标值。对于每个元素 nums[i],我们检查 target - nums[i] 是否已经在哈希表中。如果存在,则找到了一对解;如果不存在,则将 nums[i] 存入哈希表中。

这种方法的时间复杂度为 O(n),空间复杂度也为 O(n)。

4. 代码实现

方法一:暴力法

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();  // 获取 nums 数组的长度
        for (int i = 0; i < n; ++i) {  // 第一层循环,遍历 nums 数组
            for (int j = i + 1; j < n; ++j) {  // 第二层循环,从 i+1 开始遍历,避免重复检查
                if (nums[i] + nums[j] == target) {  // 检查当前两个数之和是否等于目标值
                    return {i, j};  // 如果等于目标值,返回这两个数的索引
                }
            }
        }
        return {};  // 如果没有找到符合条件的两个数,返回空的 vector
    }
};
  1. 定义类 Solution:

    cpp 复制代码
    class Solution {

    这行代码定义了一个名为 Solution 的类。这是 LeetCode 中常见的做法,用于组织解题代码。

  2. 声明成员函数 twoSum:

    cpp 复制代码
    public:
        vector<int> twoSum(vector<int>& nums, int target) {

    这是一个公开的成员函数 twoSum,它接受一个整数向量 nums 的引用和一个整数 target 作为参数,并返回一个包含两个整数的向量。这里的 nums 是问题描述中的整数数组,target 是目标值。

  3. 获取数组长度:

    cpp 复制代码
        int n = nums.size();

    这行代码获取了 nums 向量的大小,并将其存储在整数变量 n 中。

  4. 第一层循环:

    cpp 复制代码
        for (int i = 0; i < n; ++i) {

    这是第一层循环,用于遍历整个 nums 向量。变量 i 作为索引从 0 开始递增。

  5. 第二层循环:

    cpp 复制代码
            for (int j = i + 1; j < n; ++j) {

    这是第二层循环,它从 i + 1 开始,直到 n。这样可以确保不会重复检查相同的元素对。

  6. 检查两数之和:

    cpp 复制代码
                if (nums[i] + nums[j] == target) {

    这行代码检查当前的 nums[i]nums[j] 之和是否等于 target

  7. 返回索引:

    cpp 复制代码
                    return {i, j};

    如果找到匹配的元素对,就立即返回包含这两个索引的向量 {i, j}

  8. 结束第二层循环:

    cpp 复制代码
                }
            }
  9. 结束第一层循环:

    cpp 复制代码
        }
  10. 如果没有找到匹配的元素对:

    cpp 复制代码
           return {};
    //如果遍历完所有的可能组合都没有找到匹配的元素对,那么返回一个空的向量。

这段代码实现了暴力法来解决"两数之和"问题,其时间复杂度为 O(n^2)。虽然这种方法不是最优的,但它简单直观,易于理解。

方法二:哈希表

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable;  // 创建一个无序哈希表来存储数值及其索引
        for (int i = 0; i < nums.size(); ++i) {  // 遍历 nums 向量
            auto it = hashtable.find(target - nums[i]);  // 查找哈希表中是否存在 target - nums[i]
            if (it != hashtable.end()) {  // 如果找到了对应的键
                return {it->second, i};  // 返回对应的索引对
            }
            hashtable[nums[i]] = i;  // 将当前元素 nums[i] 和它的索引 i 存入哈希表
        }
        return {};  // 如果没有找到解,返回空向量
    }
};
  1. 定义类 Solution:

    cpp 复制代码
    class Solution {

    这行代码定义了一个名为 Solution 的类。这是 LeetCode 中常见的做法,用于组织解题代码。

  2. 声明成员函数 twoSum:

    cpp 复制代码
    public:
        vector<int> twoSum(vector<int>& nums, int target) {

    这是一个公开的成员函数 twoSum,它接受一个整数向量 nums 的引用和一个整数 target 作为参数,并返回一个包含两个整数的向量。这里的 nums 是问题描述中的整数数组,target 是目标值。

  3. 创建哈希表:

    cpp 复制代码
        unordered_map<int, int> hashtable;

    这行代码创建了一个 unordered_map,用来存储每个元素的值及其在数组中的索引。unordered_map 是 C++ 标准库中的容器,提供了类似哈希表的数据结构。

  4. 遍历数组:

    cpp 复制代码
        for (int i = 0; i < nums.size(); ++i) {

    这是循环,用于遍历整个 nums 向量。变量 i 作为索引从 0 开始递增。

  5. 查找补数:

    cpp 复制代码
            auto it = hashtable.find(target - nums[i]);

    这行代码尝试在哈希表中查找 target - nums[i]find 函数返回一个迭代器,指向哈希表中对应的键,如果键不存在则返回 end()

  6. 检查是否找到补数:

    cpp 复制代码
            if (it != hashtable.end()) {

    这行代码检查 it 是否不等于 hashtable.end(),即判断 target - nums[i] 是否存在于哈希表中。

  7. 返回索引对:

    cpp 复制代码
                return {it->second, i};

    如果找到了匹配的元素,就立即返回包含两个索引的向量 {it->second, i}。这里 it->secondtarget - nums[i] 对应的索引。

  8. 更新哈希表:

    cpp 复制代码
            hashtable[nums[i]] = i;

    如果没有找到匹配的元素,则将当前元素 nums[i] 和它的索引 i 存入哈希表中,以便后续的查找。

  9. 结束循环:

    cpp 复制代码
        }
  10. 如果没有找到匹配的元素对:

    cpp 复制代码
           return {};

如果遍历完所有的元素都没有找到匹配的元素对,那么返回一个空的向量。

这段代码实现了使用哈希表来解决"两数之和"问题,其时间复杂度为 O(n),空间复杂度同样为 O(n)。这种方法比暴力法更高效,因为它只需要遍历一次数组。

5. 测试结果

运行上述代码后,我们可以得到如下输出:

Indices: [0, 1]

这与题目要求的结果一致。

6. 总结

通过解决"两数之和"这个问题,我们不仅学会了如何利用哈希表来提高算法的效率,还掌握了处理数组问题的基本技巧。这对于后续更复杂的算法问题非常有帮助。希望这篇博客能帮助你更好地理解和掌握这道经典的 LeetCode 题目。


相关推荐
xiaoshiguang32 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡2 小时前
【C语言】判断回文
c语言·学习·算法
别NULL2 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇3 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
CYBEREXP20084 小时前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
yuanbenshidiaos4 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos4 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习4 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA4 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
tianmu_sama4 小时前
[Effective C++]条款38-39 复合和private继承
开发语言·c++