精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
算法面試題:草坪修整

來自公眾號:小k算法 (ID:xiaok365)

作者:小K



01
故事起源
給定一個草坪區間的集合,為使區間互不重疊,最少需要移除多少個區間?


簡單描述如下圖,最少移除多少個區間,可以使剩余的區間不重疊。
注:
1、區間終點一定大于起點;
2、區間[1,2]和[2,3]接觸,但不重疊。



02
分析
題目求最少需要移除多少個,其實可以轉換問題,變成最多有多少個區間不重疊。
很多時候不容易直接求解時,都可以嘗試反向思考,這個技巧非常重要。

所以現在問題就是求最多有多少個區間,使他們落在x軸上不重疊。



03
最終狀態法
這里給大家介紹一種非常重要的思考方法,小K稱之為“最終狀態法”。其本質就是先思考最終要得到的狀態,或者說正確結果應該是什么樣子。

比如這個問題,假設我們已經求出了最優解,那這個最優解,一定是所有的區間中的k個區間,他們能平鋪在數軸上且不重疊。下面的藍色就是我們的答案。


如果我在中間某個位置切一刀,分成兩個子問題?,F在我問你:左邊區間中的解,是否仍然是左邊子問題的最優解呢?


可以用反證法,先假設它不是最優解,那就意味著左邊一定還有更優的解,比如下面這樣,左邊可以選出3個區間。


如果再把2個子問題組合起來,那整個問題的最優解應該是4個區間,這和我們之前假設的藍色是最優解矛盾了。說明分割子問題后,子問題的最優解也一定包含在整個問題的最優解中。

反過來,我們求出了子問題的最優解,就可以遞推出大問題的最優解,這就是動態規劃的思想。



04
動態規劃
子問題是沿著數軸進行擴大的,有嚴格的順序關系,所以先對區間進行排序。
設f[i]表示前i個區間中,選擇第i個區間作為最后一個區間時的最優解,則f[i]=max(f[j])+1,其中區間j與區間i無重疊。
最大的f[i]就是我們要求的最優解。


通過遞推公式發現,這個模型跟最長上升子序列很像,如果我們把所有的區間繞起點逆時針旋轉90度如下,這不就是一個變種的LIS問題了嗎。


LIS問題可以看成是所有的區間起點都是0,只要求終點要大于之前的終點,而這個問題可以看成區間的起點都不一樣,且要求每個區間的起點要大于之前區間的終點。

那他們之間的區別又有哪些呢?  

1、LIS問題不能排序,因為每個位置都是一個點,所以必須在原來的順序上,找出最大遞增的數量?,F在的問題都是區間,只求最終可以放下的數量,與順序無關,所以可以排序。

2、LIS問題的f[i]可以由前面任意一個f[j]轉移過來?,F在的問題如果排序完成后,其實不用枚舉前面所有的f[j],因為前面一定比后面的小,更大的數軸區間一定可以放下更大的數量啊,所以f[i]其實完全可以從最近的f[j]直接轉移。

比如下面,f[3]一定大于等于f[2]。


再換一種說法,如果在任何一個位置切一刀,前面是不是都是一個小規模的最優解。再加上前面的結論,每一步只需要從前一個轉移過來,這就意味著,每一步都是選擇最優的,而且最終得到的結果也是全局最優的。

那這不就是貪心的思想了嗎,每一步都選擇當前最優的即可。



05
貪心
動態規劃的核心其實是對枚舉的優化,它本質也是枚舉了所有的情況,只是消除了重復子問題,所以一定能得到最優解。
而貪心并不是計算了所有的情況,它是在每一步都選擇一個最優的,從而保證全局也是最優的。

5.1
貪心策略

選擇b比選擇a更優,因為可以留下更多的空間給其它的區間占領。


再考慮應該選擇哪一個區間作為第一個區間呢?
如果按區間終點排序,則選擇a比選擇b更優,因為從左向右求每一步的最優解時,選擇a可以給后面的區間留下更多的空間。同理如果按起點排序,就從右向左掃描求解即可。


5.2
貪心建模

按區間終點排序,從左向右依次求出每一步的最優解。如果當前區間的起點大于等于上一步選擇的終點,即可選擇當前區間,并重置最右側為當前區間的終點,否則放棄選擇。


5.3
代碼實現

vector<vector<int>> a(100vector<int>(20));
bool cmp(const vector<int> &u, const vector<int> &v) {
    return u[1] < v[1];
}
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> a[i][0] >> a[i][1];
    }
    a.resize(n);
    sort(a.begin(), a.end(), cmp);
    int ans = 1, right = a[0][1];
    for (int i = 1; i < n; ++i) {
        if (a[i][0] >= right) {
            right = a[i][1];
            ans++;
        }
    }
    cout << n - ans << endl;
    return 0;
}



06
總結
這個問題難度不大,但卻有很多可以思考的東西在里面,如果直接看問題肯定和LIS沒有任何聯系,但通過公式發現其本質還是有一些聯系在里面。類似的思想很常見,比如如果發現問題符合這種模型,那就又可以用之前寫過的一篇LIS問題的優化技巧,單調隊列+二分來進行模型的優化。當然算法問題不應太注重固定的套路模型,思考方法才是更重要的,以不變應萬變。
本文原創作者:小K,一個思維獨特的寫手。
文章首發平臺:微信公眾號【小K算法】。
本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
動態規劃算法入門,需要搞懂這5個問題
數組的最長遞增子序列
動態規劃(2)
貪心算法:買賣股票的最佳時機II
C 中vector的remove用法
Python|跳躍游戲
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 凤山县| 毕节市| 玉树县| 二连浩特市| 北流市| 南阳市| 迁西县| 江孜县| 吉安县| 德州市| 中西区| 开鲁县| 大新县| 保定市| 梧州市| 军事| 巢湖市| 天柱县| 鄂伦春自治旗| 城固县| 壶关县| 招远市| 垫江县| 丽江市| 黔西| 凌海市| 科技| 汶川县| 吴旗县| 泗洪县| 定远县| 西林县| 杭州市| 香河县| 柳林县| 西乌珠穆沁旗| 甘南县| 丹阳市| 呼玛县| 抚远县| 广河县|