Java&C++题解与拓展——leetcode436.寻找右区间【么的新知识】

117 阅读1分钟
每日一题做题记录,参考官方和三叶的题解

题目要求

在这里插入图片描述

思路一:排序+二分

【是我没想到的思路】

  • 要比较的对象是左端点,那就把左端点抽出来排个序形成数组leftleft
  • 遍历右端点:
    • 对每个右端点intervals[i][1]intervals[i][1],用二分在leftleft里找第一个大于等于它的数。
  • 数组leftleft要记录在intervalsintervals的下标。

Java

class Solution {
    public int[] findRightInterval(int[][] intervals) {
        int n = intervals.length;
        int[][] left = new int[n][2]; //(left, idx)
        for(int i = 0; i < n; i++)
            left[i] = new int[]{intervals[i][0], i};
        Arrays.sort(left, (a,b) -> a[0] - b[0]);
        
        int[] res = new int[n];
        // 二分找第一个大于等于目标
        for(int i = 0; i < n; i++) {
            int l = 0, r = n - 1;
            while(l < r) {
                int mid = l + r >> 1;
                if(left[mid][0] >= intervals[i][1])
                    r = mid;
                else
                    l = mid + 1;
            }
            res[i] = left[r][0] >= intervals[i][1] ? left[r][1] : -1;
        }
        return res;
    }
}
  • 时间复杂度:O(nlogn)O(n\log n)nn次遍历,每次O(logn)O(\log n)
  • 空间复杂度:O(n)O(n)

C++

class Solution {
public:
    vector<int> findRightInterval(vector<vector<int>>& intervals) {
        int n = intervals.size();
        vector<vector<int>> left(n, vector<int>(2)); //(left, idx)
        for(int i = 0; i < n; i++)
            left[i] = {intervals[i][0], i};
        sort(left.begin(), left.end());   

        vector<int> res(n);
        // 二分找第一个大于等于目标
        for(int i = 0; i < n; i++) {
            int l = 0, r = n - 1;
            while(l < r) {
                int mid = l + r >> 1;
                if(left[mid][0] >= intervals[i][1])
                    r = mid;
                else
                    l = mid + 1;
            }
            res[i] = left[r][0] >= intervals[i][1] ? left[r][1] : -1;
        }
        return res;
    }
};
  • 时间复杂度:O(nlogn)O(n\log n)nn次遍历,每次二分O(logn)O(\log n)
  • 空间复杂度:O(n)O(n)

思路二:双指针

  • 把左端点和右端点都排个序,两个指针分别从两个数组头开始;
  • 遍历右端点的时候就不用每次都从整个leftleft里面找了,只需要从上一次结束的地方开始。

Java

class Solution {
    public int[] findRightInterval(int[][] intervals) {
        int n = intervals.length;
        int[][] left = new int[n][2], right = new int[n][2];
        for(int i = 0; i < n; i++) {
            left[i] = new int[]{intervals[i][0], i};
            right[i] = new int[]{intervals[i][1], i};
        }
        Arrays.sort(left, (a,b) -> a[0] - b[0]);
        Arrays.sort(right, (a,b) -> a[0] - b[0]);
        
        int[] res = new int[n];
        for(int l = 0, r = 0; r < n; r++) {
            int cur = right[r][0], idx = right[r][1];
            while(l < n && left[l][0] < cur)
                l++;
            res[idx] = l == n ? -1 : left[l][1];
        }
        return res;
    }
}
  • 时间复杂度:O(nlogn)O(n\log n),看起来和之前一样是因为排序复杂度高,其实构造答案的复杂度只有O(n)O(n)
  • 空间复杂度:O(n)O(n)

C++

class Solution {
public:
    vector<int> findRightInterval(vector<vector<int>>& intervals) {
        int n = intervals.size();
        vector<vector<int>> left(n, vector<int>(2)), right(n, vector<int>(2));
        for(int i = 0; i < n; i++) {
            left[i] = {intervals[i][0], i};
            right[i] = {intervals[i][1], i};
        }
        sort(left.begin(), left.end());
        sort(right.begin(), right.end());

        vector<int> res(n);
        for(int l = 0, r = 0; r < n; r++) {
            int cur = right[r][0], idx = right[r][1];
            while(l < n && left[l][0] < cur)
                l++;
            res[idx] = l == n ? -1 : left[l][1];
        }
        return res;
    }
};
  • 时间复杂度:O(nlogn)O(n\log n)
  • 空间复杂度:O(n)O(n)

总结

热爱双指针的我一下就想到了第二种,轻松搞定~

【和自己去过了520、还有周董看、很快乐了】


欢迎指正与讨论!