原文链接;【LeetCode学习计划】《数据结构入门-C++》第2天 数组_Wang_Xin_Ling的博客-CSDN博客
目录
方法2:哈希表方法1中时间复杂度较高的原因是内层寻找target-x的复杂度较高,
88. 合并两个有序数组LeetCode: 88. 合并两个有序数组
1. 两数之和
LeetCode: 1. 两数之和
题目:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
思路: 我们先找到一个数,我们设为x,则另外的一个数就是target - x
于是我们可以使用两重循环,外层确定一个
x
,内层寻找target-x
方法一:暴力破解
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
const int n = nums.size();
for(int left = 0;left < n;left++)
{
for(int right = left +1;right<n;right++)
{
if(nums[left] + nums[right] ==target)
{
return {left,right};
}
}
}
return {};
}
};
方法2:哈希表
方法1中时间复杂度较高的原因是内层寻找target-x的复杂度较高,
而使用哈希表,可以使查找target-x的时间复杂度从O ( n ) ——> O(1)。
主要是思路:
对于每一个x,先查找target-x是否在哈希表中,若在则返回答案。然后把x插入到哈希表中。
解析
1.什么是vector?
向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。2.c++的容器——unordered_map,它是一个关联容器,内部采用的是hash表结构,拥有快速检索的功能 参考文章 STL—unordered_map 哈希表_ZS_Wang_Blogs的博客-CSDN博客
3.auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end())
return {it->second, i};
hashtable[nums[i]] = i;1)it->first和it->second相当于键和值 对应map<int,int> 就是类似python中的字典
2)hashtable[nums[i]]=i相当于插入操作
3)find函数返回的是一个迭代器(就是索引)
4)it是一个指针 存了哈希表每一项的信息
5)auto it = hashtable.find(target - nums[i]); if (it != hashtable.end())
这两个组合在一起的意思是 元素如果在哈希表中
则 证明找到return 键值对 和 i(就是x的索引)
这几行代码总体意思就是找到 target - x 元素的下标
#include<vector>
#include<unordered_map>
using std::unordered_map;
using std::vector;
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 {};
}
};
88. 合并两个有序数组
LeetCode: 88. 合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
方法1:合并后排序
最暴力的方法就是把nums2
的所有元素先插入到nums1
的后面,然后对nums1
进行排序
#include<vector>
#include<algorithm>
using namespace std;
class Solution
{
public:
void merge(vector<int> &num1,int m,vector<int> &num2,int n)
{
for (int i = 0;i<n;i++)
{
num1[m+i] = num2[i];
}
sort(num1.begin(),num1.end());
}
};
方法2:双指针
题目中提到两个数组都是已排序好的,于是我们在各数组的起始项设置一个指针,这样我们就能从小至大遍历2个数组了。每次遍历,将两个指针指向的更小的那个值存入一个新数组ans
。最后将整个ans
复制到nums1
中即可
字有点丑,博主在坚持每天练字了
#include <vector>
using namespace std;
class Solution
{
public:
void merge(vector<int> &nums1, int m, vector<int> &nums2, int n)
{
int p1 = 0, p2 = 0, p = 0;
int *ans = new int[m + n];
while (p1 < m && p2 < n)
{
if (nums1[p1] < nums2[p2])
{
ans[p] = nums1[p1];
p1++;
p++;
}
else
{
ans[p] = nums2[p2];
p2++;
p++;
}
}
while (p1 < m)
{
ans[p] = nums1[p1];
p1++;
p++;
}
while (p2 < n)
{
ans[p] = nums2[p2];
p2++;
p++;
}
for (int i = 0; i < m + n; i++)
{
nums1[i] = ans[i];
}
}
};
方法3:逆向双指针
方法2中需要用到中间数组的根本原因是:我们在确认nums1每个位置最终的元素时,又要保持原数组nums1不变。
而方法3的入手点在于:nums1数组的后半部分是无效值,也就是说这一部分的值是不用维护的。这样一来,我们可以在nums1和nums2数组的末项处各设置一个指针,每次将更大的元素存入nums1,这样就不会覆盖掉nums1中任何未被遍历的值,而且也省去了用于维护的中间数组。
字有点丑,博主在坚持每天练字了
#include <vector>
using namespace std;
class Solution
{
public:
void merge(vector<int> &nums1, int m, vector<int> &nums2, int n)
{
int p1 = m - 1, p2 = n - 1, p = m + n - 1;
while (p1 >= 0 && p2 >= 0)
{
if (nums1[p1] < nums2[p2])
{
nums1[p] = nums2[p2];
p2--;
p--;
}
else
{
nums1[p] = nums1[p1];
p1--;
p--;
}
}
while (p1 >= 0)
{
nums1[p] = nums1[p1];
p1--;
p--;
}
while (p2 >= 0)
{
nums1[p] = nums2[p2];
p2--;
p--;
}
}
};