【LeetCode】No.1 Two Sum

本文介绍LeetCode经典题目“两数之和”的多种高效解法,包括双层循环、哈希表及排序查找等,分析每种方法的时间与空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【原题】

Given an array of integers, find two numbers such that they add up to a specific target number.The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.You may assume that each input would have exactly one solution.

Input:numbers={2, 7, 11, 15}, target=9
Output:index1=1, index2=2

【翻译】

给定一个整数数组,找出其中两个数满足相加等于你指定的目标数字。要求:这个函数twoSum必须要返回能够相加等于目标数字的两个数的索引,且index1必须要小于index2。请注意一点,你返回的结果(包括index1和index2)都不是基于0开始的。你可以假设每一个输入肯定只有一个结果。例:

输入:numbers={2, 7, 11, 15}, target = 9

输出:index1 = 1, index2 = 2(不是基于0开始的)

【预备知识】

作为一名刷题新手,一见到自动生成的vector就懵了,所以做题之前我还是只能先去查阅了关于vector的资料。

一、vector向量

       平时写c++程序时极少使用到vector,它是C++中的一种数据结构与string相同,同属于STL(Standard Template Library,标准模板库)中的一种自定义的数据类型,相当于一个动态的数组我们无法知道自己需要的数组规模多大时来解决问题可以达到最大节约空间的目的

二、基本操作

   a.clear()                  移除容器中所有数据。

         a.empty()                 判断容器是否为空。

         a.erase(pos)            删除pos位置的数据

         a.erase(beg,end)     删除[beg,end)区间的数据

         a.front()                    传回第一个数据。

         a.insert(pos,elem)    在pos位置插入一个elem拷贝

         a.pop_back()            删除最后一个数据。

         a.push_back(elem) 在尾部加入一个数据。

         a.size()                    回容器中实际数据的个数。

         a.begin()                  返回指向容器第一个元素的迭代器即数组头的指针

         a.end()                      返回指向容器最后一个元素的迭代器即数组最后一个单元+1的指针


          vector<int> b(a.begin(), a.begin()+3) //a[0]a[3](共3个)作为向量b的初始值

         (a.begin(),a.begin()+3)表示向量起始元素位置到起始元素+3之间的元素位置

三、迭代器

       在元素的输出上还可以使用遍历器(又称迭代器)进行输出控制向量元素的位置便成为遍历器同时向量元素的位置也是一种数据类型,在向量中遍历器的类型为: vector<int>::iterator。遍历器不但表示元素位置还可以再容器中前后移动。

//元素全部输出
for(int i=0; i<a.size(); i++)
    cout<<a[i]<<" " ;
可以改写为:
vector<int>::iterator t ;
for(t=a.begin(); t!=a.end(); t++)
    cout<<*t<<" " ;

*t为指针的间接访问形式意思是访问t所指向的元素值。

四、特别注意:

(1)

vector <int > a;
int b = 5;
a.push_back(b);

此时若对b另外赋值时不会影响a[0]。往a中压入的是b的值,即a[0]=b,此时a[0]和b是存储在两个不同的地址中的,因此改变b的值不会影响a[0]。

(2)

vector <int*> a;
int *b;
b = new int[4];
b[0]=0;
b[1]=1;
b[2]=2;
a.push_back(b);
delete b;      //释放b的地址空间
for(int i=0; i <3; i++)
{
    cout<<a[0][i]<<endl;
}

此时输出的值并不是一开始b数组初始化的值,而是一些无法预计的值。因为是这里把一个地址(指针)压入向量a,因此释放了b的地址也就等于释放了a[0]的地址,因此a[0]数组中存放的数值也就不得而知了。

【解题思路】

单纯的想解出这道题当然直接使用两层循环就够了,时间复杂度为O(n^2),空间复杂度为O(1),我的代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> vec;
        for(int i=0;i<nums.size();i++){
            for(int j=i+1;j<nums.size();j++){  //防止同一个数自己相加,所以j要从i+1开始
                if(nums[i]+nums[j]==target){
                    vec.push_back(i+1);
                    vec.push_back(j+1);
                }
            }
        }
        return vec;
    }
};
【其他方法】

显然我的代码效率非常的低下,应该学会更好的解决此类问题:

(1)建立Hash表

       使用map<key, value>结构来存储给定数组nums对应的<numValeu, numIndex>。

       1)i=0,nums指向数值2,map为空肯定找不到符合条件的值,则将<2,0>加入到map中,即m[2]=0;

       2)i=1,nums的指针移到了第二个数值7,找2(=9-7),这时map中正好有key值为2的元组,则将map中找到的这个key值对应的value,再加上1(题中说了不从0开始)存入新的vector,再将nums指针指向的这个数的索引加1也存入vector;因为题中说只有一组结果,那么就可以break了。这时map中只有一个元素<2,0>。

      时间复杂度:O(n),空间复杂度:O(n),达到以空间换时间的目的。

class Solution{
public:
   vector<int> twoSum(vector<int>& nums, int target)
    {
        vector<int> v;
        map<int, int> m;
        for(int i = 0; i < nums.size(); i++)  //可不可以写++i?
        {
            if(m.find(target - nums[i]) != m.end())  //若找到目标数值,则将对应索引压入新的vector
             {
                 v.push_back(m[target - nums[i]] + 1);
                 v.push_back(i + 1);
                 break;		//跳出循环
             }
             m[nums[i]] = i;  //没有找到目标数值,把当前nums值压入map
         }
         return v;
     }
};
(2)先排序,后查找

       1)首先同样分配一个数组空间,将数据备份,以便获得索引值;

       2)将拷贝的数组排序;

       3)对排序后的数组,建立两个查找“指针”,一个在数组头,一个在数组尾部,依次相加比较,如果大于target,尾部向前移一位,如果小于target,头部向后移一位,直至有相等的情况或者头部与尾部交叉的情况发生;

       4)最后再扫描一遍原数组,获取这两个数字的索引。

       时间复杂度:O(nlogn)(取决于排序时间复杂度),空间复杂度:O(n)(取决于排序空间复杂度以及备份数组的空间复杂度)。

class Solution{
 public:
      vector<int> twoSum(vector<int>& nums, int target)
      {
          vector<int> v(nums);
          sort(v.begin(),v.end());
          int l = 0, r = v.size() - 1;
          while(l < r)
          {
             if(v[l] + v[r] == target)
                 break;
             else if(v[l] + v[r] > target)
                 --r;
             else
                 ++l;
          }
          //遍历原数组找对应的索引值
          vector<int> index;
          for(int i = 0, n = 2; i < nums.size(); i++)
             if(v[l] == nums[i] || v[r] == nums[i])
             {
                 index.push_back(i + 1);
                 if(--n == 0)
                     break;
             }
          return index;
     }
};

【运行结果】

LeetCode上这道题的Expected answer应该错了,应该为[2,3]


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值