Leetcode->1 两数之和

这篇博客详细解析了LeetCode中第1题‘两数之和’的解题思路,包括暴力枚举和哈希表两种方法。暴力枚举的时间复杂度为O(n^2),而哈希表能将复杂度降低到O(n)。博主还分享了关于C++中vector作为函数参数的注意事项,以及在Linux下避免控制台立即关闭的方法。最后提到了unordered_map的特性及其与map的区别。
摘要由CSDN通过智能技术生成

1)两数之和

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

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

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

示例 :

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

方法一:暴力枚举

  1. 枚举在数组中所有的不同的两个下标的组合
  2. 逐个检查它们所对应的数的和是否等于target

思路及算法

最容易想到的方法是枚举数组中的每一个数 x,寻找数组中是否存在 target - x。

当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x 之前的元素都已经和 x 匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在 x 后面的元素中寻找 target - x。

复杂度分析

  • 时间复杂度:O(n^2),这里n为数组长度,最坏情况下数组中任意两个数都要被匹配一次。
  • 空间复杂度:O(1),只用到常数个临时变量
#include <vector>
#include <iostream>
using namespace std;

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[i] + nums[j] == target) {
                    return {i, j};
                }
            }
        }
        return {};
    }
};

int main()
{
	int target = 9;
	Solutiont two;
	
	vector<int> arr = { 2, 7, 11, 15};
	
	cout << "[" << two.twoSum(arr, target)[0] << ","<<two.twoSum(arr, target)[1] << "]" << endl;
	//pause();
	return 0;
}

方法二:哈希表
思路及算法

注意到方法一的时间复杂度较高的原因是寻找 target - x 的时间复杂度过高。因此,我们需要一种更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出它的索引。

使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N)降低到 O(1)。

这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。

#include <iostream>  
#include <unordered_map>  
#include <vector>
using namespace std; 

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable;
        for (int i = 0; i < nums.size(); ++i) {
            auto it = hashtable.find(target - nums[i]);
            if (it != hashtable.end()) {
                return {it->second, i};
            }
            hashtable[nums[i]] = i;
        }
        return {};
    }
};

int main()
{
	int target = 9;
	Solution two;
	
	vector<int> arr = { 2, 7, 11, 15};
	
	cout << "[" << two.twoSum(arr, target)[0] << ","<<two.twoSum(arr, target)[1] << "]" << endl;
	//pause();
	return 0;
}

复杂度分析

时间复杂度:O(N),其中 N是数组中的元素数量。对于每一个元素 x,我们可以 O(1)地寻找 target - x。

空间复杂度:O(N),其中 N 是数组中的元素数量。主要为哈希表的开销。

小记:

1)当vector当作形参输入到函数时,有两种方法:

vector<int>& nums;
vector<int> nums;

带&表示传入函数的是vector的引用(即物理位置),函数内部对vector改动,vector就会改变;
不带&表示传入的是vector的复制品(开辟了另一块位置),函数内部对其改动,不会影响原本的vector;

vector nums:nums是一个容器变量,容器名称为vector,容器内存的数据为int型
vector &nums:nums为一个引用,引用的内容是vector这个容器内部存放的整型数据

vector具体用法参见:https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html

2)linux下运行c++程序时,希望控制台不会输出后马上消失。

在windows系统下,用如下语句:

#include

system(“pause”);

发现在linux系统下会出现如题的错误,这是因为linux不认识 system(“pause”); 这条语句,改为:

#include <unistd.h>

pause();

即可在linux系统下实现保留控制台的效果。

3)unordered_map

无序映射(Unordered maps)是用于存储键值和映射值组合成的元素的关联容器,并允许基于其键快速检索各个元素。在unordered_map中,键值通常用于唯一地标识元素,而映射值是具有与该键关联的内容的对象。键的类型和映射的值可能会有所不同。

unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此,其元素的排列顺序是无序的。

与map对比

map

优点:

有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作;

红黑树,内部实现一个红黑树使得map的很多操作在O(lgn)的时间复杂度下就可以实现,因此效率非常的高。

缺点:空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间

应用场景:对于那些有顺序要求的问题,用map会更高效一些

unordered_map

优点:因为内部实现了哈希表,因此其查找速度非常的快
缺点:哈希表的建立比较耗费时间
应用场景:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map

总结

内存占有率的问题就转化成红黑树 VS Hash表,还是unordered_map占用的内存要高;
但是unordered_map执行效率要比map高很多;
对于unordered_map或unordered_set容器,其遍历顺序与创建该容器时输入的顺序不一定相同,因为遍历是按照哈希表从前往后依次遍历的。

使用:
unordered_map的用法和map是一样的,提供了 insert,size,count等操作,并且里面的元素也是以pair类型来存贮的。其底层实现是完全不同的,上方已经解释了,但是就外部使用来说却是一致的。

#include <iostream>  
#include <unordered_map>  
#include <map>
#include <string>  
using namespace std;  
int main()  
{  
	//注意:C++11才开始支持括号初始化
    unordered_map<int, string> myMap={{ 5, "张大" },{ 6, "李五" }};//使用{}赋值
    myMap[2] = "李四";  //使用[ ]进行单个插入,若已存在键值2,则赋值修改,若无则插入。
    myMap.insert(pair<int, string>(3, "陈二"));//使用insert和pair插入
  
	//遍历输出+迭代器的使用
    auto iter = myMap.begin();//auto自动识别为迭代器类型unordered_map<int,string>::iterator
    while (iter!= myMap.end())
    {  
        cout << iter->first << "," << iter->second << endl;  
        ++iter;  
    }  
	
	//查找元素并输出+迭代器的使用
    auto iterator = myMap.find(2);//find()返回一个指向2的迭代器
    if (iterator != myMap.end())
	    cout << endl<< iterator->first << "," << iterator->second << endl;  
    system("pause");  
    return 0;  
}  

输出:

3,陈二
2,李四
5,张大
6,李五

2,李四
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值