區(qū)間問(wèn)題

區(qū)間問(wèn)題

Ⅰ 解題框架

? 所謂區(qū)間問(wèn)題,就是線段問(wèn)題,讓你合并所有線段、找出線段的交集等等。主要有兩個(gè)技巧:
? 1、排序。常見(jiàn)的排序方法就是按照區(qū)間起點(diǎn)排序,或者先按照起點(diǎn)升序排序,若起點(diǎn)相同,則按照終點(diǎn)降序排序。
? 2、畫(huà)圖。就是說(shuō)不要偷懶,勤動(dòng)手,兩個(gè)區(qū)間的相對(duì)位置到底有幾種可能,不同的相對(duì)位置我們的代碼應(yīng)該怎么去處理。

Ⅱ 相關(guān)習(xí)題

1、刪除覆蓋區(qū)間(LeetCode 1288)

? 給你一個(gè)區(qū)間列表,請(qǐng)你刪除列表中被其他區(qū)間所覆蓋的區(qū)間。只有當(dāng) c <= a 且 b <= d 時(shí),我們才認(rèn)為區(qū)間 [a,b) 被區(qū)間 [c,d) 覆蓋。在完成所有刪除操作后,請(qǐng)你返回列表中剩余區(qū)間的數(shù)目。

? 首先排序:按照起點(diǎn)升序排序,起點(diǎn)相同則按照終點(diǎn)降序排序,使用lamda表達(dá)式

//將intervals按照起點(diǎn)升序排序,起點(diǎn)相同則按照終點(diǎn)降序排序
        Arrays.sort(intervals,(a,b)->{
            if (a[0] == b[0]) return b[1]-a[1];
            return a[0]-b[0];
        });
image-20201213135848220

排序之后,兩個(gè)相鄰區(qū)間只可能有如下三種相對(duì)位置:

image-20201213135923221

? 對(duì)于這三種情況,我們應(yīng)該這樣處理:對(duì)于情況一,找到了覆蓋區(qū)間。對(duì)于情況二,兩個(gè)區(qū)間可以合并,成一個(gè)大區(qū)間。對(duì)于情況三,兩個(gè)區(qū)間完全不相交。

class Solution {
    public int removeCoveredIntervals(int[][] intervals) {
        int num = intervals.length;
        //將intervals按照起點(diǎn)升序排序,起點(diǎn)相同則按照終點(diǎn)降序排序
        Arrays.sort(intervals,(a,b)->{
            if (a[0] == b[0]) return b[1]-a[1];
            return a[0]-b[0];
        });
        //記錄線段的左右邊界,初始值就是第一條線段的起點(diǎn)和終點(diǎn)
        int left = intervals[0][0];
        int right = intervals[0][1];

        //開(kāi)始覆蓋
        for (int i=1;i<intervals.length;i++) {
            if (intervals[i][1] <= right) { //區(qū)間被覆蓋了,對(duì)應(yīng)情況1
                num--;
            }else if (intervals[i][0] >= right) {//對(duì)應(yīng)情況3
                left = intervals[i][0];
                right = intervals[i][1];
            }else if (right>intervals[i][0] && right<intervals[i][1]) {
                //對(duì)應(yīng)情況2
                right = intervals[i][1];
            }
        }
        return num;
    }
}

2、區(qū)間合并(LeetCode 56)

? 和第一題類(lèi)似,但要注意三種情況的符號(hào),弄清楚到底要不要加等于號(hào)

class Solution {
    public int[][] merge(int[][] intervals) {
        
        int len = intervals.length;
        List<int[]> res = new ArrayList<>();
        //排序
        Arrays.sort(intervals,(a,b)-> {
            return a[0] == b[0]?(b[1]-a[1]):(a[0]-b[0]);
        });

        int left = intervals[0][0];
        int right = intervals[0][1];
        res.add(intervals[0]);

        for (int i=1;i<len;i++) {
            if (right >= intervals[i][1]) {
                continue;
            }else if(right >= intervals[i][0] && right < intervals[i][1]) {
                right = intervals[i][1];
                //先取出修改后再重新添加
                int[] tmp = res.remove(res.size()-1);
                tmp[1] = right;
                res.add(tmp);
            } else if (right < intervals[i][0]) { //注意此處為嚴(yán)格小于號(hào),不能寫(xiě)小于等于!
                left = intervals[i][0];
                right = intervals[i][1];
                int[] tmp2 = {left,right};
                res.add(tmp2);
            }
        }
        return res.toArray(new int[res.size()][]);
    }
}
image-20201213143517525

3、區(qū)間交集問(wèn)題(LeetCode 986)

? 給定兩個(gè)由一些 閉區(qū)間 組成的列表,每個(gè)區(qū)間列表都是成對(duì)不相交的,并且已經(jīng)排序。返回這兩個(gè)區(qū)間列表的交集。形式上,閉區(qū)間 [a, b](其中 a <= b)表示實(shí)數(shù) x 的集合,而 a <= x <= b。兩個(gè)閉區(qū)間的交集是一組實(shí)數(shù),要么為空集,要么為閉區(qū)間。例如,[1, 3] 和 [2, 4] 的交集為 [2, 3]。)

? 此題注意簡(jiǎn)化,不然情況太多

class Solution {
    public int[][] intervalIntersection(int[][] A, int[][] B) {
        int lenA = A.length;int lenB = B.length;
        if (lenA == 0 || lenB == 0) return new int[0][0];

        int indexA = 0;int indexB = 0;
        List<int[]> res = new ArrayList<>();
        while (indexA < lenA && indexB <lenB) {
            //可以這樣簡(jiǎn)化?。。?            int lo = Math.max(A[indexA][0],B[indexB][0]);
            int hi = Math.min(A[indexA][1],B[indexB][1]);

            if (lo<=hi) {
                res.add(new int[]{lo,hi});
            }
            //誰(shuí)的右邊小,誰(shuí)的指針就右移
            if (A[indexA][1]>=B[indexB][1]) {
                indexB++;
            }else {
                indexA++;
            }
        }
        return res.toArray(new int[res.size()][]);
    }
}

區(qū)間貪心算法

4、無(wú)重疊區(qū)間(LeetCode 435)

給定一個(gè)區(qū)間的集合,找到需要移除區(qū)間的最小數(shù)量,使剩余區(qū)間互不重疊。

注意:可以認(rèn)為區(qū)間的終點(diǎn)總是大于它的起點(diǎn)。區(qū)間 [1,2] 和 [2,3] 的邊界相互“接觸”,但沒(méi)有相互重疊。

image
class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {

        if (intervals.length == 0) return 0;
        return intervals.length-interval(intervals);
    }

    int interval (int[][] intervals) {
        int res = 1;
        Arrays.sort(intervals,(a,b)->{
            return a[1]-b[1];
        }); 
        int start = intervals[0][0];
        int end = intervals[0][1];
        for (int i=1;i<intervals.length;i++) {
            if (end <= intervals[i][0]) {
                res++;
                start = intervals[i][0];
                end = intervals[i][1];
            }
        }
        return res;
    }
}

5、用箭引爆氣球(LeetCode 452)

與上一題不同的是兩個(gè)區(qū)間交集為一個(gè)點(diǎn)時(shí)還是算作一個(gè)區(qū)間

class Solution {
    public int findMinArrowShots(int[][] points) {

        if (points.length == 0) return 0;
        Arrays.sort(points,(a,b)->{
            //不要用return a[1]-b[1];  會(huì)發(fā)生溢出
            return a[1] > b[1] ? 1 : -1;
        });
        int res = 1;
        int start = points[0][0];
        int end = points[0][1];
        for (int i=1;i<points.length;i++) {
            if (end < points[i][0]) {
                res++;
                start = points[i][0];
                end = points[i][1];
            }
        }
        return res;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 區(qū)間覆蓋 這道題的本質(zhì)——讓我們找到給定區(qū)間中最能代表線段區(qū)間的區(qū)間,然后盡可能少。目的是可以完全代表這個(gè)線段區(qū)間...
    StevenHD閱讀 161評(píng)論 0 0
  • 區(qū)間分組 目標(biāo)是給給定的所有區(qū)間分組,然后每一個(gè)組中的所有區(qū)間都沒(méi)有交集,然后盡可能的組數(shù)要少一些。 核心——找出...
    StevenHD閱讀 194評(píng)論 0 0
  • 本文對(duì)區(qū)間查詢(xún)問(wèn)題常用的數(shù)據(jù)結(jié)構(gòu)方法進(jìn)行總結(jié) 1. 前綴和 前綴和是降低區(qū)間查詢(xún)問(wèn)題復(fù)雜度的一種常見(jiàn)預(yù)處理方法,對(duì)...
    舒也ella閱讀 2,525評(píng)論 0 0
  • 一、題目 我們來(lái)對(duì)比分析2個(gè)問(wèn)題。 區(qū)間選點(diǎn) 最大不相交區(qū)間數(shù)量 先來(lái)看下題意—— 其實(shí)這兩道題是一樣的。代碼都是...
    StevenHD閱讀 490評(píng)論 0 0
  • 讀完本文,你不僅學(xué)會(huì)了算法套路,還可以順便去 LeetCode 上拿下如下題目: 1288.刪除被覆蓋區(qū)間[htt...
    labuladong閱讀 547評(píng)論 0 5

友情鏈接更多精彩內(nèi)容