2024D-找座位
2024D-找座位
题目描述与示例
题目描述
疫情期间课堂的座位进行了特殊的调整,不能出现两个同学紧挨着,必须隔至少一个空位。
给你一个整数数组 desk
表示当前座位的占座情况,由若干 0
和 1
组成,其中 0
表示没有占位,1
表示占位。在不改变原有座位秩序情况下,还能安排坐几个人?
输入
第一行是个子数组表示作为占座情况,由若干 0
和 1
组成,其中 0
表示没有占位,1
表示占位
输出
输出数值表示还能坐几个人
说明
1 <= desk.length <= 2 * 10^4
示例一
输入
1,0,0,0,1
输出
1
说明
只有 desk[2]
的位置可以坐一个人
示例二
输入
0,0,0,0,0
输出
3
解题思路
注意,本题和LC605. 种花问题几乎完全一致。
很多同学对这个经典的贪心问题感到混乱。
只知道应该在一个while
循环下进行不定步长的索引前进,但是具体如何实现,仍然容易搞不清楚。
注意题目中有一个非常重要的隐藏条件:原数组中不会出现连续的两个紧挨着的1
。
在考虑位置i
的近邻位置的时候,我们始终只考虑i
后面的位置(比如i+1
、i+2
、i+3
),而不会向前考虑i
前面的位置(比如i-1
)。
这是因为,i
前面的位置是否为1
,已经在考虑i
前面位置时的向后考虑判断过了。
实际上,对于任意一个位置i
,只可能出现以下3
种情况。
注意,x
表示既可能是0
也可能是1
,是后续要跳到的位置。
- 情况1:第
i
个位置是1
。那么第i+1
个位置一定是0
。下一步我们需要跳到第i+2
的位置。在第i
个位置和第i+1
个位置我们都不能种花。种花数目不需要修改。
i i+2
↓ ↓
1 0 x
- 情况2:第
i
个位置是0
,第i+1
个位置也是0
。下一步我们需要跳到第i+2
的位置。我们贪心地选择在第i
个位置种花。种花数目修改。
i i+2
↓ ↓
0 0 x
- 情况3:第
i
个位置是0
,第i+1
个位置是1
,那么第i+2
个位置一定是0
,下一步我们需要跳到第i+3
的位置。在第i
个、第i+1
个、第i+2
个位置我们都不能种花。种花数目不修改。
i i+3
↓ ↓
0 1 0 x
我们可以看到,每次进行索引更新之后,x
(不管x
是1
还是0
),x
的前一个位置,都一定是0
。
所以我们不需要去考虑i-1
的情况,只需要考虑i
后面位置的索引的情况。
另外,就是边界值的处理。对于情况2而言,如果lst[i]
为0
,且已经到达了数组的最后一个位置lst[n-1]
,那么同样要进行答案更新。
代码
Python
# 题目:2024D-座位调整
# 分值:100
# 作者:许老师-闭着眼睛学数理化
# 算法:贪心
# 代码看不懂的地方,请直接在群上提问
# 输入的座位数组
lst = input().split(",")
# 能坐下的总人数
ans = 0
# 遍历数组,在遍历过程中,采取贪心的思路,并不需要【每个位置】都去查看是否可以坐下
# 1、当前位置已经有人坐下,那么后一个位置明显不能坐下,可以跳过去
# 2、当前位置没有人坐下,需要考虑后面一个位置是否有人已经坐下
# 初始化座位索引为0
i = 0
while i < len(lst):
# 对应情况1
# 1、当前位置已经有人坐下,lst[i] == "1",那么后一个位置明显不能坐下,可以跳过去
# 所以让 i 执行加 2 操作,跳过了加 1 后的那个位置
if lst[i] == "1":
# 让 i 执行加 2 操作
i += 2
# 2、否则说明当前位置没有人坐下 lst[i] == "0"
else:
# 对应情况2
# 3、如果这个位置【是】数组的最后一个位置,说明后一个位置不存在,没有限制,说明 lst[i] 可以坐下
# 4、如果这个位置【不是】数组的最后一个位置,那么只有当后一个位置【没人坐下】,才有资格在 lst[i] 位置坐下
# 这两种条件都可以在 lst[i] 位置坐下
if i == len(lst) - 1 or lst[i + 1] == "0":
# 成功之后,坐下人数ans + 1
ans += 1
# 在 lst[i] 位置种花之后,i + 1 位置不需要去考虑了,因为它明显不能种花,可以跳过去
# 让 i 执行加 2 操作
i += 2
# 对应情况3
# 5、当前位置没有人坐下 lst[i] == "0"
# 6、但是后一个位置已经有人坐下了,那么当前位置无法坐下
# i + 1 位置已经坐下,不用再去访问一遍
# i + 2 位置考虑到 i + 1 位置已经有人坐下,所以也无法坐下,不用再去访问
# 让 i 执行加 3 操作
else:
i += 3
print(ans)
Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] lst = scanner.nextLine().split(",");
int ans = 0;
int i = 0;
while (i < lst.length) {
if (lst[i].equals("1")) {
i += 2;
} else {
if (i == lst.length - 1 || lst[i + 1].equals("0")) {
ans += 1;
i += 2;
} else {
i += 3;
}
}
}
System.out.println(ans);
}
}
C++
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
string line;
getline(cin, line);
istringstream iss(line);
vector<string> lst;
string val;
while (getline(iss, val, ',')) {
lst.push_back(val);
}
int ans = 0;
int i = 0;
while (i < lst.size()) {
if (lst[i] == "1") {
i += 2;
} else {
if (i == lst.size() - 1 || lst[i + 1] == "0") {
ans += 1;
i += 2;
} else {
i += 3;
}
}
}
cout << ans << endl;
return 0;
}
时空复杂度
时间复杂度:O(N)
。仅需一次遍历数组
空间复杂度:O(1)
。仅需要用到若干常数变量。
相同问题不同描述
2024D-找座位
题目描述
在一个大型体育场内举办了一场大型活动,由于疫情防控的需要,要求每位观众的必须间隔至少一个空位才允许落座。现在给出一排观众座位分布图,座位中存在已落座的观众,请计算出,在不移动现有观众座位的情况下,最多还能坐下多少名观众。
输入描述
一个数组,用来标识某一排座位中,每个座位是否已经坐人。0
表示该座位没有坐人,1
表示该座位已经坐人。 1 <= 数组长度 <= 10000
输出描述
整数,在不移动现有观众座位的情况下,最多还能坐下多少名观众。
示例一
输入
10001
输出
1
示例二
输入
0101
输出
0