LeetCode 502. IPO

这周老师讲解了一下贪心算法(greedy),我科对贪心的解释是

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

大概就是这样,按照惯例,我们找到了在LeetCode上tag为greedy的题目中找到了这一道难度为hard通过率最高的题,也就是这一道题目为IPO的题,下面是题目

--------------------------题目在此-------------------------

Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Capital, LeetCode would like to work on some projects to increase its capital before the IPO. Since it has limited resources, it can only finish at most k distinct projects before the IPO. Help LeetCode design the best way to maximize its total capital after finishing at most k distinct projects.

You are given several projects. For each project i, it has a pure profit Pi and a minimum capital of Ci is needed to start the corresponding project. Initially, you have W capital. When you finish a project, you will obtain its pure profit and the profit will be added to your total capital.

To sum up, pick a list of at most k distinct projects from given projects to maximize your final capital, and output your final maximized capital.

Example 1:

Input: k=2, W=0, Profits=[1,2,3], Capital=[0,1,1].

Output: 4

Explanation: Since your initial capital is 0, you can only start the project indexed 0.
             After finishing it you will obtain profit 1 and your capital becomes 1.
             With capital 1, you can either start the project indexed 1 or the project indexed 2.
             Since you can choose at most 2 projects, you need to finish the project indexed 2 to get the maximum capital.
             Therefore, output the final maximized capital, which is 0 + 1 + 3 = 4.

Note:

  1. You may assume all numbers in the input are non-negative integers.
  2. The length of Profits array and Capital array will not exceed 50,000.
  3. The answer is guaranteed to fit in a 32-bit signed integer.
-------------------------题解在此------------------------------

老规矩吧,自认为英语比我好的小伙伴自行翻译,忽略背景知识,我对这所谓的IPO是真的一窍不通,我们直接看重要的部分吧,给了两个整数W,K,两个向量Profits和Capital,Profits和Capital是一一对应的,即我花费Capital【i】这么多本金就可以得到Profits【i】这么多纯利益,我最多选择k个不同的项目,也就是选择不同的i,我的初始本金是W,当然了,当我获得纯利益后可以直接加到W中,并继续执行,得到一个最大的W。

题目看起来挺复杂的,既然是贪心算法,现在就是要选择一个策略了,策略倒是挺容易想的,每次我找到满足我当前本金W能够运营的所有的项目,选一个纯利益最大的就好了。这种策略看起来就够贪心了,但是我没想到的是这道题还要更贪。

我前后使用了三种方法来解决这道题,有的新观众可能就震惊了,没有想到我一个大学生还保持着初高中对知识的初心,追求一题多解。当然了,老观众是知道我的,我这么懒一个人怎么可能干这么无聊的事情,所以答案就是前两次错了,我要说的也就是这道题真正贪心的地方,我的前两种方法超时了!!!对,你没有看错,超时了。所以这道题是真的贪心啊。

我的第一种方法的思路是这样的,建立一个Capital到一个Capital对应的所有的Profits所组成的一个stack,这个stack是一个有序的,即最上面的元素是最大的,然后再对Capital排序,每次我只要找到所有小于W的Capital对应的stack的顶端元素的最大值,加到W上,并且将这个元素弹出stack。就是这样的一种方法在倒数第二个点超时了,预处理的时间复杂度是O(n),后面查询的时间复杂度O(n^2)

第二种方法和第一种主要思路是差不多的,进行了一点常数级优化,先用桶排序对Capital和Profits组成的一个pair进行排序,这样一来Capital从小到大排,相同Capital对应的Profits从大到小排,再用队列来存一个Capital对应的所有Profits,并此时Profits已经是从大到小排列了。与第一种方法同样查询,依旧在倒数第二个点超时了。

这是我就已经意识到了问题的所在了,就是查询是那O(n^2)的复杂度,不能保证Capital越大,对应的Profits也越大,所有只能从最小的Capital找到小于等于W的所有Capital,再找这个区间内所有Profits最大的一个,我能怎么办?我也很无奈啊。既然已经发现问题了,那么就想办法解决问题呗,之前想的都是每查询完一次下一次就重新查询,直接导致了O(n^2)的时间复杂度,那么我要是只是遍历一次Capital的向量复杂度应该就OK了吧,那么查询问题怎么解决呢?我需要每次都能得到目前访问位置之前的最大的一个Profits,而且还要在使用完后删除。答案就是优先队列,或者说集合也可以,这里我选择了使用集合,预处理我也想了一个新的更直观的方法来做。下面直接上代码吧。

------------------------------下面是代码------------------------

#include <iostream>
#include <vector>
#include <memory.h>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
class Solution {
public:
	static bool cmp(pair<int,int>a,pair<int,int>b)
	{
		return a.first<b.first;
	}
    int findMaximizedCapital(int k, int W, vector<int>& p, vector<int>& c) {
        vector<pair<int,int> >indexc;//建立Capital到源向量下标的映射 
        int t=p.size() ;
        for(int i=0;i<t;i++)
        {
        	pair<int,int> temp;
        	temp=make_pair(c[i],i);
        	indexc.push_back(temp); 
		}
		stable_sort(indexc.begin() ,indexc.end(),cmp);//使得Capital从小到大排列 
		priority_queue<int> pp;
		int i=0;
		while(k--)
		{
			for(;i<indexc.size() &&indexc[i].first<=W;i++)
			{
				int index=indexc[i].second;
				int pi=p[index];
				pp.push(pi);
			}
			if(pp.empty())
			break;//如果优先队列空则表明没有满足W的Capital了,这个时候也只能结束了 
			W+=pp.top();
			pp.pop();//删除当前最大元素 
		}
		return W; 
    }
};
代码很简短也很好理解,这道题真的是让我体会到了什么叫贪心,你说你都贪心了还要时间复杂度低,我是真的服。使用优先队列后整个的时间复杂度应该就变为了O(nlogn)的复杂度了,不过好歹是终于已经过了,希望小伙伴不要像我一样掉到坑里去了。这次的题解就到这里了。

----------------------------------------手动分割线----------------------------------

see you next illusion




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值