今天英文面试的时候碰见的题目,倒是不难,就是稍微变形之后,一时没想起来。
n天股票价格的信息,只能买卖一次,问什么时候买卖利润最大。这道题真的是太过经典了,但是面试的时候虽然答出来了,但是解释的不是很好,一方面是因为英文面试所以不是很擅长表述,另外一方面解释的不够有逻辑性,认为面试官很多都知道的。可以如下解释:
- 这道题给形式化之后相当于找出一个i,j(i< j)使得nums[j]-nums[i]值最大
- 那么我们可以把原来的数组转化成为一个新的数组:差分数组。d[i] = nums[i+1]-nums[i],而 ∑mi=ndi=nums[m+1]−nums[n]
- 所以原问题就变成了,找出差值数组的最大子段和
- 这是一道动态规划可以做的题目
int f(vector<int> &nums){
int mark = 0;
int max_mark = 0;
vector<int> d(nums.size()-1)
for(int i=0;i<nums.size()-1;i++){
d[i] = nums[i+1]-nums[i];
}
for(int i=0;i<d.size(),i++){
if(mark+d[i]<0)
continue;
else
mark += d[i];
max_mark = max(max_mark,mark);
}
return max_mark;
}
我就是按照上面写法写的程序,不过面试官好像一直不是很明白其中的原理,因为用英文,所以我解释的也不是很清楚。下次可以注意发现面试官不是很理解的【尤其是欧美的面试官,一定不要跳跃太大】
PS.后来跟舍友聊起来,舍友说转化成最大字段和的问题略麻烦了,还是直接用dp,储存一个当前情况下,最小低的点即可,其实跟最大字段和原理一样的,只不过不用另开一个数组了,降低了空间复杂度。解法如下:
int maxProfit(vector<int>& prices) {
if(prices.size() == 0)
return 0;
int res = 0;
int low_p = prices[0];
for(int i=0;i<prices.size();i++){
if(prices[i] < low_p){
low_p = prices[i];
}
res = max(res,prices[i]-low_p);
}
return res;
}
然后面试官又问了一个变形,就是「如果这个人购买股票的资金量是一定的,还是只能买卖一次,那么如何购买才能使得利润最大?」当场想了一下没有想起来,回来之后跟舍友提起来,才明白这道题如何做。
即用log即可,还是转换成差分数组,但是这次不是相减了,而是相除,即找出最大字段乘积,且每个子段中每一项都是大于0的。【如果这道题不用差分来做的话,跟上面一题一样,都是保存一个最小的即可】
用后一种思路
int maxProfit(vector<int>& prices) {
if(prices.size() == 0)
return 0;
int res = 1;
int low_p = prices[0];
for(int i=0;i<prices.size();i++){
if(prices[i] < low_p){
low_p = prices[i];
}
res = max(res,prices[i]/low_p);
}
return res;
}
用转化成最大字段和的问题,就是两两做除法,然后取log,然后再考虑一个最大字段和的问题。
double f(vector<int> &nums){
double mark = 0;
double max_mark = 0;
vector<double> d(nums.size()-1)
for(int i=0;i<nums.size()-1;i++){
d[i] = log(nums[i+1]/nums[i]);
}
for(int i=0;i<d.size(),i++){
if(mark+d[i]<0)
continue;
else
mark += d[i];
max_mark = max(max_mark,mark);
}
return exp(max_mark);
}
其实这个变形时非常简单的,但是当时却一直没有想出来,说明自己的应变能力还是得加强,另外一点就是面试的时候不要太紧张,好好分析题意。相信面试问到的问题都不难的。