【Lintcode】970. Big Business(配數學證明)

記錄演算法發表於2020-11-29

題目地址:

https://www.lintcode.com/problem/big-business/description

給定兩個陣列 a a a b b b a [ i ] a[i] a[i]代表商品 i i i的成本, b [ i ] b[i] b[i]代表商品的賣價。初始資金是 k k k,問通過交易,最後能達到的最大資金是多少。每個商品最多隻能買賣一次。

思路是貪心。直覺上來講,最貴的商品可能一下子買不起,那可以先買便宜的商品,賺了錢之後看看能不能再買更貴的商品。所以思路就是,先將所有商品按成本由低到高排序,然後依次買賣。如果到達某個商品發現買不起了,則退出迴圈。當然那些賣價小於等於買價的商品不用看,直接略過。

演算法正確性證明:
設兩個商品分別是 ( c 1 , s 1 ) (c_1,s_1) (c1,s1) ( c 2 , s 2 ) (c_2,s_2) (c2,s2),並且 c 1 < c 2 c_1<c_2 c1<c2,容易證明先買賣便宜的商品 1 1 1,賺到了錢再買賣商品 2 2 2,得到的最終的資金是一定更優於(或者一樣)先買賣商品 2 2 2後商品 1 1 1的,原因是商品 2 2 2有可能一下子買不起,而交易完商品 1 1 1後賺了錢,就有可能買得起了。所以如果某個最優解不是按這樣的順序交易的,我們總可以將最便宜的商品向前交換位置,每次交換位置都能得到最優解(因為交換完更優,而當前就是最優解了,所以更優解也是最優解),再由數學歸納法就能證明按成本從小到大的順序交易是最優的。

程式碼如下:

import java.util.ArrayList;
import java.util.List;

public class Solution {
    
    class Movie {
        int cost, price;
        
        public Movie(int cost, int price) {
            this.cost = cost;
            this.price = price;
        }
    }
    
    /**
     * @param a: The cost of the film
     * @param b: The price of the selling of the film
     * @param k: The principal
     * @return: The answer
     */
    public int bigBusiness(int[] a, int[] b, int k) {
        // Write your code here
        List<Movie> movies = new ArrayList<>();
        for (int i = 0; i < a.length; i++) {
            if (a[i] < b[i]) {
                movies.add(new Movie(a[i], b[i]));
            }
        }
        
        // 按成本排序
        movies.sort((m1, m2) -> Integer.compare(m1.cost, m2.cost));
    
        for (Movie movie : movies) {
        	// 買得起就買,賺的利潤,否則就說明當前及之後的電影都是買不起的,則退出迴圈
            if (k >= movie.cost) {
                k += movie.price - movie.cost;
            } else {
                break;
            }
        }
        
        return k;
    }
}

時間複雜度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空間 O ( n ) O(n) O(n)

相關文章