目录

题目

思路

Code

题目

题目内容:

在一个特殊的数学系统中,每个数字都有其独特的表示方式。给定两个不同的数字字符集和一个数字字符串,需要将这个数字从一个字符系统转换到另一个字符系统。

实现一个函数,将使用源字符集表示的数字转换为使用目标字符集表示的数字。

补充说明:1 <= num.length <= 100;2 <= sourceDigits.length <= 36;2 <= targetDigits.length <= 36;sourceDigits 和 targetDigits 均由不同字符组成且不包含重复字符;num 中所有字符都存在于 sourceDigits 中;输入保证有效;转换结果不应包含前导零,除非数字本身就是 0。

输入描述:

输入一行字符串,格式为 num,sourceDigits,targetDigits。

num 是源字符集表示的数字,sourceDigits 是源字符集,targetDigits 是目标字符集。

输出描述:

输出转换后的目标字符集数字字符串。

样例 1

输入:

101,01,0123456789

输出:

5

说明:

二进制 101 转换为十进制是 5。

样例 2

输入:

ff,0123456789abcdef,0123456789

输出:

255

说明:

十六进制 ff 转换为十进制是 255。

样例 3

输入:

10012,01234,012

输出:

212102

说明:

五进制 10012 转换为三进制是 212102。

思路

整体思路:不能依赖普通整数承载中间值,因为 num 最长为 100,直接转换为十进制可能溢出。

第一步:根据 sourceDigits 建立字符到数值的映射,把 num 转成源进制下的数字数组。

第二步:如果所有位都是 0,则直接输出 targetDigits 的第一个字符。

第三步:反复对当前大数执行除以目标进制的长除法,每一轮得到的余数就是目标进制的一位。

第四步:每轮长除法保留去掉前导零的商,直到商为空,再将收集到的余数字符反转输出。

边界处理:长除法中的中间值只由余数、源进制和当前位组成,源进制和目标进制都不超过 36,因此不会溢出普通整型。

复杂度分析:设输入长度为 L,输出长度为 R,时间复杂度 O(LR),空间复杂度 O(L+R)。

思路配图

Code

import sys

num, source_digits, target_digits = sys.stdin.readline().strip().split(",")
# 源字符集的排列顺序就是每个字符的位值,不能按字符本身的字典序理解。
value = {ch: i for i, ch in enumerate(source_digits)}
digits = [value[ch] for ch in num]
if all(d == 0 for d in digits):
    # 大数除法对全零会得到空结果,先单独输出目标字符集的零位字符。
    print(target_digits[0])
    sys.exit(0)
source_base = len(source_digits)
target_base = len(target_digits)
result = []
while digits:
    quotient = []
    remainder = 0
    for digit in digits:
        # 用源进制下的长除法直接除以目标进制,避免把 100 位数字塞进普通整数。
        current = remainder * source_base + digit
        q, remainder = divmod(current, target_base)
        if quotient or q != 0:
            # 商的前导零不再有数值意义,丢掉后下一轮才会逐步缩短。
            quotient.append(q)
    # 连续除法得到的余数是目标表示的最低位,因此先收集再统一反转。
    result.append(target_digits[remainder])
    digits = quotient
# 反转后才是目标字符系统中从高位到低位的正常书写顺序。
print("".join(reversed(result)))

JS

const fs = require("fs");
const [num, sourceDigits, targetDigits] = fs.readFileSync(0, "utf8").trim().split(",");
const value = new Map();
// 字符集顺序定义每个字符的位值,字符本身不一定具备可比较的数字含义。
[...sourceDigits].forEach((ch, i) => value.set(ch, i));
let digits = [...num].map(ch => value.get(ch));
if (digits.every(v => v === 0)) {
  // 全零转换后仍是零,直接输出目标字符集的零位字符。
  process.stdout.write([...targetDigits][0]);
  process.exit(0);
}
const sourceBase = [...sourceDigits].length;
const targetChars = [...targetDigits];
const targetBase = targetChars.length;
const result = [];
while (digits.length > 0) {
  const quotient = [];
  let remainder = 0;
  for (const digit of digits) {
    // 在源进制位数组上逐位相除,避免把超长输入塞进 Number 或 BigInt。
    const current = remainder * sourceBase + digit;
    const q = Math.floor(current / targetBase);
    remainder = current % targetBase;
    // 丢弃商的前导零,下一轮除法才能逐步逼近空商。
    if (quotient.length > 0 || q !== 0) quotient.push(q);
  }
  // 每轮余数对应目标数字的一位,产生顺序是从低位到高位。
  result.push(targetChars[remainder]);
  digits = quotient;
}
// 反转低位优先的余数序列,得到目标字符系统的正常书写顺序。
console.log(result.reverse().join(""));

【华为od机试真题Python+JS+Java+Go合集】【超值优惠】:Py/JS/Java/Go合集

【华为od机试真题Python】:Python真题题库

【华为od机试真题JavaScript】:JavaScript真题题库

【华为od机试真题Java&Go】:Java&Go真题题库

【华为od机试真题C++】:C++真题题库

【华为od机试真题C语言】:C语言真题题库

【华为od面试手撕代码题库】:面试手撕代码题库

【华为od机试面试交流群】【文章底部有二维码链接,可扫码加交流群】

华为OD机试面试交流群二维码

华为OD机试:二本院校有机会吗? 有机会,但不大,大神除外!机考分数越高越好,所以需要提前刷题。机考通过后,如果没有收到面试邀请,也不要着急,非目标院校面试邀请发的时间比较晚。非目标院校今年有点难,机试至少要考到350分,所以需要疯狂刷题,华为OD机考是有题库的,最好在考前完所有题库题目。华为OD机试:跨专业可以参加华为OD可以,但是如果你的本科院校比较差,上岸概率不大。华为OD机试:华为OD简历被锁定机试通过,性格测试也通过,但是没人联系面试,发现简历被锁定。此时需要主动去联系HR。让他帮助你查询原因。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐