菜狗题解:双指针法+pair (C++)——力扣1.两数之和

274 阅读1分钟

原题链接 1. 两数之和

解题思路

看到题面,我们可以想到可以使用双指针法解决这个问题。 在一个升序数组p[N]中,设置指针i和指针j,i从左向右遍历,j从右向左遍历, 假如p[i] + p[j] > 目标值的话,我们就让j指针向左移动; 假如p[i] + p[j] < 目标值的话,我们就让i指针向右移动; 假如p[i] + p[j] = 目标值我们的目的就达成啦,退出循环并返回i, j(数组下标)就行啦。

但是,本题中所给的数组居然是乱序的,那我们就需要先给它排好序,但聪明的同学肯定想到了:排完序之后数组下标岂不是都乱了?题目需要返回它们原来的数组下标呀。

这个时候,我们就可以使用pair了,由于它本质上就是一个可以存两个相对应数据的结构体,其实也可以自己实现一个结构体解决(但我太懒了)。

我们可以用pair的第一个位置存数组元素,第二个位置存每个数组元素对应的下标,这样的话,我们在给数组元素们排完序后,它们原来的下标也会跟着自己对应的数组元素变动,之后我们就可以轻松地返回它们啦。

举个栗子

  • 输入:nums = [3,2,7,15,11], target = 10
  • 输出:[0,2]

p数组中保存的是这样的:

  • 3 0————p[0]
  • 2 1————p[1]
  • 7 2————p[2]
  • 15 3————p[3]
  • 11 4————p[4]

排了序之后是这样的:

  • 2 1————p[0]
  • 3 0————p[1]
  • 7 2————p[2]
  • 11 4————p[3]
  • 15 3————p[4]

双指针判断过程是这样的:

  • 2 + 15 > 10 ————j指向11 4
  • 2 + 11 > 10 ————j指向7 2
  • 2 + 7 < 10 ————i指向3 0
  • 3 + 7 = 10 ————成功了!退出循环
  • 返回0和2

时间复杂度

可以看出,两个指针相向运动,最多在相互碰到后停下,也就是仅遍历了一遍数组,因此时间复杂度是O(n)

最后给一下力扣的通过详情,还是挺有成就感的嘿嘿 E0A79C3D111A98F5A598CECEDF6BC849.png

代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
            pair<int, int> p[nums.size()];//最好再加个10啥的防止RE

            for(int i = 0; i < nums.size(); i++) p[i]={nums[i], i};//给p数组的第一个和第二个位置赋值,第一个位置存数组元素,第二个位置存它们的下标

            sort(p , p + nums.size());//给p数组的第一个位置(数组元素)排序

            int i = 0, j = nums.size() - 1;//两个指针i和j,i从左向右遍历,j从右向左遍历
            while(i < j)
            {
                while(p[i].first + p[j].first > target) j--;
                while(p[i].first + p[j].first < target) i++;
                if(p[i].first + p[j].first == target) break;
            }
            
            return {p[i].second, p[j].second};//返回我们找到的两个元素在排序之前的数组下标
    }
};