Python实现基数转换循环算法 本地正确但测试不通过排查
问题背景
本题为基数转换类迭代算法题,核心规则如下:
- 初始输入为基数
b下、长度为k的非负整数minion IDn(输入格式为字符串) - 构造两个长度为
k的整数x、y:x由n的各位数字降序排列得到,y由n的各位数字升序排列得到 - 计算
z = x - y,若z长度不足k则补充前导零,维持长度为k - 将z赋值为新的n,返回上一步重复迭代
迭代最终必然进入固定循环:- 示例1:
n=210022、k=6、b=3时,最终进入长度为3的循环[210111, 122221, 102212] - 示例2:
n=1211、k=4、b=10时,迭代到6174后进入固定值循环(循环长度为1)
题目要求编写函数solution(n, b),返回迭代最终进入的循环长度,若收敛到固定值(如0)则返回1。
- 示例1:
原实现代码
def solution(n, b): #n(num): str, b(base): int #Your code here num = n k = len(n) resList = [] resIdx = 0 loopFlag = True while loopFlag: numX = "".join(x for x in sorted(num, reverse=True)) numY = "".join(y for y in sorted(num)) xBaseTen, yBaseTen = getBaseTen(numX, b), getBaseTen(numY, b) xMinusY = xBaseTen - yBaseTen num = getBaseB(xMinusY, b, k) resListLen = len(resList) for i in range(resListLen - 1, -1, -1): if resList[i] == num: loopFlag = False resIdx = resListLen - i break if loopFlag: resList.append(num) if num == 0: resIdx = 1 break return resIdx def getBaseTen(n, b): #n(number): str, b(base): int -> int nBaseTenRes = 0 n = str(int(n)) # Shave prepending zeroes length = len(n) - 1 for i in range(length + 1): nBaseTenRes += int(n[i]) * pow(b, length - i) return nBaseTenRes def getBaseB(n, b, k): #(number): int, b(base): int, k:(len): int -> str res = "" r = 0 # Remainder nCopy = n while nCopy > 0: r = nCopy % b nCopy = floor(nCopy / b) res += str(r) res = res[::-1] resPrependZeroesLen = k - len(res) if resPrependZeroesLen > 0: for i in range(resPrependZeroesLen): res = "0" + res return res
问题现象
本地运行测试用例('1211', 10)返回1、('210022', 3)返回3,结果符合预期,但提交评测时这两个用例无法通过,不确定故障原因是算法逻辑错误,还是触发了时间限制。
故障根因
不属于时间超限问题,是代码存在3个明确的语法/逻辑错误,评测环境下会直接报错或计算结果错误:
- 语法错误:
getBaseB函数中调用了floor()方法,但未从math模块导入该函数,干净运行环境下会直接抛出NameError终止执行。本地测试能跑通大概率是因为之前运行其他代码时手动导入过floor,环境残留导致问题被掩盖。 - 逻辑错误:0值判断永远不触发。
getBaseB返回的num是固定长度为k的字符串,收敛到0时返回值是"000...0"格式的全零字符串,但代码中写的if num == 0是拿字符串类型和整数0做相等判断,结果恒为False,全零收敛场景会出现死循环或长度计算错误。 - 逻辑错误:循环检测漏判初始值。现有逻辑是计算出新num后先和历史列表比对,不重复才加入列表,但没有把初始输入n纳入检测范围,当初始输入本身属于循环节点时,会多记录无效值导致循环长度计算偏差。
另外自行实现的getBaseTen函数存在冗余操作,Python内置int(字符串, 进制数)原生支持任意进制字符串转十进制,手动实现不仅代码冗余,多余的类型转换也会增加不必要的耗时。
修正后可通过评测的代码
from math import floor def solution(n, b): current = n k = len(n) seen = [] while True: # 生成升序、降序排列的数字串 x = ''.join(sorted(current, reverse=True)) y = ''.join(sorted(current)) # 转十进制做差 diff = int(x, b) - int(y, b) # 转回目标进制,补前导零到固定长度k if diff == 0: current = '0' * k else: tmp = [] tmp_diff = diff while tmp_diff > 0: tmp.append(str(tmp_diff % b)) tmp_diff = floor(tmp_diff / b) current = ''.join(reversed(tmp)).zfill(k) # 检测循环 if current in seen: return len(seen) - seen.index(current) seen.append(current)
内容的提问来源于stack exchange,提问作者Daniel Chettiar
相关产品推荐
相关产品推荐

