第149场双周赛:找到字符串中合法的相邻数字、重新安排会议得到最多空余时间 Ⅰ、

Q1、找到字符串中合法的相邻数字

1、题目描述

给你一个只包含数字的字符串 s 。如果 s 中两个 相邻 的数字满足以下条件,我们称它们是 合法的

  • 前面的数字 不等于 第二个数字。
  • 两个数字在 s 中出现的次数 恰好 分别等于这个数字本身。

请你从左到右遍历字符串 s ,并返回最先找到的 合法 相邻数字。如果这样的相邻数字不存在,请你返回一个空字符串。

示例 1:

**输入:**s = “2523533”

输出:“23”

解释:

数字 '2' 出现 2 次,数字 '3' 出现 3 次。"23" 中每个数字在 s 中出现的次数都恰好分别等于数字本身。所以输出 "23"

示例 2:

**输入:**s = “221”

输出:“21”

解释:

数字 '2' 出现 2 次,数字 '1' 出现 1 次。所以输出 "21"

示例 3:

**输入:**s = “22”

输出:“”

解释:

没有合法的相邻数字。

2、解题思路
  1. 计数
    首先,我们需要计算字符串中每个数字出现的次数。因为 s 只包含数字字符 '0''9',我们可以利用一个长度为 10 的数组 hash 来记录每个数字出现的次数。

  2. 检查合法性
    然后,我们通过遍历字符串 s,对于每一对相邻的数字,检查是否满足以下条件:

    • 这两个数字不相等。

    • 这两个数字的出现次数分别等于它们本身的数字值。

  3. 返回结果
    如果找到符合条件的相邻数字,直接返回这两个数字;如果遍历完整个字符串都没有找到符合条件的数字对,返回空字符串。

3、代码实现
C++
class Solution {
public:
    string findValidPair(string s) {
        int n = s.size(); // 获取字符串的长度
        int hash[10] = {0}; // 初始化一个长度为 10 的数组, 用来存储每个数字出现的次数

        // 第一次遍历字符串, 计算每个数字的出现次数
        for (const auto& ch : s) {
            hash[ch - '0']++; // 将字符转为对应的数字, 并在数组中对应位置计数
        }

        // 第二次遍历字符串, 检查相邻数字是否符合条件
        for (int i = 0; i < n - 1; ++i) {
            // 判断当前数字与下一个数字是否符合条件
            if (hash[s[i] - '0'] == s[i] - '0' && s[i] != s[i + 1] && hash[s[i + 1] - '0'] == s[i + 1] - '0') {
                // 返回符合条件的相邻数字
                return s.substr(i, 2);
            }
        }

        // 如果没有找到符合条件的相邻数字, 返回空字符串
        return {};
    }
};
Python
class Solution:
    def findValidPair(self, s: str) -> str:
        n = len(s)              # 获取字符串的长度
        hash = [0] * 10         # 初始化一个长度为 10 的数组, 用来存储每个数字出现的次数

        # 第一次遍历字符串, 计算每个数字的出现次数
        for ch in s:
            hash[int(ch)] += 1  # 将字符转为对应的数字, 并且对数字出现频率计数

        # 第二次遍历字符串, 检查相邻数字是否符合条件
        for i in range(n - 1):
            # 判断当前数字与下一个数字是否符合条件
            if (
                hash[int(s[i])] == int(s[i])    # 当前数字的出现次数等于其本身
                and s[i] != s[i+1]              # 两个数字不相等
                and hash[int(s[i + 1])] == int(s[i + 1])    # 下一个数字的出现次数等于其本身
            ):
                # 返回符合条件的相邻数字
                return s[i : i + 2]

        # 如果没有找到符合条件的相邻数字, 返回空字符串
        return ""
4、复杂度分析
  • 时间复杂度

    • 第一遍遍历字符串 s 来统计每个数字的出现次数的时间复杂度是 O(n),其中 n 是字符串的长度。

    • 第二遍遍历字符串 s 来检查相邻的数字对的合法性,时间复杂度也是 O(n)

​ 因此,总的时间复杂度是 O(n)

  • 空间复杂度
    • 我们使用了一个长度为 10 的数组 hash 来存储每个数字的出现次数。由于该数组大小是固定的,所以空间复杂度为 O(1)

Q2、重新安排会议得到最多空余时间 Ⅰ

1、题目描述

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

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

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

移动前后所有会议之间的 相对 顺序需要保持不变,而且会议时间也需要保持互不重叠。

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

注意,会议 不能 安排到整个活动的时间以外。

示例 1:

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

**输出:**2

解释:

img

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

示例 2:

**输入:**eventTime = 10, k = 1, startTime = [0,2,9], endTime = [1,4,10]

**输出:**6

解释:

img

[2, 4] 的会议安排到 [1, 3] ,得到空余时间 [3, 9]

示例 3:

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

**输出:**0

解释:

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

2、解题思路

这是一个滑动窗口问题。我们可以通过以下步骤来解决:

  1. 计算空余时间
    • 定义 get(i) 函数,计算第 i 个会议之前的空余时间。
    • 如果 i == 0,空余时间为 startTime[0]
    • 如果 i == n,空余时间为 eventTime - endTime[n - 1]
    • 否则,空余时间为 startTime[i] - endTime[i - 1]
  2. 滑动窗口
    • 使用滑动窗口维护一个大小为 k + 1 的窗口,计算窗口内的空余时间和。
    • 当窗口大小超过 k + 1 时,移除窗口最左边的空余时间。
  3. 返回结果
    • 返回滑动窗口中的最大空余时间和。
3、代码实现
C++
class Solution {
public:
    int maxFreeTime(int eventTime, int k, vector<int>& startTime, vector<int>& endTime) {
        int n = startTime.size();

        // 计算第 i 个会议之前的空余时间
        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];
        };

        // sum 表示当前窗口的空余时间和, ret 表示最大空余时间和
        int sum = 0, ret = 0;
        for (int i = 0; i <= n; ++i) {
            sum += get(i); // 将当前空余时间加入窗口
            if (i < k) {
                continue; // 窗口大小不足 k+1, 继续扩展
            }
            ret = max(ret, sum); // 更新最大空余时间和
            sum -= get(i - k);   // 移除窗口最左边的空余时间
        }
        return ret; // 返回结果
    }
};
Python
class Solution:
    def maxFreeTime(self, eventTime: int, k: int, startTime: List[int], endTime: List[int]) -> int:
        n = len(startTime)

        # 计算第 i 个会议之前的空余空间
        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]

        # sum 表示当前窗口的空余时间和, ret 表示最大空余时间和
        sum, ret = 0, 0
        for i in range(n + 1):
            sum += get(i)       # 将当前空余时间加入窗口
            if i < k:
                continue        # 窗口大小不足 k+1, 继续扩展
            ret = max(ret, sum) # 更新最大空余时间和
            sum -= get(i - k)   # 移除窗口最左边的空余时间

        return ret
4、复杂度分析
  • 时间复杂度
    • 遍历空余时间数组:O(n)
    • 每个空余时间的计算:O(1)
    • 总时间复杂度:O(n)
  • 空间复杂度
    • 只使用了常数级别的额外空间。
    • 总空间复杂度:O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lenyiin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值