差分数组(TreeMap / redblacktree.NewWithIntComparator 红黑树)、顺序遍历、二分查找(upper_bound + bisect_right / lower_bound + bisect_left / sort.Search + sort.SearchInts) 3 种算法,用升序(sort / Arrays.sort / Array.Sort / qsort(int*, int, sizeof(int), cmp) / sort.Ints)技巧,求解《1450. 在既定时间做作业的学生人数》

2022-08-19 15:28:33

差分数组(TreeMap / Object.create(null) / Array / redblacktree.NewWithIntComparator 红黑树)、顺序遍历、二分查找(upper_bound + bisect_right + sort.Search + sort.SearchInts / lower_bound + bisect_left + sort.Search + sort.SearchInts) 3 种算法,用升序(sort / Arrays.sort / Array.Sort / qsort(int*, int, sizeof(int), cmp) / sort.Ints)技巧,求解《1450. 在既定时间做作业的学生人数》

例题

1450. 在既定时间做作业的学生人数

给你两个整数数组 startTime(开始时间)和 endTime(结束时间),并指定一个整数 queryTime 作为查询时间。
已知,第 i 名学生在 startTime[i] 时开始写作业并于 endTime[i] 时完成作业。
请返回在查询时间 queryTime 时正在做作业的学生人数。形式上,返回能够使 queryTime 处于区间 [startTime[i], endTime[i]](含)的学生人数。
示例 1:
输入:startTime = [1,2,3], endTime = [3,2,7], queryTime = 4
输出:1
解释:一共有 3 名学生。
第一名学生在时间 1 开始写作业,并于时间 3 完成作业,在时间 4 没有处于做作业的状态。
第二名学生在时间 2 开始写作业,并于时间 2 完成作业,在时间 4 没有处于做作业的状态。
第三名学生在时间 3 开始写作业,预计于时间 7 完成作业,这是是唯一一名在时间 4 时正在做作业的学生。
示例 2:
输入:startTime = [4], endTime = [4], queryTime = 4
输出:1
解释:在查询时间只有一名学生在做作业。
示例 3:
输入:startTime = [4], endTime = [4], queryTime = 5
输出:0
示例 4:
输入:startTime = [1,1,1,1], endTime = [1,3,2,4], queryTime = 7
输出:0
示例 5:
输入:startTime = [9,8,7,6,5,4,3,2,1], endTime = [10,10,10,10,10,10,10,10,10], queryTime = 5
输出:5
提示:
startTime.length == endTime.length
1 <= startTime.length <= 100
1 <= startTime[i] <= endTime[i] <= 1000
1 <= queryTime <= 1000

答案

差分数组

var busyStudent = function(startTime, endTime, queryTime) { // Object 实现
  const treeMap = Object.create(null), n = startTime.length
  for (let i = 0; i < n; i++) {
    const start = startTime[i], end = endTime[i]
    treeMap[start] = (treeMap[start] || 0) + 1
    treeMap[end + 1] = (treeMap[end + 1] || 0) - 1
  }
  let r = 0
  for (const [time, times] of Object.entries(treeMap)) {
    if (queryTime < time) return r
    r += times
  }
  return r
};
var busyStudent = function(startTime, endTime, queryTime) { // Map 实现
  const treeMap = new Map, n = startTime.length
  for (let i = 0; i < n; i++) {
    const start = startTime[i], end = endTime[i]
    treeMap.set(start, (treeMap.get(start) || 0) + 1)
    treeMap.set(end + 1, (treeMap.get(end + 1) || 0) - 1)
  }
  let r = 0
  for (const [time, times] of Array.from(treeMap.entries()).sort((a, b) => a[0] - b[0])) {
    if (time > queryTime) return r
    r += times
  }
  return r
};
var busyStudent = function(startTime, endTime, queryTime) { // Array 实现
  const maxEndTime = _.max(endTime), treeMap = new Int16Array(maxEndTime + 2), n = startTime.length
  for (let i = 0; i < n; i++) {
    const start = startTime[i], end = endTime[i]
    treeMap[start]++
    treeMap[end + 1]--
  }
  let r = 0
  for (let time = 0; time <= Math.min(maxEndTime + 1, queryTime); time++) {
    if (treeMap[time] === 0) continue
    r += treeMap[time]
  }
  return r
};
function busyStudent(startTime: number[], endTime: number[], queryTime: number): number {
  const maxEndTime = Math.max.apply(null, endTime), treeMap = new Array(maxEndTime + 2).fill(0)
  for (let i = 0; i <= maxEndTime; i++) {
    treeMap[startTime[i]]++
    treeMap[endTime[i] + 1]--
  }
  let r = 0
  for (let time = 0; time <= Math.min(maxEndTime + 1, queryTime); time++) {
    r += treeMap[time]
  }
  return r
};
class Solution {
  function busyStudent($startTime, $endTime, $queryTime) {
    $maxEndTime = max($endTime);
    $treeMap = array_fill(0, $maxEndTime + 2, 0);
    foreach ($startTime as $i => $start) {
      $treeMap[$start]++;
      $treeMap[$endTime[$i] + 1]--;
    }
    $r = 0;
    for ($time = 0; $time <= min($maxEndTime + 1, $queryTime); $time++) {
      $r += $treeMap[$time];
    }
    return $r;
  }
}
type TreeMap struct { // redblacktree 实现
  *redblacktree.Tree
}
func Constructor() TreeMap {
  return TreeMap{redblacktree.NewWithIntComparator()}
}
func (this *TreeMap) Add(key int, value int) {
  if v, ok := this.Get(key); ok {
    value += v.(int)
  }
  this.Put(key, value)
}
func busyStudent(startTime []int, endTime []int, queryTime int) int {
  treeMap := Constructor()
  for i, start := range startTime {
    end := endTime[i]
    treeMap.Add(start, 1)
    treeMap.Add(end + 1, -1)
  }
  r := 0
  for it := treeMap.Iterator(); it.Next(); {
    if it.Key().(int) > queryTime {
      return r
    }
    r += it.Value().(int)
  }
  return r
}
func busyStudent(startTime []int, endTime []int, queryTime int) int { // []int 实现
  maxEndTime := 0
  for _, end := range endTime {
    maxEndTime = max(maxEndTime, end)
  }
  treeMap, r := make([]int, maxEndTime + 2), 0
  for i, start := range startTime {
    end := endTime[i]
    treeMap[start]++
    treeMap[end + 1]--
  }
  for time := 0; time <= min(maxEndTime + 1, queryTime); time++ {
    r += treeMap[time]
  }
  return r
}
func max(a int, b int) int {
  if a > b {
    return a
  }
  return b
}
func min(a int, b int) int {
  if a < b {
    return a
  }
  return b
}
from sortedcontainers import SortedDict # soretedcontainers 实现
class Solution:
  def busyStudent(self, startTime: List[int], endTime: List[int], queryTime: int) -> int:
    treeMap, r = SortedDict(), 0
    for i, start in enumerate(startTime):
      treeMap[start] = treeMap.get(start, 0) + 1
      treeMap[endTime[i] + 1] = treeMap.get(endTime[i] + 1, 0) - 1
    for time, times in treeMap.items():
      if time > queryTime: return r
      r += times
    return r
class Solution: # list 实现
  def busyStudent(self, startTime: List[int], endTime: List[int], queryTime: int) -> int:
    maxEndTime = max(endTime)
    treeMap, r = [0] * (maxEndTime + 2), 0
    for i, start in enumerate(startTime):
      end = endTime[i]
      treeMap[start] += 1
      treeMap[end + 1] -= 1
    for time in range(min(maxEndTime + 2, queryTime + 1)):
      r += treeMap[time]
    return r
class Solution {
  public int busyStudent(int[] startTime, int[] endTime, int queryTime) {
    TreeMap<Integer, Integer> treeMap = new TreeMap<Integer, Integer>();
    int n = startTime.length, r = 0;
    for (int i = 0; i < n; i++) {
      int start = startTime[i], end = endTime[i];
      treeMap.put(start, treeMap.getOrDefault(start, 0) + 1);
      treeMap.put(end + 1, treeMap.getOrDefault(end + 1, 0) - 1);
    }
    for (Map.Entry<Integer, Integer> entry : treeMap.entrySet()) {
      int time = entry.getKey(), times = entry.getValue();
      if (time > queryTime) return r;
      r += times;
    }
    return r;
  }
}
public class Solution { // int[] 实现
  public int BusyStudent(int[] startTime, int[] endTime, int queryTime) {
    int maxEndTime = endTime.Max(), n = startTime.Length, r = 0;
    int[] treeMap = new int[maxEndTime + 2];
    for (int i = 0; i < n; i++) {
      treeMap[startTime[i]]++;
      treeMap[endTime[i] + 1]--;
    }
    for (int time = 0; time <= Math.Min(maxEndTime + 1, queryTime); time++) {
      r += treeMap[time];
    }
    return r;
  }
}
#define MAX(a, b) a > b ? a : b
#define MIN(a, b) a < b ? a : b
int busyStudent(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int queryTime){ // int* 实现
  int maxEndTime = 0;
  for (int i = 0; i < endTimeSize; i++) {
    maxEndTime = MAX(maxEndTime, endTime[i]);
  }
  int* treeMap = malloc(sizeof(int) * (maxEndTime + 2));
  memset(treeMap, 0, sizeof(int) * (maxEndTime + 2));
  for (int i = 0; i < endTimeSize; i++) {
    treeMap[startTime[i]]++;
    treeMap[endTime[i] + 1]--;
  }
  int r = 0, minTime = MIN(maxEndTime + 1, queryTime);
  for (int time = 0; time <= minTime; time++) {
    r += treeMap[time];
  }
  free(treeMap);
  return r;
}
class Solution { // vector<int> 实现
public:
  int busyStudent(vector<int>& startTime, vector<int>& endTime, int queryTime) {
    int maxEndTime = *max_element(endTime.begin(), endTime.end()), r = 0;
    vector<int> treeMap(maxEndTime + 2, 0);
    for (int i = 0; i < startTime.size(); i++) {
      treeMap[startTime[i]]++;
      treeMap[endTime[i] + 1]--;
    }
    for (int time = 0; time <= min(maxEndTime + 1, queryTime); time++) {
      r += treeMap[time];
    }
    return r;
  }
};

顺序遍历

var busyStudent = function(startTime, endTime, queryTime) {
  const n = startTime.length
  let r = 0
  for (let i = 0; i < n; i++) {
    if (startTime[i] <= queryTime && endTime[i] >= queryTime) r++
  }
  return r
};
function busyStudent(startTime: number[], endTime: number[], queryTime: number): number {
  const n = startTime.length
  let r = 0
  for (let i = 0; i < n; i++) {
    if (startTime[i] <= queryTime && endTime[i] >= queryTime) r++
  }
  return r
};
class Solution {
  function busyStudent($startTime, $endTime, $queryTime) {
    $r = 0;
    foreach ($startTime as $i => $start) {
      if ($queryTime >= $start && $queryTime <= $endTime[$i]) $r++;
    }
    return $r;
  }
}
func busyStudent(startTime []int, endTime []int, queryTime int) int {
  r := 0
  for i, start := range startTime {
    if queryTime >= start && queryTime <= endTime[i] {
      r++
    }
  }
  return r
}
class Solution:
  def busyStudent(self, startTime: List[int], endTime: List[int], queryTime: int) -> int:
    r = 0
    for i, start in enumerate(startTime):
      if queryTime >= start and queryTime <= endTime[i]: r += 1
    return r
class Solution {
  public int busyStudent(int[] startTime, int[] endTime, int queryTime) {
    int n = startTime.length, r = 0;
    for (int i = 0; i < n; i++) {
      if (queryTime >= startTime[i] && queryTime <= endTime[i]) r++;
    }
    return r;
  }
}
public class Solution {
  public int BusyStudent(int[] startTime, int[] endTime, int queryTime) {
    int n = startTime.Length, r = 0;
    for (int i = 0; i < n; i++) {
      if (queryTime >= startTime[i] && queryTime <= endTime[i]) r++;
    }
    return r;
  }
}
int busyStudent(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int queryTime){
  int r = 0;
  for (int i = 0; i < startTimeSize; i++) {
    if (queryTime >= startTime[i] && queryTime <= endTime[i]) r++;
  }
  return r;
}
class Solution {
public:
  int busyStudent(vector<int>& startTime, vector<int>& endTime, int queryTime) {
    int r = 0, n = startTime.size();
    for (int i = 0; i < n; i++) {
      if (queryTime >= startTime[i] && queryTime <= endTime[i]) r++;
    }
    return r;
  }
};

二分查找 · 升序

var busyStudent = function(startTime, endTime, queryTime) {
  startTime.sort((a, b) => a - b)
  endTime.sort((a, b) => a - b)
  return upper_bound(startTime, queryTime) - lower_bound(endTime, queryTime)
};
const upper_bound = (nums, num) => {
  let l = 0, r = nums.length - 1
  while (l <= r) {
    const m = l + r >>> 1
    if (nums[m] > num) r = m - 1
    else l = m + 1
  }
  return l
}
const lower_bound = (nums, num) => {
  let l = 0, r = nums.length - 1
  while (l <= r) {
    const m = l + r >>> 1
    if (nums[m] >= num) r = m - 1
    else l = m + 1
  }
  return l
}
function busyStudent(startTime: number[], endTime: number[], queryTime: number): number {
  startTime.sort((a, b) => a - b)
  endTime.sort((a, b) => a - b)
  return upper_bound(startTime, queryTime) - lower_bound(endTime, queryTime)
};
const upper_bound = (nums, num) => {
  let l = 0, r = nums.length - 1
  while (l <= r) {
    const m = l + r >>> 1
    if (nums[m] > num) r = m - 1
    else l = m + 1
  }
  return l
}
const lower_bound = (nums, num) => {
  let l = 0, r = nums.length - 1
  while (l <= r) {
    const m = l + r >>> 1
    if (nums[m] >= num) r = m - 1
    else l = m + 1
  }
  return l
}
class Solution {
  function busyStudent($startTime, $endTime, $queryTime) {
    sort($startTime, SORT_NUMERIC);
    sort($endTime, SORT_NUMERIC);
    return $this->upper_bound($startTime, $queryTime) - $this->lower_bound($endTime, $queryTime);
  }
  function upper_bound($nums, $num) {
    $l = 0;
    $r = count($nums) - 1;
    while ($l <= $r) {
      $m = $l + $r >> 1;
      if ($nums[$m] > $num) $r = $m - 1;
      else $l = $m + 1;
    }
    return $l;
  }
  function lower_bound($nums, $num) {
    $l = 0;
    $r = count($nums) - 1;
    while ($l <= $r) {
      $m = $l + $r >> 1;
      if ($nums[$m] >= $num) $r = $m - 1;
      else $l = $m + 1;
    }
    return $l;
  }
}
func busyStudent(startTime []int, endTime []int, queryTime int) int {
  sort.Ints(startTime)
  sort.Ints(endTime)
  n := len(startTime)
  return sort.Search(n, func(i int) bool {
    return startTime[i] > queryTime
  }) - sort.Search(n, func(i int) bool {
    return endTime[i] >= queryTime
  })
}
func busyStudent(startTime []int, endTime []int, queryTime int) int {
  sort.Ints(startTime)
  sort.Ints(endTime)
  return sort.SearchInts(startTime, queryTime + 1) - sort.SearchInts(endTime, queryTime)
}
class Solution:
  def busyStudent(self, startTime: List[int], endTime: List[int], queryTime: int) -> int:
    return bisect_right(sorted(startTime), queryTime) - bisect_left(sorted(endTime), queryTime)
class Solution {
  public int busyStudent(int[] startTime, int[] endTime, int queryTime) {
    Arrays.sort(startTime);
    Arrays.sort(endTime);
    return upper_bound(startTime, queryTime) - lower_bound(endTime, queryTime);
  }
  public int upper_bound(int[] nums, int num) {
    int l = 0, r = nums.length - 1;
    while (l <= r) {
      int m = l + r >>> 1;
      if (nums[m] > num) r = m - 1;
      else l = m + 1;
    }
    return l;
  }
  public int lower_bound(int[] nums, int num) {
    int l = 0, r = nums.length - 1;
    while (l <= r) {
      int m = l + r >>> 1;
      if (nums[m] >= num) r = m - 1;
      else l = m + 1;
    }
    return l;
  }
}
public class Solution {
  public int BusyStudent(int[] startTime, int[] endTime, int queryTime) {
    Array.Sort(startTime);
    Array.Sort(endTime);
    return upper_bound(startTime, queryTime) - lower_bound(endTime, queryTime);
  }
  public int upper_bound(int[] nums, int num) {
    int l = 0, r = nums.Length - 1;
    while (l <= r) {
      int m = l + r >> 1;
      if (nums[m] > num) r = m - 1;
      else l = m + 1;
    }
    return l;
  }
  public int lower_bound(int[] nums, int num) {
    int l = 0, r = nums.Length - 1;
    while (l <= r) {
      int m = l + r >> 1;
      if (nums[m] >= num) r = m - 1;
      else l = m + 1;
    }
    return l;
  }
}
static inline int cmp(const void *pa, const void *pb) {
  return *(int*)pa - *(int*)pb;
}
int upper_bound(int* nums, int* num, int* numsSize) {
  int l = 0, r = *numsSize - 1;
  while (l <= r) {
    int m = l + r >> 1;
    if (nums[m] > *num) r = m - 1;
    else l = m + 1;
  }
  return l;
}
int lower_bound(int* nums, int* num, int* numsSize) {
  int l = 0, r = *numsSize - 1;
  while (l <= r) {
    int m  = l + r >> 1;
    if (nums[m] >= *num) r = m - 1;
    else l = m + 1;
  }
  return l;
}
int busyStudent(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int queryTime){
  qsort(startTime, startTimeSize, sizeof(int), cmp);
  qsort(endTime, endTimeSize, sizeof(int), cmp);
  return upper_bound(startTime, &queryTime, &startTimeSize) - lower_bound(endTime, &queryTime, &endTimeSize);
}
class Solution {
public:
  int busyStudent(vector<int>& startTime, vector<int>& endTime, int queryTime) {
    sort(startTime.begin(), startTime.end());
    sort(endTime.begin(), endTime.end());
    return upper_bound(startTime.begin(), startTime.end(), queryTime) - startTime.begin() - (lower_bound(endTime.begin(), endTime.end(), queryTime) - endTime.begin());
  }
};

顺序遍历,用 Label 或 continue 2 继续外层循环,单调栈(顺序遍历 / 倒序遍历),3 解法求解《1475. 商品折扣后的最终价格》
顺序遍历,用 Label 或 continue 2 继续外层循环,单调栈(顺序遍历 / 倒序遍历),3 解法求解《1475. 商品折扣后的最终价格》
双指针,单指针,原地交换,用临时变量,加减法,指针交换变量。求解《剑指 Offer 21. 调整数组顺序使奇数位于偶数前面》
双指针,单指针,原地交换,用临时变量,加减法,指针交换变量。求解《剑指 Offer 21. 调整数组顺序使奇数位于偶数前面》
栈,列表(指针模拟栈),2 解法求解《946. 验证栈序列》
栈,列表(指针模拟栈),2 解法求解《946. 验证栈序列》