编程题一

问题分析
题目要求使用 n
根小木棒,按照特定的方式排列,形成一个数字。具体规则如下:
- 每个数字由小木棒组成,例如:
1
需要 2 根小木棒。0
需要 6 根小木棒。- 其他数字(如
2, 3, 4, 5, 6, 7, 8, 9
)需要的木棒数分别为 5, 5, 5, 4, 5, 3, 7, 2。
- 要求生成的数字中,0 不能位于最前端。
- 在满足上述条件的情况下,找到使用
n
根小木棒能够形成的最小数字。
解题思路
为了生成最小的数字,我们需要遵循以下原则:
- 优先使用较少木棒的数字 :例如,
1
只需要 2 根木棒,是所有数字中使用木棒最少的,因此应该尽量多用1
。 - 避免在最前端使用
0
:如果剩余木棒不足以构成其他数字,可以考虑使用0
,但不能放在最前端。 - 贪心策略:从高位到低位依次选择能够使用的最小数字,直到用完所有的木棒。
实现步骤
- 定义每个数字所需的木棒数:创建一个数组或映射,存储每个数字对应的木棒数。
- 贪心构造数字 :
- 从高位到低位,优先选择能够使用的最小数字。
- 如果当前位无法使用
0
(因为它是首位),则选择次小的数字。 - 如果剩余木棒不足以构成任何数字,则结束构造。
- 输出结果:将构造好的数字输出。
C++ 代码实现
以下是完整的 C++ 代码实现:
cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 定义每个数字所需的木棒数
const vector<int> sticks = {6, 2, 5, 5, 4, 5, 6, 3, 7, 2};
int main() {
int n;
cin >> n; // 输入木棒总数
string result; // 存储最终结果
// 构造数字
while (n > 0) {
bool found = false; // 标记是否找到合适的数字
for (int digit = 0; digit <= 9; ++digit) {
if (sticks[digit] <= n) {
// 如果是第一位,不能使用 '0'
if (result.empty() && digit == 0) continue;
// 使用该数字
result += ('0' + digit);
n -= sticks[digit];
found = true;
break;
}
}
// 如果找不到合适的数字,退出循环
if (!found) break;
}
// 输出结果
if (result.empty()) {
cout << "-1" << endl; // 如果无法构造数字,输出 -1
} else {
cout << result << endl;
}
return 0;
}
代码解释
-
输入处理:
- 读取用户输入的木棒总数
n
。
- 读取用户输入的木棒总数
-
贪心构造数字:
- 使用一个字符串
result
来存储构造的数字。 - 从高位到低位,依次尝试使用数字
0
到9
。 - 如果当前位是第一位,不能使用
0
,因此跳过。 - 如果某个数字的木棒需求不超过剩余木棒数,则将其加入结果,并更新剩余木棒数。
- 如果遍历完所有数字都无法找到合适的数字,则退出循环。
- 使用一个字符串
-
输出结果:
- 如果成功构造了数字,则输出结果。
- 如果无法构造数字(例如木棒数不足),输出
-1
。
示例运行
输入:
10
输出:
1111
输入:
6
输出:
0
输入:
7
输出:
11
复杂度分析
-
时间复杂度:
- 每次尝试构造数字时,最多需要遍历 10 个数字(
0
到9
),因此每次操作的时间复杂度为 (O(1))。 - 总共需要进行 (O(n)) 次操作,其中 (n) 是木棒总数。
- 因此,总时间复杂度为 (O(n))。
- 每次尝试构造数字时,最多需要遍历 10 个数字(
-
空间复杂度:
- 主要空间用于存储结果字符串和常量数组
sticks
,空间复杂度为 (O(n))。
- 主要空间用于存储结果字符串和常量数组
结论
该代码通过贪心策略,优先选择使用较少木棒的数字,并确保 0
不出现在最前端,从而构造出最小的数字。对于给定的木棒数 n
,能够高效地计算出对应的最小数字。
编程题二

问题分析
题目要求根据整数 n
对 7 的余数,构造一个特定的数字 m
。具体规则如下:
- 如果
n
是 7 的倍数,则m
等于n / 7
个8
。 - 如果
n
除以 7 的余数为 1,则m
是由若干个8
组成的数字,前面加上10
。 - 如果
n
除以 7 的余数为 2,则m
是由若干个8
组成的数字,前面加上18
。 - 如果
n
除以 7 的余数为 3,则m
是由若干个8
组成的数字,前面加上20
。 - 如果
n
除以 7 的余数为 4,则m
是由若干个8
组成的数字,前面加上48
。 - 如果
n
除以 7 的余数为 5,则m
是由若干个8
组成的数字,前面加上28
。 - 如果
n
除以 7 的余数为 6,则m
是由若干个8
组成的数字,前面加上102
。
解题思路
- 计算
n
对 7 的余数 :使用取模运算符%
计算n % 7
。 - 根据余数构造数字 :
- 如果余数为 0,直接构造
n / 7
个8
。 - 如果余数不为 0,先根据余数确定前缀(如
10
,18
,20
, 等),然后在后面追加(n / 7)
个8
。
- 如果余数为 0,直接构造
- 输出结果:将构造好的数字输出。
C++ 代码实现
以下是完整的 C++ 代码实现:
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
int n;
cin >> n; // 输入整数 n
// 计算 n 对 7 的余数
int remainder = n % 7;
// 构造数字 m
string prefix; // 前缀
string suffix; // 后缀(由若干个 '8' 组成)
// 根据余数确定前缀
switch (remainder) {
case 0:
prefix = ""; // 如果是 7 的倍数,不需要前缀
break;
case 1:
prefix = "10";
break;
case 2:
prefix = "18";
break;
case 3:
prefix = "20";
break;
case 4:
prefix = "48";
break;
case 5:
prefix = "28";
break;
case 6:
prefix = "102";
break;
}
// 计算后缀中 '8' 的数量
int num_eights = n / 7;
// 构造后缀
for (int i = 0; i < num_eights; ++i) {
suffix += '8';
}
// 拼接前缀和后缀
string result = prefix + suffix;
// 输出结果
cout << result << endl;
return 0;
}
代码解释
-
输入处理:
- 读取用户输入的整数
n
。
- 读取用户输入的整数
-
计算余数:
- 使用
n % 7
计算n
对 7 的余数,并存储在变量remainder
中。
- 使用
-
根据余数确定前缀:
- 使用
switch
语句根据余数选择对应的前缀字符串(如"10"
,"18"
,"20"
等)。 - 如果余数为 0,说明
n
是 7 的倍数,此时前缀为空字符串。
- 使用
-
构造后缀:
- 后缀由若干个
'8'
组成,其数量为n / 7
。 - 使用一个循环,将
'8'
追加到字符串suffix
中。
- 后缀由若干个
-
拼接前缀和后缀:
- 将前缀和后缀拼接起来,形成最终的数字字符串
result
。
- 将前缀和后缀拼接起来,形成最终的数字字符串
-
输出结果:
- 将构造好的数字字符串
result
输出。
- 将构造好的数字字符串
示例运行
输入:
21
输出:
888
输入:
22
输出:
10888
输入:
28
输出:
8888
输入:
30
输出:
20888
复杂度分析
-
时间复杂度:
- 构造后缀时,需要遍历
n / 7
次,因此时间复杂度为 (O(n / 7)),可以简化为 (O(n))。
- 构造后缀时,需要遍历
-
空间复杂度:
- 主要空间用于存储前缀和后缀字符串,空间复杂度为 (O(n))。
结论
该代码通过简单的数学运算和字符串操作,高效地实现了根据 n
的余数构造数字 m
的功能。对于给定的输入 n
,能够正确输出对应的数字 m
。