股票最大收益问题+最大子数组之和问题

最近在复习算法考试,往年题目中有一些题目自己是之前不会的,整理一下,算是学习了。

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

猜你喜欢

转载自blog.csdn.net/q_all_is_well/article/details/80875944
今日推荐