【線性 dp】A009_LC_規劃兼職工作(dp / 二分優化)

一、Problem

We have n jobs, where every job is scheduled to be done from startTime[i] to endTime[i], obtaining a profit of profit[i].

You’re given the startTime , endTime and profit arrays, you need to output the maximum profit you can take such that there are no 2 jobs in the subset with overlapping time range.

If you choose a job that ends at time X you will be able to start another job that starts at time X.
在這裏插入圖片描述

Input: startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
Output: 120
Explanation: The subset chosen is the first and fourth job. 
Time range [1-3]+[3-6] , we get profit of 120 = 50 + 70.

Constraints:

1 <= startTime.length == endTime.length == profit.length <= 5 * 10^4
1 <= startTime[i] < endTime[i] <= 10^9
1 <= profit[i] <= 10^4

二、Solution

方法一:

  • 定義狀態
    • f[i]f[i] 表示詢問到第 ii 份工作時,得到的最大報酬
  • 思考初始化:
    • f[0]=jobs[0].profitf[0] = jobs[0].profit
  • 思考狀態轉移方程
    • f[i]=max(f[i1],f[preJobID]+jobs[i].profit)f[i] = max(f[i-1], f[preJobID] + jobs[i].profit),對於第 i(i1)i (i \geqslant 1) 份工作,可以選擇不做也可以選擇做,做的話就要連着前一份工作
  • 思考輸出f[n]f[n]

開始寫的是這種,然後很不幸,過不了…

[1,1,1]
[2,3,4]
[5,6,4]
預期:6
輸出:11
class Solution {
    public int jobScheduling(int[] st, int[] et, int[] pf) {
        int n = st.length, f[] = new int[n];
        Job[] js = new Job[n];
        for (int i = 0; i < n; i++) js[i] = new Job(st[i], et[i], pf[i]);
        Arrays.sort(js, (e1, e2) -> e1.e - e2.e);

        int pre[] = new int[n];
        for (int i = 1; i < n; i++)
        for (int j = i-1; j >= 0; j--) if (js[j].e <= js[i].s) {
            pre[i] = j;
            break;
        }
        f[0] = js[0].p;
        for (int i = 1; i < n; i++) {
            f[i] = Math.max(f[i-1], f[pre[i]] + js[i].p);
        }
        return f[n-1];
    }
    class Job {
        int s, e, p;
        Job(int s, int e, int p) {this.s = s;this.e = e;this.p = p;}
        Job(){}
    }
}

原因是當某些工作的開始時間相同的話,只能選擇其中的一份,而下面下標從 1 開始運算的話,相當於增加了一份報酬爲 0 的假工作,使得第一份工作可以進行比較,而如果從 0 開始,那麼第一份工作將不可以比較。

class Solution {
    public int jobScheduling(int[] st, int[] et, int[] pf) {
        int n = st.length, f[] = new int[n+1];
        Job[] js = new Job[n+1];
        js[0] = new Job();
        for (int i = 1; i <= n; i++) js[i] = new Job(st[i-1], et[i-1], pf[i-1]);
        Arrays.sort(js, (e1, e2) -> e1.e - e2.e);

        int pre[] = new int[n+1];
        for (int i = 2; i <= n; i++)
        for (int j = i-1; j >= 1; j--) if (js[i].s >= js[j].e) {
            pre[i] = j;
            break;
        }
        f[1] = js[1].p;
        for (int i = 2; i <= n; i++) {
            f[i] = Math.max(f[i-1], f[pre[i]] + js[i].p);
        }
        return f[n];
    }
    class Job {
        int s, e, p;
        Job(int s, int e, int p) {this.s = s;this.e = e;this.p = p;}
        Job(){}
    }
}

複雜度分析

  • 時間複雜度:O(n2)O(n^2)
  • 空間複雜度:O(n)O(n)

方法二:二分優化

我們對 jobs 數組進行了排序,所以我們可以用二分來查找出工作 ii 的前一份可行的工作來優化 O(n2)O(n^2) 查找前一份工作。


複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章