最近在复习算法考试,往年题目中有一些题目自己是之前不会的,整理一下,算是学习了。
题目1:Given an array A[0...n-1]of numbers,the problem is to find 0<=i<=j<n,such that A[j]-A[i] is maximized(gain)
Story:You learned what the stock price will be for next n days,on condition you can buy once(on day i) and sell once(on day j).
(a)Brute-force algorithm:Describe a naive, brute-force algorithm that takes A as input and outputs the maximum gain.
(b)Describe an O(nlgn)time algorithm for this problem.
(c)Describe an O(n)time algorithm for this problem.
首先,这是leetcode上股票问题的改编版本。其中有可卖出多次,可卖出一次的两种题型。第三种太难了。目前没有求虐的打算。
首先看第一种,卖出一次的情况。
暴力的思想算法时间复杂度为O(n^2),第一次遍历数组,将每一个元素看做是买进的,然后从下一个元素开始遍历,找出利润最大的即可。
public static int Brute_MaxProfit(int []arr) throws Exception {
if (arr.length==0||arr==null){
throw new Exception("数组异常");
}
int max=Integer.MIN_VALUE;
int start=0;
int end=0;
for (int i=0;i<arr.length;i++){
start=arr[i];
for (int j=i+1;j<arr.length;j++){
end=arr[j];
max=Math.max(max,start-end);
}
}
return max;
}
第二种,要求时间复杂度为O(n*lg^n),看到涉及到lg,我们大概可以想到分治的思想吧。那么这里应该是将买进和卖出的位置进行了划分,主要可以考虑一下几种情况,1.n/2之前买入,n/2之后卖出。2.n/2之前买入,n/2之后卖出。3.n/2之后买入,n/2之后卖出。
public static int Optimal1_MaxProfit(int [] arr,int start,int end)throws Exception {
if (arr.length==0||arr==null){
throw new Exception("数组异常");
}
int mid=start+(end-start)/2;
int profit1=Optimal1_MaxProfit(arr,start,mid);
int profit2=Optimal1_MaxProfit(arr,mid+1,end);
int profit3=MergeProfit(arr,start,mid,end);
return Math.max(profit1,Math.max(profit2,profit3));
}
private static int MergeProfit(int[] arr, int start, int mid, int end) {
int i=start;
int min=arr[start];
int j=mid+1;
int max=arr[mid+1];
for (;i<mid;i++){
if (arr[i]<min){
min=arr[i];
}
}
for (;j<end;j++){
if (arr[j]>max){
max=arr[j];
}
}
return max-min;
}
要求3:时间复杂度要求为O(n),思路与前面类似。设置标志位,用来记录最小值和最大利润,边维护边计算。需要注意的是一定是先买入之后才能卖出。所以一定要i<j。这里是确认无误的结果。
public class Solution {
public int maxProfit(int prices[]) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice)
minprice = prices[i];
else if (prices[i] - minprice > maxprofit)
maxprofit = prices[i] - minprice;
}
return maxprofit;
}
}
题目2:Find a O(n) algorithm that,given an array of n integers (possibly some of the elements negative),determines the contiguous sub-array within the array of numbers which has the largest sum.For example,for the sequence of values -2,1,-3,4,-1,2,1,-5,4;the contiguous sub-array with the largest sum is 4,-1,2,1,with sum 6.
题目的要求是返回最大连续数组之和,其中数组中有负数。所以我们不能认为越长越好。那么该如何确定最优解呢。
首先,我们不妨将数组分为三部分,A[0...L].A[L+1...R],A[R+1,...,end].所以这里我们不妨假设答案是A[L+1,... ,R]中的和,所以一定有A[0,...,L]的和是负数。同样的,A[R+1,...,end]中A[R+1]一定是一个负数。这样,我们基本定位了一个思路。因为前面的和是负数。所以我们可以使用一个标志位cur,来从前向后累加。当cur<0的时候,我们就放弃前面的和,从下一个位置开始重新统计。
public static int MaxSum(int []arr)throws Exception {
if (arr.length==0||arr==null){
throw new Exception("数组异常");
}
int max=Integer.MIN_VALUE;
int cur=0;
for (int i=0;i<arr.length;i++){
cur+=arr[i];
max=Math.max(cur,max);
cur=cur<0?0:cur;
}
return max;
}