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、解题思路
-
计数:
首先,我们需要计算字符串中每个数字出现的次数。因为s
只包含数字字符'0'
到'9'
,我们可以利用一个长度为 10 的数组hash
来记录每个数字出现的次数。 -
检查合法性:
然后,我们通过遍历字符串s
,对于每一对相邻的数字,检查是否满足以下条件:-
这两个数字不相等。
-
这两个数字的出现次数分别等于它们本身的数字值。
-
-
返回结果:
如果找到符合条件的相邻数字,直接返回这两个数字;如果遍历完整个字符串都没有找到符合条件的数字对,返回空字符串。
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)
。
- 我们使用了一个长度为 10 的数组
Q2、重新安排会议得到最多空余时间 Ⅰ
1、题目描述
给你一个整数 eventTime
表示一个活动的总时长,这个活动开始于 t = 0
,结束于 t = eventTime
。
同时给你两个长度为 n
的整数数组 startTime
和 endTime
。它们表示这次活动中 n
个时间 没有重叠 的会议,其中第 i
个会议的时间为 [startTime[i], endTime[i]]
。
你可以重新安排 至多 k
个会议,安排的规则是将会议时间平移,且保持原来的 会议时长 ,你的目的是移动会议后 最大化 相邻两个会议之间的 最长 连续空余时间。
移动前后所有会议之间的 相对 顺序需要保持不变,而且会议时间也需要保持互不重叠。
请你返回重新安排会议以后,可以得到的 最大 空余时间。
注意,会议 不能 安排到整个活动的时间以外。
示例 1:
**输入:**eventTime = 5, k = 1, startTime = [1,3], endTime = [2,5]
**输出:**2
解释:
将
[1, 2]
的会议安排到[2, 3]
,得到空余时间[0, 2]
。示例 2:
**输入:**eventTime = 10, k = 1, startTime = [0,2,9], endTime = [1,4,10]
**输出:**6
解释:
将
[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、解题思路
这是一个滑动窗口问题。我们可以通过以下步骤来解决:
- 计算空余时间:
- 定义
get(i)
函数,计算第i
个会议之前的空余时间。 - 如果
i == 0
,空余时间为startTime[0]
。 - 如果
i == n
,空余时间为eventTime - endTime[n - 1]
。 - 否则,空余时间为
startTime[i] - endTime[i - 1]
。
- 定义
- 滑动窗口:
- 使用滑动窗口维护一个大小为
k + 1
的窗口,计算窗口内的空余时间和。 - 当窗口大小超过
k + 1
时,移除窗口最左边的空余时间。
- 使用滑动窗口维护一个大小为
- 返回结果:
- 返回滑动窗口中的最大空余时间和。
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)
。