题目## 题目
解题思路
这是一道数字组合的递归题目,主要思路如下:
-
首先判断输入的合法性:
- a a a 和 b b b 必须在 1 1 1 到 1000000000 1000000000 1000000000 之间
- b b b 必须大于等于 a a a
-
计算思路:
- 获取 a a a 和 b b b 的位数 ( l e n A ) (lenA) (lenA) 和 ( l e n B ) (lenB) (lenB)
- 对于每个长度从 l e n A lenA lenA 到 l e n B lenB lenB 的数字进行组合
- 使用递归生成所有可能的6和8的组合
- 判断生成的数字是否在 [ a , b ] [a,b] [a,b] 范围内
-
优化:
- 当数字长度超过10位时直接返回
- 使用字符数组构建数字,最后转换为整数比较
代码
#include <iostream>
#include <string>
using namespace std;
int a, b, count = 0;
// 计算数字的位数
int intlen(int num) {
int i = 0;
while(num) {
num /= 10;
i++;
}
return i;
}
// 递归生成数字
void generate(char cs[], int index, int len) {
// 超过10位直接返回
if(len >= 10) return;
// 当前位数已满,检查数字是否在范围内
if(index == len) {
int num = atoi(cs);
if(num >= a && num <= b) {
count++;
}
return;
}
// 在当前位置尝试6和8
for(int i = 0; i < 2; i++) {
cs[index] = (i == 0) ? '6' : '8';
generate(cs, index + 1, len);
}
}
int main() {
// 输入并检查合法性
cin >> a;
if(a < 1 || a > 1000000000) {
cout << "-1" << endl;
return 0;
}
cin >> b;
if(b < a || b > 1000000000) {
cout << "-1" << endl;
return 0;
}
// 计算位数范围
int lenA = intlen(a);
int lenB = intlen(b);
// 对每个可能的位数生成组合
for(int i = lenA; i <= lenB; i++) {
char cs[11] = {0}; // 多分配一位用于字符串结束符
generate(cs, 0, i);
}
cout << count << endl;
return 0;
}
import java.util.*;
public class Main {
static int count = 0;
static int a, b;
// 计算数字的位数
static int intlen(int num) {
int i = 0;
while(num > 0) {
num /= 10;
i++;
}
return i;
}
// 递归生成数字
static void generate(char[] cs, int index, int len) {
if(len >= 10) return;
if(index == len) {
int num = Integer.parseInt(new String(cs, 0, len));
if(num >= a && num <= b) {
count++;
}
return;
}
for(int i = 0; i < 2; i++) {
cs[index] = (i == 0) ? '6' : '8';
generate(cs, index + 1, len);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
a = sc.nextInt();
if(a < 1 || a > 1000000000) {
System.out.println("-1");
return;
}
b = sc.nextInt();
if(b < a || b > 1000000000) {
System.out.println("-1");
return;
}
int lenA = intlen(a);
int lenB = intlen(b);
for(int i = lenA; i <= lenB; i++) {
char[] cs = new char[i];
generate(cs, 0, i);
}
System.out.println(count);
}
}
def intlen(num):
"""计算数字的位数"""
i = 0
while num:
num //= 10
i += 1
return i
def generate(cs, index, length, a, b):
"""递归生成数字"""
if length >= 10:
return 0
if index == length:
num = int(''.join(cs[:length]))
if a <= num <= b:
return 1
return 0
count = 0
for digit in ['6', '8']:
cs[index] = digit
count += generate(cs, index + 1, length, a, b)
return count
def main():
# 输入并检查合法性
a, b = map(int, input().split())
if a < 1 or a > 1000000000:
print("-1")
return
if b < a or b > 1000000000:
print("-1")
return
# 计算位数范围
len_a = intlen(a)
len_b = intlen(b)
# 统计所有可能的组合
total = 0
for length in range(len_a, len_b + 1):
cs = ['0'] * length
total += generate(cs, 0, length, a, b)
print(total)
if __name__ == "__main__":
main()
算法及复杂度
- 算法:递归 + 回溯
- 时间复杂度: O ( 2 n ) \mathcal{O}(2^n) O(2n) - 其中 n n n 为数字的最大位数,每位有2种选择
- 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 递归调用栈的深度为数字的位数
解题思路
这是一个进制转换和数位和计算问题。关键点:
-
十进制数位和 f ( x ) f(x) f(x):
- 对数字 x x x 按 10 10 10 取余,累加每一位
- 如 f ( 123 ) = 1 + 2 + 3 = 6 f(123) = 1 + 2 + 3 = 6 f(123)=1+2+3=6
-
二进制数位和g(x):
- 对数字 x x x 按 2 2 2 取余,累加每一位
- 如 123 ( 1111011 ) 123(1111011) 123(1111011), g ( 123 ) = 1 + 1 + 1 + 1 + 0 + 1 + 1 = 6 g(123) = 1+1+1+1+0+1+1 = 6 g(123)=1+1+1+1+0+1+1=6
-
幸运数判断:
- 遍历 1 1 1 到 n n n 的每个数
- 判断 f ( x ) = = g ( x ) f(x) == g(x) f(x)==g(x)
代码
#include <iostream>
using namespace std;
// 计算十进制数位和
int getDecimalSum(int x) {
int sum = 0;
while(x > 0) {
sum += x % 10;
x /= 10;
}
return sum;
}
// 计算二进制数位和
int getBinarySum(int x) {
int sum = 0;
while(x > 0) {
sum += x & 1;
x >>= 1;
}
return sum;
}
int main() {
int n;
while(cin >> n) {
int count = 0;
for(int i = 1; i <= n; i++) {
if(getDecimalSum(i) == getBinarySum(i)) {
count++;
}
}
cout << count << endl;
}
return 0;
}
import java.util.*;
public class Main {
// 计算十进制数位和
private static int getDecimalSum(int x) {
int sum = 0;
while(x > 0) {
sum += x % 10;
x /= 10;
}
return sum;
}
// 计算二进制数位和
private static int getBinarySum(int x) {
int sum = 0;
while(x > 0) {
sum += x & 1;
x >>= 1;
}
return sum;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
int count = 0;
for(int i = 1; i <= n; i++) {
if(getDecimalSum(i) == getBinarySum(i)) {
count++;
}
}
System.out.println(count);
}
}
}
# -*- coding:utf-8 -*-
def get_decimal_sum(x):
"""计算十进制数位和"""
sum = 0
while x > 0:
sum += x % 10
x //= 10 # 使用整除
return sum
def get_binary_sum(x):
"""计算二进制数位和"""
sum = 0
while x > 0:
sum += x & 1
x >>= 1
return sum
while True:
try:
n = int(input()) # 改用input()
count = 0
for i in range(1, n + 1): # 改用range
if get_decimal_sum(i) == get_binary_sum(i):
count += 1
print(count) # 添加括号
except:
break
算法及复杂度
- 算法:模拟
- 时间复杂度: O ( n log n ) \mathcal{O}(n\log n) O(nlogn),每个数字需要 O ( log n ) O(\log n) O(logn) 的时间计算数位和
- 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1),只使用常数额外空间
校招算法笔面试之幸运数字真题解析
1074

被折叠的 条评论
为什么被折叠?



