题解:学而思编程 斐波那契字符串
【题目来源】
学而思编程:斐波那契字符串
【题目描述】
斐波那契数列指的是这样一个数列:\(1\)、\(1\)、\(2\)、\(3\)、\(5\)、\(8\)、\(13\)、\(21\)、\(34\)、......
在数学上,斐波那契数列以如下递推的形式定义:\(F(0)=1\),\(F(1)=1\),\(F(n)=F(n−1)+F(n−2)(n≥2)\)。
如果一个数出现在斐波那契数列之中,那么我们就称这个数为斐波那契数。
现在,给定一个整数 \(n\),请你构造一个长度为 \(n\) 的字符串 \(s_1s_2\dots s_n\)。
对于字符串中的第 \(i\) 个字符 \(s_i\):
- 如果 \(i\) 是斐波那契数,则 \(s_i\) 为大写字母 O。
- 如果 \(i\) 不是斐波那契数,则 \(s_i\) 为小写字母 o。
输出构造好的字符串。
注意,字符下标从 \(1\) 到 \(n\)。
【输入】
一行一个整数 \(n\)。
【输出】
一个字符串,表示答案。
【输入样例】
3
【输出样例】
OOO
【核心思想】
-
问题分析:给定整数 \(n\),构造长度为 \(n\) 的字符串,其中第 \(i\) 位为
O(大写)当且仅当 \(i\) 是斐波那契数,否则为o(小写)。这是一个斐波那契数生成 + 标记数组问题,关键在于高效生成不超过 \(n\) 的所有斐波那契数并标记。 -
算法选择:
- 递推生成斐波那契数:利用 \(F(i) = F(i-1) + F(i-2)\) 递推,直到超过 \(n\)
- 布尔标记数组:
flag[i] = true表示 \(i\) 是斐波那契数,实现 \(O(1)\) 查询
-
关键步骤:
- 初始化:读取 \(n\)
- 斐波那契数列生成:
f[0] = 1, f[1] = 1,flag[1] = true(\(1\) 是斐波那契数)- 遍历 \(i\) 从 \(2\) 开始,直到
f[i-1] > n:f[i] = f[i-1] + f[i-2]- 若
f[i] <= n:flag[f[i]] = true
- 构造字符串:
- 遍历 \(i\) 从 \(1\) 到 \(n\):
- 若
flag[i] == true:输出O - 否则:输出
o
- 若
- 遍历 \(i\) 从 \(1\) 到 \(n\):
-
时间/空间复杂度:
- 时间复杂度:\(O(\log n + n)\),斐波那契数增长指数级,不超过 \(n\) 的项数为 \(O(\log n)\),构造字符串 \(O(n)\)
- 空间复杂度:\(O(n)\),标记数组
flag[1..n]
-
递推标记的核心思想:
- 斐波那契数的稀疏性:斐波那契数列指数增长,不超过 \(n\) 的项数约为 \(O(\log n)\),递推生成非常高效
- 标记数组查询优化:生成时直接标记,后续查询 \(O(1)\),避免每次判断时重新计算或查找
- 下标从1开始:题目明确字符下标从 \(1\) 到 \(n\),与斐波那契数的自然数定义一致
- 重复值处理:\(F(0) = F(1) = 1\),但标记数组只关心是否出现,重复不影响结果
- 适用于"数列判定 + 序列构造"类问题,递推生成配合标记数组是经典组合
【算法标签】
递推
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, f[50]; // f: 存储斐波那契数列
bool flag[100005]; // flag: 标记是否是斐波那契数
int main()
{
cin >> n;
f[0] = 1, f[1] = 1; // 初始化斐波那契数列
flag[1] = true; // 1是斐波那契数
// 生成不超过n的斐波那契数列
for (int i = 2; f[i - 1] <= n; i++)
{
f[i] = f[i - 1] + f[i - 2];
flag[f[i]] = true; // 标记斐波那契数
}
// 输出序列:斐波那契数输出"O",否则输出"o"
for (int i = 1; i <= n; i++)
{
if (flag[i] == true)
{
cout << "O";
}
else
{
cout << "o";
}
}
return 0;
}
【运行结果】
3
OOO
浙公网安备 33010602011771号