查看: 11882| 回复: 20
跳转到指定楼层
上一主题 下一主题
收起左侧

[Leetcode] 一个模板刷N题-treeMap解区间题

 
全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
第一次刷题经验帖,表达能力比较差,求各位看官请拍。觉得有用的话,顺便求米~~~
第一题:LC1094:car-pooling
https://leetcode.com/problems/car-pooling/
给定一个数据trips,trips[0] , trips[1], trips[2]分表代表上车地点,下车地点和人数,要求返回汽车是否可以一趟运输完所有的乘客。我们可以模拟汽车的行驶过程,记录每一个上车以及下车地点车上的人数,最后判断每个上下车点人数是否超过capacity。由于上下车地点是排序的,可以使用treeMap这种数据结构,代码如下:
      
  1. TreeMap<Integer, Integer> map = new TreeMap();
  2.    for (int[] trip : trips) {
  3.     map.put(trip[1], map.getOrDefault(trip[1], 0) + trip[0]);
  4.     map.put(trip[2], map.getOrDefault(trip[2], 0) - trip[0]);
  5.    }
  6.    int persons = 0;
  7.    for (int k : map.keySet()) {
  8.     persons += map.get(k);
  9.     if(persons > capacity) return false;
  10.    }
  11.    return true;
  12.     }
复制代码

第二题:LC253:meeting-room-ii
https://leetcode.com/problems/meeting-rooms-ii/
给定一个会议区间列表,返回需要的会议室数量。
Example 1:
Input: [[0, 30],[5, 10],[15, 20]]
Output: 2
和上一题其实很类似,上一题是给定区间trip,trip[2]代表权重。这一题meeting只有两个值,其实最有一个值是默认值1。Meeting[0], meeting[1]代表上下车地点,最有一个值表示每个地点上车1人,返回车上最多一共出现过多少人。代码如下:

[hide=20]
  1. public int minMeetingRooms(int[][] intervals) {
  2.      TreeMap<Integer, Integer> map = new TreeMap();
  3.      for (int[] itv : intervals) {
  4.       map.put(itv[0], map.getOrDefault(itv[0], 0)+1);
  5.       map.put(itv[1], map.getOrDefault(itv[1], 0)-1);
  6.      }
  7.      int res = 0, count = 0;
  8.      for (int v : map.values()) {
  9.       count += v;
  10.       res = Math.max(res, count);
  11.      }
  12.      return res;
  13. }[/hide]
  14. 第三、四、五题:my-calendar i, ii, iii
  15. [url=https://leetcode.com/problems/my-calendar-i/]https://leetcode.com/problems/my-calendar-i/[/url], 日程不能有冲突
  16. [url=https://leetcode.com/problems/my-calendar-ii/]https://leetcode.com/problems/my-calendar-ii/[/url], 日程最多只有一次冲突
  17. [url=https://leetcode.com/problems/my-calendar-iii/]https://leetcode.com/problems/my-calendar-iii/[/url], 返回日程最多出现过几次冲突
  18. 类似meeting-room-ii,出现最多冲突的日程次数即上一题中,最多需要的会议室:
  19. my-calendar-iii代码如下
  20. [code]TreeMap<Integer, Integer> map;

  21.     public MyCalendar() {
  22.         map = new TreeMap();
  23.     }
  24.     public int book(int start, int end) {
  25.         int res = 0, count = 0;
  26.         map.put(start, map.getOrDefault(start, 0)+1);
  27.         map.put(end, map.getOrDefault(end, 0)-1);
  28.         for(int v : map.values()){
  29.             count+=v;
  30.             res = Math.max(res, count);
  31.         }
  32.         return res;
  33.     }
  34. my-calendar-ii代码:
  35. public boolean book(int start, int end) {
  36.         int count = 0;
  37.         map.put(start, map.getOrDefault(start, 0)+1);
  38.         map.put(end, map.getOrDefault(end, 0)-1);
  39.         boolean canBook = true;
  40.         for(int v : map.values()){
  41.             count+=v;
  42.             if(count>2){//最多出现冲突日程不能大于2
  43.                 canBook = false;
  44.                 break;
  45.             }
  46.         }
  47.         if(!canBook){
  48.             map.put(start, map.get(start)-1);
  49.             map.put(end, map.get(end)+1);
  50.         }

  51.         return canBook;
  52. }
复制代码



第六题:LC56. Merge Intervals
https://leetcode.com/problems/merge-intervals/
合并区间,一般做法是先排序再合并。如果遇到follow-up,比如intervals是stream形式给出的,排序的解法就处理不了。但是treeMap可以:
代码如下:
  1. public int[][] merge(int[][] intervals) {
  2.         if (intervals.length == 0) return new int[0][0];
  3.         List<int[]> list = new ArrayList<>();
  4.         TreeMap<Integer, Integer> map = new TreeMap<>();
  5.         for(int[] itv : intervals){//添加区间节点的过程
  6.             map.put(itv[0], map.getOrDefault(itv[0], 0)+1);
  7.             map.put(itv[1], map.getOrDefault(itv[1], 0)-1);
  8.         }
  9.         int count = 0, start = Integer.MAX_VALUE, end = Integer.MIN_VALUE;
  10.         for (int k : map.keySet()){
  11.             count+=map.get(k);
  12.             start = Math.min(start, k);
  13.             end = Math.max(end, k);
  14.             if (count==0){//关键:count==0代表区间闭合了,需要把刚刚闭合的区间添加到结果集中。可以类比字符串中左右括号的情况,遇到左括号+1,右括号-1。当count==0时,区间的括号是完全匹配的。
  15.                 list.add(new int[]{start, end});
  16.                 start = Integer.MAX_VALUE;
  17.                 end = Integer.MIN_VALUE;
  18.             }
  19.         }
  20.         return list.toArray(new int[list.size()][2]);
  21. }
复制代码




第七题:LC1109. Corporate Flight Bookings
https://leetcode.com/problems/corporate-flight-bookings/
Input: bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
Output: [10,55,45,25,25]
给出起止航班号以及订阅数量,返回每个航班的订阅数量:
  1. public int[] corpFlightBookings(int[][] bookings, int n) {
  2.         int[] res = new int[n];
  3.         TreeMap<Integer, Integer> map = new TreeMap<>();
  4.         for (int[] booking : bookings){
  5.             map.put(booking[0], map.getOrDefault(booking[0], 0)+booking[2]);
  6.             map.put(booking[1]+1, map.getOrDefault(booking[1]+1, 0)-booking[2]);
  7.         }
  8.         int prev = 0;
  9.         for (int k : map.keySet()){
  10.             map.put(k, map.get(k)+prev);
  11.             prev = map.get(k);
  12.         }
  13.         for (int i=1;i<=n;i++){
  14.             Integer booking = map.floorKey(i);
  15.             if (booking!=null){
  16.                 res[i-1] = map.get(booking);
  17.             }
  18.         }
  19.         return res;
  20.     }
复制代码

由于给出的航班数是有限值n,可以使用counting sort代替treeMap进行排序,代码如下:
  1. public int[] corpFlightBookings3(int[][] bookings, int n) {
  2.         int[] res = new int[n];
  3.         for (int[] booking : bookings){
  4.             res[booking[0]-1] += booking[2];
  5.             if (booking[1]<n){
  6.                 res[booking[1]] -= booking[2];
  7.             }
  8.         }
  9.         for (int i=1;i<n;i++){
  10.             res[i] += res[i-1];
  11.         }
  12.         return res;
  13.     }
复制代码

如果上面几题给的区间开始和截止点都比较小的话,也都可以使用数据代替treeMap进行排序。


[/i]

评分

参与人数 25大米 +130 收起 理由
FrankBOKI + 1 给你点个赞!
joestar + 1 给你点个赞!
zjliu + 1 给你点个赞!
ccvzz + 2 给你点个赞!
gongchangzhANYK + 1 很有用的信息!

查看全部评分


上一篇:刷多少hard/多快做完hard才算准备充分?
下一篇:【路过加米】纯小白打算开始刷leetcode,请教是先去看什么书/课程么?求指路
推荐
heronalps 2020-1-24 03:04:28 | 只看该作者
全局:
这个模版的本质,还是start和end两个位置的频率统计,然后遍历结果以求得capacity / merge / verify。如果需要遍历的元素数量上限确定的话,可以用数组来代替treemap。

比如Car Pooling


  1. public boolean carPooling(int[][] trips, int capacity) {
  2.         int stops[] = new int[1001];
  3.         for (int[] t : trips) {
  4.           stops[t[1]] += t[0];
  5.           stops[t[2]] -= t[0];
  6.         }
  7.         for (int i = 0; i < stops.length; i++) {
  8.             capacity -= stops[i];
  9.             if (capacity < 0) return false;
  10.         }
  11.         return true;
  12.     }
复制代码


TreeMap的优势在于Flexible Length, 以及floorKey等接口,可以避免如1109题中的Corner case. 缺点在于每一个操作都是O(Log(n)), 很多情况下与数组相比TC会处于劣势。

很棒,感谢分享!
回复

使用道具 举报

全局:
zea7ot 发表于 2020-08-24 18:10:35
我不太清楚你这里说的"这个"具体是指什么。

如果是使用楼主本帖描述的扫描线(Sweep Line)算法,那TreeMap几乎是是必须的。如果不是必须的,我个人也是强烈推荐的。
嗯嗯 我觉得你对扫描线算法的理解是对的 但是就对这两题而言 我们扫描过程不是由这个map决定的而是由那个for 循环 你看代码只有读值和插入对吧 其实这题的本质就是start 和 end 的频率统计 所以其实不需要treemap
回复

使用道具 举报

推荐
diamondsky 2020-1-22 13:15:28 | 只看该作者
全局:
本帖最后由 diamondsky 于 2020-1-22 13:18 编辑

非常棒!

> 56 merge intervals 如果遇到follow-up,比如intervals是stream形式给出的,排序的解法就处理不了。但是treeMap可以
排序也可以解,也非常清晰,就是57. Insert Interval, 代码如下:
  1. class Solution {
  2.     public int[][] insert(int[][] intervals, int[] newInterval) {
  3.         List<int[]> list = new ArrayList<>();
  4.         
  5.         // corner case
  6.         if ((intervals == null || intervals.length == 0)
  7.             && (newInterval == null || newInterval.length == 0)) return new int[][]{};
  8.         
  9.         int i = 0;
  10.         int n = intervals.length;
  11.         int start = newInterval[0];
  12.         int end = newInterval[1];
  13.         
  14.         // case 1: no overlap
  15.         // intervals :     |_____|
  16.         // [start, end] :               |______|
  17.         //
  18.         while (i < n && intervals[1] < start) {
  19.             list.add(intervals);
  20.             i++;
  21.         }
  22.         
  23.         // case 2: overlap
  24.         // intervals :     |_____| |___|
  25.         // [start, end] :        |______|
  26.         //
  27.         while (i < n && intervals[0] <= end) {
  28.             start = Math.min(start, intervals[0]);
  29.             end = Math.max(end, intervals[1]);
  30.             i++;
  31.         }
  32.         list.add(new int[]{start, end});
  33.         
  34.         // case 3: no overlap
  35.         // intervals :               |_____|
  36.         // [start, end] :     |______|
  37.         //
  38.         while (i < n) {
  39.             list.add(intervals);
  40.             i++;
  41.         }
  42.         return list.toArray(new int[0][]);
  43.     }
  44. }
复制代码

评分

参与人数 1大米 +16 收起 理由
Warald + 16

查看全部评分

回复

使用道具 举报

🔗
scope 2020-1-21 23:53:22 来自APP | 只看该作者
全局:
为什么不用HashMap用TreeMap呢?

评分

参与人数 1大米 +2 收起 理由
dennyzhang007 + 2 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
diamondsky 2020-1-22 14:56:24 | 只看该作者
全局:
仔细看了这个帖子的话,interval相关的所有问题都能解了! 非常感谢楼主!
回复

使用道具 举报

🔗
jliu 2020-1-23 00:17:52 | 只看该作者
全局:
一直有疑问,如果刷题用python, 然后发现题目要用到tree map 怎么办
回复

使用道具 举报

🔗
Wu_kong 2020-1-23 13:32:17 | 只看该作者
全局:
话说java 有tree map, 但是python 需要先自己实现一下
回复

使用道具 举报

🔗
gwy 2020-1-24 02:31:37 | 只看该作者
全局:
scope 发表于 2020-1-21 23:53
为什么不用HashMap用TreeMap呢?

TreeMap 有排序
回复

使用道具 举报

🔗
heronalps 2020-1-24 02:54:12 | 只看该作者
全局:
diamondsky 发表于 2020-1-22 00:15
非常棒!

> 56 merge intervals 如果遇到follow-up,比如intervals是stream形式给出的,排序的解法就处理 ...

57的默认条件是Interval 数组已经排好序,而56并没有这个条件。但interval以数据流形式出现,每一步interval insert之后,整体数组保持有序。

感谢分享!
回复

使用道具 举报

🔗
dreamy 2020-1-24 16:20:47 | 只看该作者
全局:
本帖最后由 dreamy 于 2020-1-24 16:27 编辑

这个帖子总结的很好,和leetcode上的这个discussion异曲同工。https://leetcode.com/problems/me ... -Scheduling-Problem
759. Employee Free Time 也可以用这个模板,和merge interval思路相同。merge interval求的是时间戳上所有被占据的区间,而759求得是时间戳上没有被占据的间隙。
  1. class Solution {
  2.     public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
  3.         List<Interval> res = new ArrayList<>();
  4.         if (schedule == null || schedule.size() == 0) return res;
  5.         TreeMap<Integer, Integer> calendar = new TreeMap<>();
  6.         for (List<Interval> list : schedule) {
  7.             if (list == null || list.size() == 0) continue;
  8.             for (Interval i : list) {
  9.                 calendar.put(i.start, calendar.getOrDefault(i.start, 0) + 1);
  10.                 calendar.put(i.end, calendar.getOrDefault(i.end, 0) - 1);
  11.             }
  12.         }
  13.         int count = 0;
  14.         int start = -1;
  15.         for (Map.Entry<Integer, Integer> entry : calendar.entrySet()) {
  16.             count += entry.getValue();
  17.             if (count == 0) start = entry.getKey();
  18.             if (count > 0 && start != -1) {
  19.                 res.add(new Interval(start, entry.getKey()));
  20.                 start = -1;
  21.             }
  22.         }
  23.         return res;
  24.     }
  25. }
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表