350. 两个数组的交集 II
给定两个数组,编写一个函数来计算它们的交集。示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
说明:
输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
我们可以不考虑输出结果的顺序。
原始思路:
1.选出较短的数组 2.将短数组中的数值与长数组中的比较,输出相等的数值
(问题出在了 1.如何选较短的数组上,就是法二中的 intersect(nums2,nums1),但没有想到用hash 表去记录每个数值的出现次数;2.想到了用两个指针去比较数组,但没有想到要排序)
思路更正:
1.排序法
(1)创建两个指针i,j,分别指向数组首位
(2)创建一个临时栈stack用于存放结果集
(3)比较指针所指位置数值大小;两个值不等,小的后移;两个值相等,将交集压入栈后两指针后移
(4)一个数组遍历结束,代表两者之间不会再出现交集
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(),nums1.end());
sort(nums2.begin(),nums2.end());
int length1=nums1.size();
int length2=nums2.size();
vector<int>result;
int p1=0,p2=0;
while(p1<length1&&p2<length2){
if(nums1[p1]<nums2[p2]){
p1++;
}else if(nums1[p1]>nums2[p2]){
p2++;
}else{
result.push_back(nums1[p1]);
p1++;
p2++;
}
}
return result;
}
};//4ms 9.7MB
第二种写法:
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(begin(nums1),end(nums1));
sort(begin(nums2),end(nums2));
int i=0,j=0,k=0;
while(i<nums1.size()&&j<nums2.size()){
if(nums1[i]<nums2[i]){
++i;//指针i后移
}else if(nums1[i]>nums2[i]){
++j;//指针j后移
}else{
nums1[k++]=nums1[i++];//相等时,将数字添加到nums1(节省空间),指针后移
++j;
}
}
return vector<int>(begin(nums1),begin(nums1)+k);//返回nums1中前k个元素
}
};
2. hash表
map映射 映射关系:<元素,出现次数>
//同一个数字在两个数组中都可能出现多次-->使用hash表存储每个数字的出现次数
//对于一个数字,其在交集中出现的次数=该数字在两个数组中出现次数的最小值
//对较小的数组进行hash表的映射
//1.遍历第一个数组,在hash表中记录每个数字的出现次数
//2.遍历第二个数组,如果在hash表中存在这个数字,则将该数字添加到答案,并减少hash表中的对应次数
第一种写法:
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size()>nums2.size()){
return intersect(nums2,nums1); //交换nums2,nums1;使nums1为最小数组
}
//构造nums1的hash表
unordered_map<int,int>m;//hash表 m
for(int num:nums1){ //简化的循环写法
/*for (int i = 0; i < nums1.size();i++) {
int num = nums1[i];
*/
++m[num]; //num1中每个数值出现的次数
}
vector<int>intersection:
for(int num:nums2){ //遍历nums2
if(m.count(num)){
intersection.push_back(num);
--m[num]; //减少m中对应的元素计数,即hash表中数值减少
if(m[num]==0){
m.erase(num);//删除num
}
}
}
return intersection;
}
};
第二种写法:
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size()>nums2.size()){
return intersect(nums2,nums1); //交换nums2,nums1;使nums1为最小数组
}
//构造nums1的hash表
unordered_map<int,int>m;//hash表 m
for(int num:nums1){
++m[num]; //num1中每个数值出现的次数
}
int k=0;
for(int num:nums2){ //遍历nums2
int it=m.find(num);
if(it !=end(m)&&--it->second>=0){ //若存在且为正,拷贝到nums1[k]中对应元素的计数
nums1[k++]=num;
}
}
return vector(begin(nums1),begin(nums1)+k);//返回nums1中前k个元素
}
};
121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。( 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。)
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 10 5
0 <= prices[i] <= 10 4
原始思路:
1.确定哪天买入(与之前的数组比较是最小值);2.在买入日期的后面选择与之差最大的日期,即为卖出日期 ; 3.输出差值
(解释:一开始想的有点复杂了,认为当天无法知道第二天的股价,后来看了题解发现是直接遍历数组获得最大值和最小值)
思路更正:
1.暴力法 最容易想到,但超时
找出数组两数之差的最大值
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
int ans=0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
ans=max(ans,prices[j]-price[i];
}
}
return ans;
}
};
2.一次遍历
1.假设在第i天卖出; 2.用变量minprice记录历史最低价格,利润可得。
如何记录历史最低点-->遍历价格数组
class Solution {
public:
int maxProfit(vector<int>& prices) {
int inf=1e9;
int minprice=inf,maxprofit=0;
for(int i=0;i<prices.size();i++){
int price=prices[i]; //假设在第i天卖出 简化写为:int price:prices 时间:92ms
maxprofit=max(maxprofit,price-minprice);
minprice=min(price,minprice);
}
return maxprofit;
}
};//112ms 91.1MB
3.动态规划
1.确定dp数组的表示含义
2.dp(i)和dp(i-1)-->状态转移方程
3.确定初始条件,dp(0)
解:
1.dp[i]表示前i天的最大利润
2.状态转移方程:始终要使利益最大化
dp[i]=max(dp[i-1],price[i]-minprice)
3.dp[0]=0
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=price.size();
if(n==0) return 0; //边界条件
int minprice=prices[0];
vector<int>dp(n,0);
for(int i=1;i<n;i++){
minprice=min(minprice,price[i]);
dp[i]=max(dp[i-1],price[i]-minprice); //状态转换方程
}
return dp[n-1];//范围索引0~n-1
}
};