Leetcode 632.最小区间

最小区间

你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。

我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

示例 1:

输入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]

输出: [20,24]

解释:

列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。

列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。

列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。

注意:

  1. 给定的列表可能包含重复元素,所以在这里升序表示 >= 。
  2. 1 <= k <= 3500
  3. -105 <= 元素的值 <= 105
  4. 对于使用Java的用户,请注意传入类型已修改为List<List<Integer>>。重置代码模板后可以看到这项改动。

思路

这个题来自打车公司lyft,现实意义是模拟该app在很多user登陆的登陆时间,narrow一个范围,这样就可以在user登陆时间最频繁的范围里投放广告或者做些其他的商业行为。

two pointer的思路。

三个指针zero、first、second同时从每个list的首元素出发。用pointerIndex来维护一个数组记录每个list当前指针的index。

比较三个指针对应的元素大小。记录比较后的curMin, curMax,更新smallest range。

移动curMin对应的指针,比较三个指针对应的元素大小。记录比较后的curMin, curMax,更新smallest range。 更新pointerIndex。

直至curMin对应的指针无法移动为止(即curMin走到了某个list的尽头)。

 1 class Solution {
 2     public int[] smallestRange(List<List<Integer>> nums) {
 3         int curMin = 0;
 4         int curMax = Integer.MAX_VALUE;
 5         int[] pointerIndex = new int[nums.size()];// maintain一个数组来记录每层list当前的pointer的index
 6         boolean flag = true;  // flag辅助判断是否有某个list走到了末尾
 7
 8         for (int i = 0; i < nums.size() && flag; i++) { // 外层循环遍历list
 9             for (int j = 0; j < nums.get(i).size() && flag; j++) { // 内层循环遍历某个list的第 j 个元素
10                 int minValueLevel = 0;
11                 int maxValueLevel = 0;
12                 for (int k = 0; k < nums.size(); k++) {
13                     if (nums.get(minValueLevel).get(pointerIndex[minValueLevel]) > nums.get(k).get(pointerIndex[k])) {
14                         minValueLevel = k;
15                     }
16                     if (nums.get(maxValueLevel).get(pointerIndex[maxValueLevel]) < nums.get(k).get(pointerIndex[k])) {
17                         maxValueLevel = k;
18                     }
19                 }
20                 // 是否更新smallest range
21                 if (nums.get(maxValueLevel).get(pointerIndex[maxValueLevel]) - nums.get(minValueLevel).get(pointerIndex[minValueLevel]) < curMax - curMin) {
22                     curMin = nums.get(minValueLevel).get(pointerIndex[minValueLevel]);
23                     curMax = nums.get(maxValueLevel).get(pointerIndex[maxValueLevel]);
24                 }
25                 // 移动当前找到的最小值对应的pointer
26                 pointerIndex[minValueLevel]++;
27                 // flag辅助判断是否有某个list走到了末尾
28                 if (pointerIndex[minValueLevel] == nums.get(minValueLevel).size()) {
29                     flag = false;
30                     break;
31                 }
32
33             }
34         }
35         return new int[]{curMin, curMax};
36     }
37 }

这个代码在oj上显示time limit exceeded

因为每次都要比较三个指针对应元素的curMin和curMax,  我们可以用一个PriorityQueue来优化。

PriorityQueue里面存放当前三个指针对应的元素。

PriorityQueue 删除极值的时间复杂度是 O(logN), 查找极值的时间复杂度是 O(1)

能够在时间上进行优化。

这个代码在oj上显示time limit exceeded

因为每次都要比较三个指针对应元素的curMin和curMax,  我们可以用一个PriorityQueue来优化。

PriorityQueue里面存放当前三个指针对应的元素。

PriorityQueue 删除极值的时间复杂度是 O(logN), 查找极值的时间复杂度是 O(1)

能够在时间上进行优化。

 1 import java.util.List;
 2 import java.util.PriorityQueue;
 3
 4 class Solution {
 5     public int[] smallestRange(List<List<Integer>> nums) {
 6         int curMin = 0;
 7         int curMax = Integer.MAX_VALUE;
 8         int max = Integer.MIN_VALUE;
 9         int[] pointerIndex = new int[nums.size()];
10         boolean flag = true;
11         PriorityQueue<Integer> queue = new PriorityQueue<Integer>((i, j) -> nums.get(i).get(pointerIndex[i]) - nums.get(j).get(pointerIndex[j]));
12         for (int i = 0; i < nums.size(); i++) {
13             queue.add(i);
14             max = Math.max(max, nums.get(i).get(0));
15         }
16         for (int i = 0; i < nums.size() && flag; i++) {
17             for (int j = 0; j < nums.get(i).size() && flag; j++) {
18                 int minValueLevel = queue.poll();
19                 // 是否更新smallest range
20                 if (max - nums.get(minValueLevel).get(pointerIndex[minValueLevel]) < curMax - curMin) {
21                     curMin = nums.get(minValueLevel).get(pointerIndex[minValueLevel]);
22                     curMax = max;
23                 }
24                 // 移动当前找到的最小值对应的pointer
25                 pointerIndex[minValueLevel]++;
26                 // flag辅助判断是否有某个list走到了末尾
27                 if (pointerIndex[minValueLevel] == nums.get(minValueLevel).size()) {
28                     flag = false;
29                     break;
30                 }
31                 queue.offer(minValueLevel);
32                 max = Math.max(max, nums.get(minValueLevel).get(pointerIndex[minValueLevel]));
33
34             }
35         }
36         return new int[]{curMin, curMax};
37     }
38 }

原文地址:https://www.cnblogs.com/kexinxin/p/10381442.html

时间: 2024-10-08 23:06:42

Leetcode 632.最小区间的相关文章

[LeetCode] 632. Smallest Range Covering Elements from K Lists

[LeetCode]632. Smallest Range Covering Elements from K Lists 你有 k 个升序排列的整数数组.找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中. 我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小. 示例 1: 输入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]] 输出: [20,24] 解释: 列表 1:

转:最小区间:k个有序的数组,找到最小区间使k个数组中每个数组至少有一个数在区间中

转:http://www.itmian4.com/thread-6504-1-1.html 最小区间原题 k个有序的数组,找到最小的区间范围使得这k个数组中,每个数组至少有一个数字在这个区间范围内.比如: 数组1:[4, 10, 15, 24, 26] 数组2:[0, 9, 12, 20] 数组3:[5, 18, 22, 30] 最小的区间是[20, 24],这个区间包含了数组1中的24,数组2中的20,数组3中的22 思考时间~~~ 分析 该题看起来还算比较简单,大家通常都会想到:为每一个数组

[LeetCode] 910. Smallest Range II 最小区间之二

Given an array?A?of integers, for each integer?A[i]?we need to choose?either?x = -K?or?x = K, and add?x?to?A[i]?(only once). After this process, we have some array?B. Return the smallest possible difference between the maximum value of?B?and the mini

求珠子的长度最小区间

有一串首尾相连的珠子,共有m个,每一个珠子有一种颜色,并且颜色的总数不超过n(n<=10),求连续的珠子的颜色总数为n时,长度最小的区间. #include <iostream> using namespace std; #define MAXN 10 int colors[MAXN];//record the counter of one color int colorsCounter; void find(int arr[],int len, int colorsNeed) {   

LeetCode#453 最小移动次数使数组元素相等

给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数.每次移动可以使 n - 1 个元素增加 1. 示例: 输入: [1,2,3] 输出: 3 解释: 只需要3次移动(注意每次移动会增加两个元素的值): [1,2,3] => [2,3,3] => [3,4,3] => [4,4,4] 自我思考:观察规律,移动次数是数组内最大值减去最小值,然后生成新数组后继续用最大值减最小值,直到这个差为0,每次的差的和就是移动次数代码实现如下 1 import java.io.IOE

leetcode.310最小高度树

对于一个具有树特征的无向图,我们可选择任何一个节点作为根.图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树.给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点. 格式 该图包含 n 个节点,标记为 0 到 n - 1.给定数字 n 和一个无向边 edges 列表(每一个边都是一对标签). 你可以假设没有重复的边会出现在 edges 中.由于所有的边都是无向边, [0, 1]和 [1, 0] 是相同的,因此不会同时出现在 edges 里. 示例 1: 输入:

LeetCode 57. 插入区间

题目链接:https://leetcode-cn.com/problems/insert-interval/ 解法一:可以LeetCode 56 题的合并区间为基础.   将newInterval插入至intervals中,然后对intervals进行合并区间,就能够得到最终的结果.   时间复杂度:O(N) 解法二:贪心算法. 配合代码讲解: 使用start_ptr和end_ptr记录需要被合并的块区间. 用start_pos和end_pos记录合并的区间的端点值. 使用start_flag来

LeetCode——无重叠区间

Q:给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠. 注意: 可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2,3] 的边界相互"接触",但没有相互重叠. 示例 1: 输入: [ [1,2], [2,3], [3,4], [1,3] ] 输出: 1 解释: 移除 [1,3] 后,剩下的区间没有重叠. 示例 2: 输入: [ [1,2], [1,2], [1,2] ] 输出: 2 解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠. 示例 3:

POJ - 2376 Cleaning Shifts 贪心(最小区间覆盖)

Cleaning Shifts Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cleaning chores around the barn. He always wants to have one cow working on cleaning things up and has divided the day into T shifts (1 <= T <= 1,000,000