斐波那契
[题目链接](https://www.nowcoder.com/practice/b55722617e204b0ba9d40dd01191fb7b)
思路
给定整数 和数位
,在前
个斐波那契数中,找出包含数位
次数最多的那个数(若有多个次数相同的,输出最小的)。
斐波那契数列定义如下:
$$
\text{Fib}(n) = \begin{cases} 1 & n = 1, 2 \\ \text{Fib}(n-1) + \text{Fib}(n-2) & n \ge 3 \end{cases}
$$
解法:模拟
直接模拟:
- 生成斐波那契数列:从 Fib(1)=1, Fib(2)=1 开始,依次计算到第
项。
- 统计每个数中数位
出现的次数:将数转成字符串逐位扫描。
- 选取最优答案:遍历时维护当前最大出现次数
maxCnt及对应的最小数值ans。若某项的次数严格大于maxCnt,则更新;若次数相等且该数更小,也更新。
关键细节
- 题目保证一定存在满足条件的数,因此不需要处理无解情况。
时,Fib(30) = 832040,long long 完全够用,无需大整数。
- "如果有多个就输出最小的"——斐波那契数列单调不减,但 Fib(1)=Fib(2)=1,因此两个值相同时取第一个即可;遍历时用严格小于来更新最小值即可正确处理。
复杂度分析
- 时间复杂度:
,其中
是最大斐波那契数的十进制位数,对
约为 6 位。
- 空间复杂度:
,存储斐波那契数列。
代码
#include <bits/stdc++.h>
using namespace std;
int countDigit(long long num, int d) {
string s = to_string(num);
int cnt = 0;
for (char c : s) {
if (c - '0' == d) cnt++;
}
return cnt;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, d;
cin >> n >> d;
vector<long long> fib;
if (n >= 1) fib.push_back(1);
if (n >= 2) fib.push_back(1);
for (int i = 2; i < n; i++) {
fib.push_back(fib[i-1] + fib[i-2]);
}
int maxCnt = -1;
long long ans = -1;
for (long long f : fib) {
int cnt = countDigit(f, d);
if (cnt > maxCnt || (cnt == maxCnt && f < ans)) {
maxCnt = cnt;
ans = f;
}
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static int countDigit(long num, int d) {
String s = Long.toString(num);
int cnt = 0;
for (char c : s.toCharArray()) {
if (c - '0' == d) cnt++;
}
return cnt;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int d = sc.nextInt();
List<Long> fib = new ArrayList<>();
if (n >= 1) fib.add(1L);
if (n >= 2) fib.add(1L);
for (int i = 2; i < n; i++) {
fib.add(fib.get(i-1) + fib.get(i-2));
}
int maxCnt = -1;
long ans = -1;
for (long f : fib) {
int cnt = countDigit(f, d);
if (cnt > maxCnt || (cnt == maxCnt && f < ans)) {
maxCnt = cnt;
ans = f;
}
}
System.out.println(ans);
}
}

京公网安备 11010502036488号