专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。
一、题目描述
小明在做构造数列的题目,题目要求数列中第一个数为n,且数列后面的每一个数字都不能大于前一个数字的一半,数列的元素是正整数,请问在给定n的情况下,最多能构造多少合适且不同的数列?
二、输入描述
输入一个n。
备注:
1 ≤ n ≤ 10000
三、输出描述
输出可以构造的序列个数
四、测试用例
测试用例1:
1、输入
7
2、输出
6
3、说明
可以构成 [7], [7,3], [7,2], [7,1], [7,3,1], [7,2,1]
测试用例2:
1、输入
5
2、输出
4
3、说明
可以构成 [5], [5,2], [5,1], [5,2,1]
五、解题思路
对于数字n,我们需要找出所有可能的递减数列:
- 每个数列都以n开始
- 后续每个数字都不能大于前一个数字的一半
- 所有数字都是正整数
算法思路:
- 使用动态规划,dp[i]表示以数字i开始能构造的不同数列个数
- 对于数字i,dp[i] = 1 + sum(dp[j] for j in [1, i/2])
- 其中1表示只有一个数字i的数列,后面的求和表示所有可能的后续数列
六、Python算法源码
def count_sequences(n):
"""
计算以数字n开始能构造的不同数列个数
参数:n - 起始数字
返回:不同数列的个数
"""
# dp[i]表示以数字i开始能构造的不同数列个数
dp = [0] * (n + 1)
# 从1开始计算到n,使用动态规划
for i in range(1, n + 1):
# 每个数字本身就是一个数列,所以初始值为1
dp[i] = 1
# 遍历所有可能的下一个数字j,j的范围是[1, i//2]
for j in range(1, i // 2 + 1):
# 以j开始的数列个数加到以i开始的数列个数中
dp[i] += dp[j]
# 返回以n开始的数列个数
return dp[n]
def main():
"""
主函数,处理输入输出
"""
# 读取输入的数字n
n = int(input())
# 计算并输出结果
result = count_sequences(n)
print(result)
# 执行主函数
if __name__ == "__main__":
main()
七、JavaScript算法源码
/**
* 计算以数字n开始能构造的不同数列个数
* @param {number} n 起始数字
* @returns {number} 不同数列的个数
*/
function countSequences(n) {
// dp[i]表示以数字i开始能构造的不同数列个数
const dp = new Array(n + 1).fill(0);
// 从1开始计算到n,使用动态规划
for (let i = 1; i <= n; i++) {
// 每个数字本身就是一个数列,所以初始值为1
dp[i] = 1;
// 遍历所有可能的下一个数字j,j的范围是[1, Math.floor(i/2)]
for (let j = 1; j <= Math.floor(i / 2); j++) {
// 以j开始的数列个数加到以i开始的数列个数中
dp[i] += dp[j];
}
}
// 返回以n开始的数列个数
return dp[n];
}
/**
* 主函数,处理输入输出
*/
function main() {
// 引入readline模块用于控制台输入
const readline = require('readline');
// 创建readline接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 读取输入的数字n
rl.question('', (input) => {
const n = parseInt(input.trim());
// 计算并输出结果
const result = countSequences(n);
console.log(result);
// 关闭readline接口
rl.close();
});
}
// 执行主函数
main();
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
/**
* 计算以数字n开始能构造的不同数列个数
* @param n 起始数字
* @return 不同数列的个数
*/
int countSequences(int n) {
// 动态分配dp数组,dp[i]表示以数字i开始能构造的不同数列个数
int *dp = (int*)calloc(n + 1, sizeof(int));
// 从1开始计算到n,使用动态规划
for (int i = 1; i <= n; i++) {
// 每个数字本身就是一个数列,所以初始值为1
dp[i] = 1;
// 遍历所有可能的下一个数字j,j的范围是[1, i/2]
for (int j = 1; j <= i / 2; j++) {
// 以j开始的数列个数加到以i开始的数列个数中
dp[i] += dp[j];
}
}
// 保存结果
int result = dp[n];
// 释放动态分配的内存
free(dp);
// 返回以n开始的数列个数
return result;
}
/**
* 主函数,处理输入输出
*/
int main() {
int n; // 定义输入变量
// 读取输入的数字n
scanf("%d", &n);
// 计算并输出结果
int result = countSequences(n);
printf("%d\n", result);
return 0; // 程序正常结束
}
九、C++算法源码
#include <iostream>
#include <vector>
using namespace std;
/**
* 计算以数字n开始能构造的不同数列个数
* @param n 起始数字
* @return 不同数列的个数
*/
int countSequences(int n) {
// 使用vector存储dp数组,dp[i]表示以数字i开始能构造的不同数列个数
vector<int> dp(n + 1, 0);
// 从1开始计算到n,使用动态规划
for (int i = 1; i <= n; i++) {
// 每个数字本身就是一个数列,所以初始值为1
dp[i] = 1;
// 遍历所有可能的下一个数字j,j的范围是[1, i/2]
for (int j = 1; j <= i / 2; j++) {
// 以j开始的数列个数加到以i开始的数列个数中
dp[i] += dp[j];
}
}
// 返回以n开始的数列个数
return dp[n];
}
/**
* 主函数,处理输入输出
*/
int main() {
int n; // 定义输入变量
// 读取输入的数字n
cin >> n;
// 计算并输出结果
int result = countSequences(n);
cout << result << endl;
return 0; // 程序正常结束
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2025 B卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。