阅读视图

发现新文章,点击刷新页面。

每日一题-重新安排会议得到最多空余时间 II🟡

给你一个整数 eventTime 表示一个活动的总时长,这个活动开始于 t = 0 ,结束于 t = eventTime 。

同时给你两个长度为 n 的整数数组 startTime 和 endTime 。它们表示这次活动中 n 个时间 没有重叠 的会议,其中第 i 个会议的时间为 [startTime[i], endTime[i]] 。

你可以重新安排 至多 一个会议,安排的规则是将会议时间平移,且保持原来的 会议时长 ,你的目的是移动会议后 最大化 相邻两个会议之间的 最长 连续空余时间。

请你返回重新安排会议以后,可以得到的 最大 空余时间。

注意,会议 不能 安排到整个活动的时间以外,且会议之间需要保持互不重叠。

注意:重新安排会议以后,会议之间的顺序可以发生改变。

 

示例 1:

输入:eventTime = 5, startTime = [1,3], endTime = [2,5]

输出:2

解释:

将 [1, 2] 的会议安排到 [2, 3] ,得到空余时间 [0, 2] 。

示例 2:

输入:eventTime = 10, startTime = [0,7,9], endTime = [1,8,10]

输出:7

解释:

将 [0, 1] 的会议安排到 [8, 9] ,得到空余时间 [0, 7] 。

示例 3:

输入:eventTime = 10, startTime = [0,3,7,9], endTime = [1,4,8,10]

输出:6

解释:

将 [3, 4] 的会议安排到 [8, 9] ,得到空余时间 [1, 7] 。

示例 4:

输入:eventTime = 5, startTime = [0,1,2,3,4], endTime = [1,2,3,4,5]

输出:0

解释:

活动中的所有时间都被会议安排满了。

 

提示:

  • 1 <= eventTime <= 109
  • n == startTime.length == endTime.length
  • 2 <= n <= 105
  • 0 <= startTime[i] < endTime[i] <= eventTime
  • endTime[i] <= startTime[i + 1] 其中 i 在范围 [0, n - 2] 之间。

列表分页中的快速翻页竞态问题

在现代Web应用中,分页列表是展示数据的常见方式。然而,当用户快速连续翻页时,会出现一种微妙的竞态问题(Race Condition),导致显示的页面与预期不一致。这个问题看似简单,实则涉及网络异步请

Fetch 笔记

本文是一个Fetch的知识笔记,大部分内容通过ai搜索整理构成,主要记录 fetch的使用、优缺点,对比XML、Axios; fetch出现的原因,主要为了解决什么问题。

一文了解什么是Dart

Dart语言全面指南 Dart 是一种由 Google 开发的通用编程语言,最初设计用于替代 JavaScript 以提升 Web 开发的性能,后来成为 Flutter 框架的首选语言,用于开发高性能

重新安排会议得到最多空余时间 II

方法一:贪心

假设当前平移的会议为 $i$,那么平移的最优解有两种情况:

  1. 如果会议 $i$ 可以移动到某个空余时间段,且该空余时间段不是会议 $i$ 左右两侧相邻的两个空余时间段,那么平移会议 $i$ 可以得到一个新的空余时间段,时长为会议 $i$ 和其左右两侧相邻空余时间段的时长之和

  2. 否则,平移会议 $i$ 可以将其左右两侧相邻空间时间段进行合并

显然,重新安排会议后得到的最大空余时间必定为平移某个会议后,得到的新的空余时间段的最大值。

我们使用 $q[i]$ 记录会议 $i$ 是否适用于第一种情况,首先从左到右遍历会议,同时记录当前遍历到的会议 $i$ 左侧非相邻的空余时间段的最大时长 $t_1$,如果 $t_1 \ge \textit{endTime}[i] - \textit{startTime}[i]$,那么说明会议 $i$ 左侧有满足第一种情况的空余时间段,记 $q[i] = \text{true}$。同样地,我们从右到左遍历会议,记下会议 $i$ 右侧是否有满足第一种情况的空余时间段。

我们枚举平移的会议 $i$,同时令 $\textit{left}_i$ 表示左侧相邻会议的结束时间,$\textit{right}_i$ 表示右侧相邻会议的开始时间,然后根据 $q[i]$ 的值判断平移会议 $i$ 属于哪个情况:

  • 情况一:新的空余时间段的时长为 $\textit{right}_i - \textit{left}_i$

  • 情况二:新的空余时间段的时长为 $\textit{right}_i - \textit{left}_i - (\textit{endTime}[i] - \textit{startTime}[i])$

返回所有枚举结果的最大值。

###C++

class Solution {
public:
    int maxFreeTime(int eventTime, vector<int>& startTime, vector<int>& endTime) {
        int n = startTime.size();
        vector<bool> q(n);
        for (int i = 0, t1 = 0, t2 = 0; i < n; i++) {
            if (endTime[i] - startTime[i] <= t1) {
                q[i] = true;
            }
            t1 = max(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

            if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
                q[n - i - 1] = true;
            }
            t2 = max(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
        }

        int res = 0;
        for (int i = 0; i < n; i++) {
            int left = i == 0 ? 0 : endTime[i - 1];
            int right = i == n - 1 ? eventTime : startTime[i + 1];
            if (q[i]) {
                res = max(res, right - left);
            } else {
                res = max(res, right - left - (endTime[i] - startTime[i]));
            }
        }
        return res;
    }
};

###Go

func maxFreeTime(eventTime int, startTime []int, endTime []int) int {
n := len(startTime)
q := make([]bool, n)
t1, t2 := 0, 0
for i := 0; i < n; i++ {
if endTime[i] - startTime[i] <= t1 {
q[i] = true
}
if i == 0 {
t1 = max(t1, startTime[i])
} else {
t1 = max(t1, startTime[i] - endTime[i - 1])
}

if endTime[n - i - 1] - startTime[n - i - 1] <= t2 {
q[n - i - 1] = true
}
if i == 0 {
t2 = max(t2, eventTime - endTime[n - 1])
} else {
t2 = max(t2, startTime[n - i] - endTime[n - i - 1])
}
}

res := 0
for i := 0; i < n; i++ {
left := 0
if i != 0 {
left = endTime[i - 1]
}
right := eventTime
if i != n - 1 {
right = startTime[i + 1]
}
if q[i] {
res = max(res, right - left)
} else {
res = max(res, right - left - (endTime[i] - startTime[i]))
}
}
return res
}

###Python

class Solution:
    def maxFreeTime(self, eventTime: int, startTime: list[int], endTime: list[int]) -> int:
        n = len(startTime)
        q = [False] * n
        t1 = 0
        t2 = 0
        for i in range(n):
            if endTime[i] - startTime[i] <= t1:
                q[i] = True
            t1 = max(t1, startTime[i] - (0 if i == 0 else endTime[i - 1]))

            if endTime[n - i - 1] - startTime[n - i - 1] <= t2:
                q[n - i - 1] = True
            t2 = max(t2, (eventTime if i == 0 else startTime[n - i]) - endTime[n - i - 1])

        res = 0
        for i in range(n):
            left = 0 if i == 0 else endTime[i - 1]
            right = eventTime if i == n - 1 else startTime[i + 1]
            if q[i]:
                res = max(res, right - left)
            else:
                res = max(res, right - left - (endTime[i] - startTime[i]))
        return res

###Java

class Solution {
    public int maxFreeTime(int eventTime, int[] startTime, int[] endTime) {
        int n = startTime.length;
        boolean[] q = new boolean[n];
        for (int i = 0, t1 = 0, t2 = 0; i < n; i++) {
            if (endTime[i] - startTime[i] <= t1) {
                q[i] = true;
            }
            t1 = Math.max(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

            if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
                q[n - i - 1] = true;
            }
            t2 = Math.max(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
        }

        int res = 0;
        for (int i = 0; i < n; i++) {
            int left = i == 0 ? 0 : endTime[i - 1];
            int right = i == n - 1 ? eventTime : startTime[i + 1];
            if (q[i]) {
                res = Math.max(res, right - left);
            } else {
                res = Math.max(res, right - left - (endTime[i] - startTime[i]));
            }
        }
        return res;
    }
}

###TypeScript

function maxFreeTime(eventTime: number, startTime: number[], endTime: number[]): number {
    const n = startTime.length;
    const q: boolean[] = new Array(n).fill(false);
    let t1 = 0, t2 = 0;
    for (let i = 0; i < n; i++) {
        if (endTime[i] - startTime[i] <= t1) {
            q[i] = true;
        }
        t1 = Math.max(t1, startTime[i] - (i === 0 ? 0 : endTime[i - 1]));

        if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
            q[n - i - 1] = true;
        }
        t2 = Math.max(t2, (i === 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
    }

    let res = 0;
    for (let i = 0; i < n; i++) {
        const left = i === 0 ? 0 : endTime[i - 1];
        const right = i === n - 1 ? eventTime : startTime[i + 1];
        if (q[i]) {
            res = Math.max(res, right - left);
        } else {
            res = Math.max(res, right - left - (endTime[i] - startTime[i]));
        }
    }
    return res;
}

###JavaScript

var maxFreeTime = function(eventTime, startTime, endTime) {
    const n = startTime.length;
    const q = new Array(n).fill(false);
    let t1 = 0, t2 = 0;
    for (let i = 0; i < n; i++) {
        if (endTime[i] - startTime[i] <= t1) {
            q[i] = true;
        }
        t1 = Math.max(t1, startTime[i] - (i === 0 ? 0 : endTime[i - 1]));

        if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
            q[n - i - 1] = true;
        }
        t2 = Math.max(t2, (i === 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
    }

    let res = 0;
    for (let i = 0; i < n; i++) {
        const left = i === 0 ? 0 : endTime[i - 1];
        const right = i === n - 1 ? eventTime : startTime[i + 1];
        if (q[i]) {
            res = Math.max(res, right - left);
        } else {
            res = Math.max(res, right - left - (endTime[i] - startTime[i]));
        }
    }
    return res;
};

###C#

public class Solution {
    public int MaxFreeTime(int eventTime, int[] startTime, int[] endTime) {
        int n = startTime.Length;
        bool[] q = new bool[n];
        int t1 = 0, t2 = 0;
        for (int i = 0; i < n; i++) {
            if (endTime[i] - startTime[i] <= t1) {
                q[i] = true;
            }
            t1 = Math.Max(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

            if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
                q[n - i - 1] = true;
            }
            t2 = Math.Max(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
        }

        int res = 0;
        for (int i = 0; i < n; i++) {
            int left = i == 0 ? 0 : endTime[i - 1];
            int right = i == n - 1 ? eventTime : startTime[i + 1];
            if (q[i]) {
                res = Math.Max(res, right - left);
            } else {
                res = Math.Max(res, right - left - (endTime[i] - startTime[i]));
            }
        }
        return res;
    }
}

###C

int maxFreeTime(int eventTime, int* startTime, int startTimeSize, int* endTime, int endTimeSize) {
    int n = startTimeSize;
    bool* q = (bool*)calloc(n, sizeof(bool));
    int t1 = 0, t2 = 0;
    for (int i = 0; i < n; i++) {
        if (endTime[i] - startTime[i] <= t1) {
            q[i] = true;
        }
        t1 = fmax(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

        if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
            q[n - i - 1] = true;
        }
        t2 = fmax(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
    }

    int res = 0;
    for (int i = 0; i < n; i++) {
        int left = i == 0 ? 0 : endTime[i - 1];
        int right = i == n - 1 ? eventTime : startTime[i + 1];
        if (q[i]) {
            res = fmax(res, right - left);
        } else {
            res = fmax(res, right - left - (endTime[i] - startTime[i]));
        }
    }
    free(q);
    return res;
}

###Rust

impl Solution {
    pub fn max_free_time(event_time: i32, start_time: Vec<i32>, end_time: Vec<i32>) -> i32 {
        let n = start_time.len();
        let mut q = vec![false; n];
        let mut t1 = 0;
        let mut t2 = 0;
        for i in 0..n {
            if end_time[i] - start_time[i] <= t1 {
                q[i] = true;
            }
            t1 = t1.max(start_time[i] - if i == 0 { 0 } else { end_time[i - 1] });

            let j = n - i - 1;
            if end_time[j] - start_time[j] <= t2 {
                q[j] = true;
            }
            t2 = t2.max(if i == 0 { event_time } else { start_time[n - i] } - end_time[j]);
        }

        let mut res = 0;
        for i in 0..n {
            let left = if i == 0 { 0 } else { end_time[i - 1] };
            let right = if i == n - 1 { event_time } else { start_time[i + 1] };
            if q[i] {
                res = res.max(right - left);
            } else {
                res = res.max(right - left - (end_time[i] - start_time[i]));
            }
        }
        res
    }
}

复杂度分析

  • 时间复杂度:$O(n)$,其中 $n$ 是所有会议的数目。

  • 空间复杂度:$O(n)$。

方法二:贪心 + 优化

方法一中使用了 $q[i]$ 来判断会议 $i$ 平移的最优解,如果我们在枚举会议 $i$ 的过程中对会议 $i$ 平移的两种情况进行计算,那么就可以去掉数组 $q$。具体过程如下:

  • 枚举平移的会议,将该会议左右两侧相邻的空余时间段进行合并,计算得到的新的空余时间段的时长。

  • 从左到右枚举平移的会议,同时用 $t_1$ 记录当前遍历到的会议左侧非相邻的空余时间段的最大时长,如果当前会议时长小于等于 $t_1$,那么说明该会议可以平移到 $t_1$ 对应的空余时间段,计算平移后得到的新的空余时间段的时长。

  • 从右到左枚举平移的会议,同时用 $t_2$ 记录当前遍历到的会议右侧非相邻的空余时间段的最大时长,如果当前会议时长小于等于 $t_2$,那么说明该会议可以平移到 $t_2$ 对应的空余时间段,计算平移后得到的新的空余时间段的时长。

返回以上所有新的空余时间段时长的最大值。

###C++

class Solution {
public:
    int maxFreeTime(int eventTime, vector<int>& startTime, vector<int>& endTime) {
        int n = startTime.size(), res = 0;
        for (int i = 0, t1 = 0, t2 = 0; i < n; i++) {
            int left1 = i == 0 ? 0 : endTime[i - 1];
            int right1 = i == n - 1 ? eventTime : startTime[i + 1];
            if (endTime[i] - startTime[i] <= t1) {
                res = max(res, right1 - left1);
            }
            t1 = max(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

            res = max(res, right1 - left1 - (endTime[i] - startTime[i]));

            int left2 = i == n - 1 ? 0 : endTime[n - i - 2];
            int right2 = i == 0 ? eventTime : startTime[n - i];
            if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
                res = max(res, right2 - left2);
            }
            t2 = max(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
        }
        return res;
    }
};

###Go

func maxFreeTime(eventTime int, startTime []int, endTime []int) int {
n := len(startTime)
q := make([]bool, n)
t1, t2 := 0, 0
for i := 0; i < n; i++ {
if endTime[i] - startTime[i] <= t1 {
q[i] = true
}
if i == 0 {
t1 = max(t1, startTime[i])
} else {
t1 = max(t1, startTime[i] - endTime[i - 1])
}

if endTime[n - i - 1] - startTime[n - i - 1] <= t2 {
q[n - i - 1] = true
}
if i == 0 {
t2 = max(t2, eventTime - endTime[n - 1])
} else {
t2 = max(t2, startTime[n - i] - endTime[n - i - 1])
}
}

res := 0
for i := 0; i < n; i++ {
left := 0
if i != 0 {
left = endTime[i - 1]
}
right := eventTime
if i != n - 1 {
right = startTime[i + 1]
}
if q[i] {
res = max(res, right - left)
} else {
res = max(res, right - left - (endTime[i] - startTime[i]))
}
}
return res
}

###Python

class Solution:
    def maxFreeTime(self, eventTime: int, startTime: list[int], endTime: list[int]) -> int:
        n = len(startTime)
        q = [False] * n
        t1 = 0
        t2 = 0
        for i in range(n):
            if endTime[i] - startTime[i] <= t1:
                q[i] = True
            t1 = max(t1, startTime[i] - (0 if i == 0 else endTime[i - 1]))

            if endTime[n - i - 1] - startTime[n - i - 1] <= t2:
                q[n - i - 1] = True
            t2 = max(t2, (eventTime if i == 0 else startTime[n - i]) - endTime[n - i - 1])

        res = 0
        for i in range(n):
            left = 0 if i == 0 else endTime[i - 1]
            right = eventTime if i == n - 1 else startTime[i + 1]
            if q[i]:
                res = max(res, right - left)
            else:
                res = max(res, right - left - (endTime[i] - startTime[i]))
        return res

###Java

class Solution {
    public int maxFreeTime(int eventTime, int[] startTime, int[] endTime) {
        int n = startTime.length;
        boolean[] q = new boolean[n];
        for (int i = 0, t1 = 0, t2 = 0; i < n; i++) {
            if (endTime[i] - startTime[i] <= t1) {
                q[i] = true;
            }
            t1 = Math.max(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

            if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
                q[n - i - 1] = true;
            }
            t2 = Math.max(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
        }

        int res = 0;
        for (int i = 0; i < n; i++) {
            int left = i == 0 ? 0 : endTime[i - 1];
            int right = i == n - 1 ? eventTime : startTime[i + 1];
            if (q[i]) {
                res = Math.max(res, right - left);
            } else {
                res = Math.max(res, right - left - (endTime[i] - startTime[i]));
            }
        }
        return res;
    }
}

###TypeScript

function maxFreeTime(eventTime: number, startTime: number[], endTime: number[]): number {
    const n = startTime.length;
    const q: boolean[] = new Array(n).fill(false);
    let t1 = 0, t2 = 0;
    for (let i = 0; i < n; i++) {
        if (endTime[i] - startTime[i] <= t1) {
            q[i] = true;
        }
        t1 = Math.max(t1, startTime[i] - (i === 0 ? 0 : endTime[i - 1]));

        if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
            q[n - i - 1] = true;
        }
        t2 = Math.max(t2, (i === 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
    }

    let res = 0;
    for (let i = 0; i < n; i++) {
        const left = i === 0 ? 0 : endTime[i - 1];
        const right = i === n - 1 ? eventTime : startTime[i + 1];
        if (q[i]) {
            res = Math.max(res, right - left);
        } else {
            res = Math.max(res, right - left - (endTime[i] - startTime[i]));
        }
    }
    return res;
}

###JavaScript

var maxFreeTime = function(eventTime, startTime, endTime) {
    const n = startTime.length;
    const q = new Array(n).fill(false);
    let t1 = 0, t2 = 0;
    for (let i = 0; i < n; i++) {
        if (endTime[i] - startTime[i] <= t1) {
            q[i] = true;
        }
        t1 = Math.max(t1, startTime[i] - (i === 0 ? 0 : endTime[i - 1]));

        if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
            q[n - i - 1] = true;
        }
        t2 = Math.max(t2, (i === 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
    }

    let res = 0;
    for (let i = 0; i < n; i++) {
        const left = i === 0 ? 0 : endTime[i - 1];
        const right = i === n - 1 ? eventTime : startTime[i + 1];
        if (q[i]) {
            res = Math.max(res, right - left);
        } else {
            res = Math.max(res, right - left - (endTime[i] - startTime[i]));
        }
    }
    return res;
};

###C#

public class Solution {
    public int MaxFreeTime(int eventTime, int[] startTime, int[] endTime) {
        int n = startTime.Length;
        bool[] q = new bool[n];
        int t1 = 0, t2 = 0;
        for (int i = 0; i < n; i++) {
            if (endTime[i] - startTime[i] <= t1) {
                q[i] = true;
            }
            t1 = Math.Max(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

            if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
                q[n - i - 1] = true;
            }
            t2 = Math.Max(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
        }

        int res = 0;
        for (int i = 0; i < n; i++) {
            int left = i == 0 ? 0 : endTime[i - 1];
            int right = i == n - 1 ? eventTime : startTime[i + 1];
            if (q[i]) {
                res = Math.Max(res, right - left);
            } else {
                res = Math.Max(res, right - left - (endTime[i] - startTime[i]));
            }
        }
        return res;
    }
}

###C

int maxFreeTime(int eventTime, int* startTime, int startTimeSize, int* endTime, int endTimeSize) {
    int n = startTimeSize;
    bool* q = (bool*)calloc(n, sizeof(bool));
    int t1 = 0, t2 = 0;
    for (int i = 0; i < n; i++) {
        if (endTime[i] - startTime[i] <= t1) {
            q[i] = true;
        }
        t1 = fmax(t1, startTime[i] - (i == 0 ? 0 : endTime[i - 1]));

        if (endTime[n - i - 1] - startTime[n - i - 1] <= t2) {
            q[n - i - 1] = true;
        }
        t2 = fmax(t2, (i == 0 ? eventTime : startTime[n - i]) - endTime[n - i - 1]);
    }

    int res = 0;
    for (int i = 0; i < n; i++) {
        int left = i == 0 ? 0 : endTime[i - 1];
        int right = i == n - 1 ? eventTime : startTime[i + 1];
        if (q[i]) {
            res = fmax(res, right - left);
        } else {
            res = fmax(res, right - left - (endTime[i] - startTime[i]));
        }
    }
    free(q);
    return res;
}

###Rust

impl Solution {
    pub fn max_free_time(event_time: i32, start_time: Vec<i32>, end_time: Vec<i32>) -> i32 {
        let n = start_time.len();
        let mut q = vec![false; n];
        let mut t1 = 0;
        let mut t2 = 0;
        for i in 0..n {
            if end_time[i] - start_time[i] <= t1 {
                q[i] = true;
            }
            t1 = t1.max(start_time[i] - if i == 0 { 0 } else { end_time[i - 1] });

            let j = n - i - 1;
            if end_time[j] - start_time[j] <= t2 {
                q[j] = true;
            }
            t2 = t2.max(if i == 0 { event_time } else { start_time[n - i] } - end_time[j]);
        }

        let mut res = 0;
        for i in 0..n {
            let left = if i == 0 { 0 } else { end_time[i - 1] };
            let right = if i == n - 1 { event_time } else { start_time[i + 1] };
            if q[i] {
                res = res.max(right - left);
            } else {
                res = res.max(right - left - (end_time[i] - start_time[i]));
            }
        }
        res
    }
}

复杂度分析

  • 时间复杂度:$O(n)$,其中 $n$ 是所有会议的数目。

  • 空间复杂度:$O(1)$。

维护前三大的空位+枚举+分类讨论(Python/Java/C++/Go)

把会议区间视作桌子,空余时间视作空位,我们要把一个桌子移到别的空位中。

初步想法是枚举桌子,找一个长度大于等于桌子长度的空位移过去。看上去,找一个长度最长的空位就好了。

但万一最长空位与桌子相邻呢?这并没有把桌子彻底移出去。

找次长的空位?万一最长空位和次长空位都与桌子相邻呢?

那就再找第三长的。不可能有三个空位都与同一个桌子相邻。

核心思路:计算长度最长的三个空位在哪,其中一定有一个空位不在移出去的桌子的左右两侧。如果空位长度大于等于桌子的长度,我们把桌子移到这个空位中。

设最大的三个空位所在的位置(下标)分别是 $a,b,c$。

枚举桌子,分类讨论:

  • 如果桌子左右两侧的空位没有 $a$,那么把桌子移到 $a$。
  • 否则,如果桌子左右两侧的空位没有 $b$,那么把桌子移到 $b$。
  • 否则,把桌子移到 $c$。

继续分类讨论:

  • 如果能移(有足够长的空位),新的空位长度 = 桌子长度 + 桌子左右两侧的空位长度。
  • 如果不能移,那么只能移到左右相邻的桌子旁边,新的空位长度 = 桌子左右两侧的空位长度。

具体请看 视频讲解,欢迎点赞关注~

###py

class Solution:
    def maxFreeTime(self, eventTime: int, startTime: List[int], endTime: List[int]) -> int:
        n = len(startTime)

        # 计算空位长度
        def get(i: int) -> int:
            if i == 0:
                return startTime[0]
            if i == n:
                return eventTime - endTime[n - 1]
            return startTime[i] - endTime[i - 1]

        # 有 n+1 个空位,计算前三大的空位在哪
        a, b, c = 0, -1, -1
        for i in range(1, n + 1):
            sz = get(i)
            if sz > get(a):
                a, b, c = i, a, b
            elif b < 0 or sz > get(b):
                b, c = i, b
            elif c < 0 or sz > get(c):
                c = i

        ans = 0
        # 枚举桌子
        for i, (s, e) in enumerate(zip(startTime, endTime)):
            sz = e - s
            if i != a and i + 1 != a and sz <= get(a) or \
               i != b and i + 1 != b and sz <= get(b) or \
               sz <= get(c):  # 可以移出去
                ans = max(ans, get(i) + sz + get(i + 1))
            else:
                ans = max(ans, get(i) + get(i + 1))
        return ans

###py

class Solution:
    def maxFreeTime(self, eventTime: int, startTime: List[int], endTime: List[int]) -> int:
        free = [startTime[0]] + [s - e for s, e in zip(startTime[1:], endTime)] + [eventTime - endTime[-1]]

        a = b = c = -1
        for i, sz in enumerate(free):
            if a < 0 or sz > free[a]:
                a, b, c = i, a, b
            elif b < 0 or sz > free[b]:
                b, c = i, b
            elif c < 0 or sz > free[c]:
                c = i

        ans = 0
        for i, (s, e) in enumerate(zip(startTime, endTime)):
            sz = e - s
            if i != a and i + 1 != a and sz <= free[a] or \
               i != b and i + 1 != b and sz <= free[b] or \
               sz <= free[c]:
                ans = max(ans, free[i] + sz + free[i + 1])
            else:
                ans = max(ans, free[i] + free[i + 1])
        return ans

###java

class Solution {
    private int eventTime;
    private int[] startTime, endTime;

    public int maxFreeTime(int eventTime, int[] startTime, int[] endTime) {
        this.eventTime = eventTime;
        this.startTime = startTime;
        this.endTime = endTime;
        int n = startTime.length;

        // 有 n+1 个空位,计算前三大的空位在哪
        int a = 0, b = -1, c = -1;
        for (int i = 1; i <= n; i++) {
            int sz = get(i);
            if (sz > get(a)) {
                c = b; b = a; a = i;
            } else if (b < 0 || sz > get(b)) {
                c = b; b = i;
            } else if (c < 0 || sz > get(c)) {
                c = i;
            }
        }

        int ans = 0;
        // 枚举桌子
        for (int i = 0; i < n; i++) {
            int sz = endTime[i] - startTime[i];
            if (i != a && i + 1 != a && sz <= get(a) ||
                i != b && i + 1 != b && sz <= get(b) ||
                sz <= get(c)) { // 可以移出去
                ans = Math.max(ans, get(i) + sz + get(i + 1));
            } else {
                ans = Math.max(ans, get(i) + get(i + 1));
            }
        }
        return ans;
    }

    // 计算空位长度
    private int get(int i) {
        if (i == 0) {
            return startTime[0];
        }
        int n = startTime.length;
        if (i == n) {
            return eventTime - endTime[n - 1];
        }
        return startTime[i] - endTime[i - 1];
    }
}

###cpp

class Solution {
public:
    int maxFreeTime(int eventTime, vector<int>& startTime, vector<int>& endTime) {
        int n = startTime.size();

        // 计算空位长度
        auto get = [&](int i) -> int {
            if (i == 0) {
                return startTime[0];
            }
            if (i == n) {
                return eventTime - endTime[n - 1];
            }
            return startTime[i] - endTime[i - 1];
        };

        // 有 n+1 个空位,计算前三大的空位在哪
        int a = 0, b = -1, c = -1;
        for (int i = 1; i <= n; i++) {
            int sz = get(i);
            if (sz > get(a)) {
                c = b; b = a; a = i;
            } else if (b < 0 || sz > get(b)) {
                c = b; b = i;
            } else if (c < 0 || sz > get(c)) {
                c = i;
            }
        }

        int ans = 0;
        // 枚举桌子
        for (int i = 0; i < n; i++) {
            int sz = endTime[i] - startTime[i];
            if (i != a && i + 1 != a && sz <= get(a) ||
                i != b && i + 1 != b && sz <= get(b) ||
                sz <= get(c)) { // 可以移出去
                ans = max(ans, get(i) + sz + get(i + 1));
            } else {
                ans = max(ans, get(i) + get(i + 1));
            }
        }
        return ans;
    }
};

###go

func maxFreeTime(eventTime int, startTime, endTime []int) (ans int) {
    n := len(startTime)

    // 计算空位长度
    get := func(i int) int {
        if i == 0 {
            return startTime[0]
        }
        if i == n {
            return eventTime - endTime[n-1]
        }
        return startTime[i] - endTime[i-1]
    }

    // 有 n+1 个空位,计算前三大的空位在哪
    a, b, c := 0, -1, -1
    for i := 1; i <= n; i++ {
        sz := get(i)
        if sz > get(a) {
            a, b, c = i, a, b
        } else if b < 0 || sz > get(b) {
            b, c = i, b
        } else if c < 0 || sz > get(c) {
            c = i
        }
    }

    // 枚举桌子
    for i, e := range endTime {
        sz := e - startTime[i]
        if i != a && i+1 != a && sz <= get(a) ||
            i != b && i+1 != b && sz <= get(b) ||
            sz <= get(c) { // 可以移出去
            ans = max(ans, get(i)+sz+get(i+1))
        } else {
            ans = max(ans, get(i)+get(i+1))
        }
    }
    return ans
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(n)$,其中 $n$ 是 $\textit{startTime}$ 的长度。
  • 空间复杂度:$\mathcal{O}(1)$。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、二叉树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA/一般树)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

❌