-
-
Notifications
You must be signed in to change notification settings - Fork 9.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
【每日一题】- 2020-04-27 - 多人运动 #347
Comments
#include <bits/stdc++.h>
using namespace std;
#define up(i,a,b) for(int i = a; i <= b; i++)
#define ms(a,x) memset(a,x,sizeof(a))
#define girl pair<int,int> //first开始时间,second结束时间
#define mp(x,y) make_pair(x,y)
const int INF = 0x3f3f3f3f;
const int maxn = 1001; //小猪每晚最多约的女生数量
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n; //小猪今晚约了n个女孩
cin >> n;
vector<girl> v;
up(i,1,n)
{
int bg,ed;
cin >> bg >> ed;
v.push_back(mp(bg,ed));
}
int cnt[maxn]; //cnt[i]记录i时刻的多人运动人数
ms(cnt,0);
int ans = -INF;
up(i,0,n-1) //枚举
{
up(j,v[i].first,v[i].second)
{
cnt[j]++;
ans = max(ans,cnt[j]);
}
}
cout << ans << endl;
return 0;
} |
思路直觉: 我们来看下有哪些情况,看是否可以打开思路。 如下图:
不难发现,除了关心开始时间,我们应该同样关心结束时间。 如果”相邻“的区间重合,则人数++,最后返回人数即可。 本质上是枚举和当前女孩一起多人运动的人数的最大值,当前女孩一起多人运动的就是不比当前女孩晚进场且要排除掉结束时间大于当前女孩开始时间。
因此按照进场时间排序,然后用堆来排除结束时间大于进场时间的,就不难想到了。 具体算法:
代码C++ 代码: class Solution {
public:
int solve(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>&b){
return a[0] < b[0];
});
priority_queue<int, vector<int>, greater<int>> heap;
int ans = 0;
for (int i = 0; i < intervals.size(); i++) {
// 没重叠,弹出堆顶元素,并维持最小堆的性质不变
if (!heap.empty() && heap.top() <= intervals[i][0]) {
heap.pop();
}
// 女孩++
heap.push(intervals[i][1]);
ans = max(ans, heap.size())
}
return ans;
}
}; Python3 代码: class Solution:
def solve(self, intervals):
intervals.sort(key=lambda x:x[0])
h = []
ans = 0
for fr, to in intervals:
if h and h[0] <= fr:
heapq.heappop(h)
heapq.heappush(h, to)
ans = max(ans, len(h))
return ans 另外一种解法将区间离散化为若干点。比如 [1,3] 变为 [1, 0] [3, 1],其中 0 表示进入, 1 表示出。 转换后对数组进行排序, 然后遍历排序后的转化数组,遇到 0 girl + 1, 遇到 1 girl - 1,一边遍历一遍维护 girl 的全局最大值即可。 参考题目:
相关题目力扣的会议室系列大家可以做一下,和这个很类似。 推荐一个 BS 上的题目(据说是 amazon 的面试题),简直和这道题一模一样。 |
/*Brute force is the best algorithm!*/
#include<vector>
#include<iostream>
using std::cout;
using std::endl;
class Solution{
public:
int maxOnlineAmount(vector<vector<int>>& nums){
int min=INT_MAX,max=INT_MIN,ans=0;
for(auto num:nums){
min=num[0]<min?num[0]:min;
max=num[1]>max?num[1]:max;
}
vector<int> timetable(max-min+1,0);
for(auto num:nums){
for(int i=num[0];i<num[1];i++)timetable[i]++;
}
return *std::max_element(std::begin(timetable),std::end(timetable));
}
};
int main(){
vector<vector<int>> nums{{0,30},{5,10},{15,20},{17,25}};
Solution solu;
cout<<solu.maxOnlineAmount(nums)<<endl;
return 0;
} |
jsconst mlc = (arr) => {
const flatArr = arr.flat()
const minT = Math.min(...flatArr)
const maxT = Math.max(...flatArr)
let TIME_PEOPLE_NUM = []
arr.forEach((pt) => {
for (let i = minT; i <= maxT; i++) {
if (i >= pt[0] && i <= pt[1]) {
TIME_PEOPLE_NUM[i] ? TIME_PEOPLE_NUM[i]++ : TIME_PEOPLE_NUM[i] = 1
}
}
});
return Math.max(...TIME_PEOPLE_NUM)
}
console.log(mlc([[0, 30], [5, 10], [8, 10], [15, 20], [10, 40]]))
|
|
package main
import (
"fmt"
)
func main() {
fmt.Println(maximalSquare([][]int{{0, 30}, {5, 10}, {8, 10}, {15, 20}, {10, 40}}))
}
func maximalSquare(matrix [][]int) int {
var (
maxCount = 0
)
f := func(n int, leave int, comeIn int) int {
count := 1
for i := 0; i < n; i++ {
if comeIn <= matrix[i][1] {
count++
}
}
return count
}
for i := 1; i < len(matrix); i++ {
if f(i, matrix[i][1], matrix[i][0]) > maxCount {
maxCount = f(i, matrix[i][1], matrix[i][0])
}
}
return maxCount + 1 // 算上小猪本人 +1
}
// 不知道是否符合 |
Java /**
* 对开始时间进行排序,如果相邻的时间没有重叠,则移除最早的那个时间
* 堆的大小即为最大并集
* (移除一个元素的同时也加入一个新元素,除非有新的更大size的并集,堆的大小才会改变)
* @param intervals [开始时间,结束时间]二维数组
* @return 最大的并集
* @date 2020/4/28
*/
public int maxCount(int[][] intervals){
// 根据开始时间排序
Arrays.sort(intervals, (o1, o2) -> o1[0] - o2[0]);
// 小顶堆,保存结束时间
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
for(int i = 0;i < intervals.length;i++){
//相邻时间没有重叠,则移除最早的结束时间
if(!minHeap.isEmpty() && minHeap.peek() <= intervals[i][0]){
minHeap.remove();
}
minHeap.add(intervals[i][1]);
}
return minHeap.size();
} |
思路
图解代码const bc = girls => {
girls.sort((a, b) => a[0] - b[0]);
const room = [];
let count = 0;
girls.forEach(g => {
while (room.length > 0 && room[room.length - 1][1] <= g[0]) {
room.pop();
}
room.push(g);
room.sort((a, b) => b[1] - a[1])
count = Math.max(count, room.length);
});
return `最多同时有${count}个女生的「${count + 1}人运动」`;
}; 更正 +room.sort((a, b) => b[1] - a[1]) 实际上准备要进房间的女生应该是要和房间里结束时间最早的女生比较,所以每次有新的女生进入房间后,都要对房间内的女生进行排序,让结束时间早的女生排到栈顶。这样果然还是用小顶堆最适合。 const bc = girls => {
// 以开始时间排序
girls.sort((a, b) => a[0] - b[0]);
// 以结束时间建小顶堆
const heap = new MinHeap([]);
girls.forEach(([begin, end]) => {
while (heap.size() && heap.peek() <= begin) {
heap.pop();
}
heap.insert(end);
});
return heap.size();
}; class Heap {
constructor(list = []) {
this.list = list;
this.init();
}
init() {
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
insert(n) {
this.list.push(n);
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
pop() {
const last = this.list.pop();
if (this.size() === 0) return last;
const returnItem = this.list[0];
this.list[0] = last;
this.heapify(this.list, this.size(), 0);
return returnItem;
}
peek() {
return this.list[0];
}
size() {
return this.list.length;
}
}
class MinHeap extends Heap {
constructor(list) {
super(list);
}
heapify(arr, size, i) {
let smallest = i;
const left = Math.floor(i * 2 + 1);
const right = Math.floor(i * 2 + 2);
if (left < size && arr[smallest] > arr[left]) smallest = left;
if (right < size && arr[smallest] > arr[right]) smallest = right;
if (smallest !== i) {
[arr[smallest], arr[i]] = [arr[i], arr[smallest]];
this.heapify(arr, size, smallest);
}
}
} |
@suukii 非常棒的题解, 仅次于小哥哥我啦。 你的代码中关于stack 部分, 本质上是一个单调递减栈。 而由于每一个女孩入栈出栈次数最多一次。 因此时间复杂度是$O(N^2)$。而采用堆的做法,可以以更小的代价获取到最小值(即你的栈顶)。因此从时间复杂度上来说,采用堆的算法复杂度更加优秀。 以上 |
@azl397985856 唔...谢谢 lucifer 小哥哥的夸奖,我会继续努力向“更加优秀”的小哥哥靠近的,嗯。 |
|
好有趣的一道题😂,被同学发的题目吸引过来的,也来蹭一波热点😂。 我的想法无需优先队列等较高级的数据结构。大概思路是,将所有女孩开始和结束的时间一起排序,求和时,出现开始的时间就加一,出现结束的时间就减一,求和过程中出现的最大值就是“最多同时有几个女生做「多人运动」”。感觉和使用heap的思路总体一致。 初来乍到,不足之处还请大佬们多多包涵指教~ #include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int t; //开始结束时间
int flag; //开始结束标记
}arr[100000];
int cmp(struct node x, struct node y)
{
if(x.t == y.t)
{
return x.flag > y.flag;
}
return x.t < y.t;
}
int main()
{
int n;
cin >> n; //n个女孩
for(int i=0; i<n; ++i)
{
cin >> arr[i].t >> arr[i+n].t; //[si, ei]
arr[i].flag = 1;
arr[i+n].flag = -1;
}
sort(arr, arr+n*2, cmp);
int ans = -1, count = 0;
for(int i=0; i<n*2; ++i)
{
count += arr[i].flag;
ans = max(ans, count);
}
cout << ans << endl;
return 0;
} |
class Solution {
public int mp(int[][] times) {
Arrays.sort(times, Comparator.comparingInt(t -> t[0]));
PriorityQueue<Integer> pq = new PriorityQueue<>();
int girls = 0;
for (int[] time : times) {
while (!pq.isEmpty() && pq.peek() <= time[0]) {
pq.poll();
}
pq.add(time[1]);
girls = Math.max(girls, pq.size());
}
return girls;
}
} |
py实现方式! |
格式不对,参考我的 |
留个坑位 |
class Solution {
public:
/**
* @param intervals: an array of meeting time intervals
* @return: the minimum number of conference rooms required
*/
int minMeetingRooms(vector<Interval>& intervals) {
// Write your code here
// 01根据会议开始时间从小到大排序。如果不排序。观察出来规律就无效
sort(intervals.begin(), intervals.end(),
[](Interval& a, Interval& b) { return a.start < b.start; });
// 02从[0..i]判断历史会议由没有结束。
//利用优先级队列符合这个特点。
//最小如果还没结束,剩余根本不需要比较,如果结束了只需要返回一个就可以。
priority_queue<int, vector<int>, greater<int>> smallHeap;
// https://zh.cppreference.com/w/cpp/container/priority_queue
for (auto it : intervals) {
//判断历史会议,有结束的吗
if (!smallHeap.empty() && it.start > smallHeap.top()) {
smallHeap.pop(); // 【1,30】【1,10】---【15,20】
// a<b <c<d a<d
}
smallHeap.push(it.end);
}
return smallHeap.size(); //无重叠会议个数。
}
}; |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
思路只需要关注每个女孩的开始结束时间 代码if __name__ == '__main__':
girls = [(0, 30), (5, 10), (15, 20)]
times = set()
for girl in girls:
times.add(girl[0])
times.add(girl[1])
ans = 0
for time in times:
num = 0
for start, end in girls:
num += int(time >= start and time <= end)
ans = max(ans, num)
print(ans) |
插眼👀 |
对于这一题,没买力扣vip的小伙伴可以到lintcode提交代码,会议室 II https://www.lintcode.com/problem/919 |
刚刚头条考的就是这! |
已知小猪每晚都要约好几个女生到酒店房间。每个女生 i 与小猪约好的时间由 [si , ei]表示,其中 si 表示女生进入房间的时间, ei 表示女生离开房间的时间。由于小猪心胸开阔,思想开明,不同女生可以同时存在于小猪的房间。请计算出小猪最多同时在做几人的「多人运动」。
例子:
Input : [[ 0 , 30] ,[ 5 , 10 ] , [15 , 20 ] ]
OutPut :最多同时有两个女生的「三人运动」
类似问题:力扣会议室系列。比如:https://leetcode-cn.com/problems/meeting-rooms-ii/
The text was updated successfully, but these errors were encountered: