1 陶陶摘苹果
题目描述
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 30 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。 现在已知 10 个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
AC 代码
int solution(int arr[10], int max_tourch_height) {
int result = 0;
for (int i = 0; i < 10; ++i) {
if (max_tourch_height+30 >= arr[i]) {
++result;
}
}
return result;
}
2 交际圈
题目描述
小明参加了个大型聚会。聚会上有n个人参加,我们将他们编号为1…n,有些人已经互相认识了,有些人还不认识。聚会开始后,假设A跟B认识,A会给所有他认识的人介绍B,原先跟A认识,但不认识B的人,都会在此时,跟B互相认识。当所有人都把自己认识的人介绍一遍后,此时n个人就会形成k个交际圈,同一个交际圈中,两两互相认识,不同的交际圈之间,互相不认识 问题:当所有人都把自己认识的人介绍一遍后,形成了多少个交际圈?
思路
建立并查集,最后找出极大连通子图的个数。
个人对并查集的理解,可以概括为一句话:查他祖宗十八代
AC 代码
class UnionSet { // 并查集的英文好像是 `Union-Find Set` 或 `Disjoint-Set`,但是赛时没想起来这个词
public:
UnionSet(const int n_) {
n = n_;
ancestor = new int[n+1];
for (int i = n; i > 0; --i) {
ancestor[i] = i;
}
}
// 联通编号为 u 和 v 的节点
void add(const int u, const int v) {
ancestor[findAncestor(u)] = findAncestor(v);
}
int findAncestor(const int node) {
if (ancestor[node] != node) {
ancestor[node] = findAncestor(ancestor[node]);
}
return ancestor[node];
}
// 获取连通分量个数
int numAncestors() {
int ans = 0;
for (int i = n; i > 0; --i) {
if (ancestor[i] == i) {
++ans;
}
}
return ans;
}
int n;
int* ancestor;
};
int solution(int n, int m, std::vector<std::vector<std::string>>& matrix){
int result;
UnionSet us(n);
for (int i = 0; i < m; ++i) {
const int u = atoi(matrix[i][0].data());
const int v = atoi(matrix[i][1].data());
us.add(u, v);
}
result = us.numAncestors();
return result;
}
3 编码
题目描述
编码工作常被运用于密文或压缩传输。这里我们用一种最简单的编码方式进行编码:把一些有规律的单词编成数字。 字母表中共有26个字母{a,b,…,z},这些特殊的单词长度不超过6且字母按升序排列。把所有这样的长度相同的单词放在一起,按字典顺序排列,一个单词的编码就对应着它在整个序列中的位置。 你的任务就是对于所给的单词,求出它的编码。
思路
首先找出非法输入,非法输入是指存在后面的字符比前面的字符大的字符串。
接着用暴力,枚举编码所对应的字符串,直到找到所求字符串。
这一题的关键是找到一个字符串所对应的下一个字符串,具体算法这里不介绍,直接看代码。
AC 代码
void next(char str[]) {
const int len = strlen(str);
if (str[len-1] == 'z') {
int i = len - 2;
while (i >= 0 && str[i]+1 == str[i+1]) {
--i;
}
if (i < 0) {
for (i = 0; i <= len; ++i) {
str[i] = i + 'a';
}
} else {
++str[i];
for (++i; i < len; ++i) {
str[i] = str[i-1]+1;
}
}
} else {
++str[len-1];
}
}
int solution(std::string word){
int result = 1;
for (int i = 1; (size_t) i < word.length(); ++i) {
if (word[i] <= word[i-1]) {
return 0;
}
}
char str[10]{"a"};
while (strcmp(str, word.data()) != 0) {
next(str);
++result;
}
return result;
}
4 选择客栈
题目描述
丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到 n 编号。每家客栈都按照某一种色调进行装饰(总共 k
种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。 两位游客一起去丽江旅
游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一
家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过 p 。 他们想
知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 p 元的咖啡店小聚。
思路
针对每一种颜色各做一次计算:记录并维护已知的消费得起的客栈数目和消费不起的客栈数目,从前向后遍历咖啡店的最低消费,根据客栈的颜色和价格更新两个记录。
代码
int solution(int n, int k, int p, std::vector<std::vector<std::string>>& vec){
int result = 0;
int* colors = new int[n+1];
int* prices = new int[n+1];
for (int i = 0; i < n; ++i) { // 读取输入数据
colors[i] = atoi(vec[i][0].data());
prices[i] = atoi(vec[i][1].data());
}
// O(n * k)
for (int i = 0; i < k; ++i) { // i 代表一种颜色
int j = 0; // j 代表客栈编号
int numAfford = 0;
int numDisford = 0; // 没有一个词叫 disford,这是我临场造的词,表示“买不起”
for (; j < n && colors[j] != i; ++j) // 找到第一家颜色符合要求的客栈
/* nothing */;
for (; j < n; ++j) {
if (colors[j] == i) { // 客栈的颜色符合要求
if (prices[j] > p) { // 无法在客栈配套的咖啡厅消费,拿小伙伴就只能去更前面的客栈
result += numAfford;
++numDisford;
} else {
numAfford += numDisford;
numDisford = 0;
result += numAfford;
++numAfford;
}
} else if (prices[j] <= p) { // 客栈的颜色不符合要求,但是咖啡厅消费得起,后面就可以在这家咖啡厅消费
numAfford += numDisford;
numDisford = 0;
}
}
}
delete [] colors;
delete [] prices;
return result;
}