数据结构--LeetCode专题练习 Day3

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
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值