请教一个算法问题,把数字转换为A,B,C……,如何实现?

作者站长头像
站长
· 阅读数 16

请教一个算法问题,把数字转换为A,B,C……,如何实现?现在我想根据数字转换为英文字母:比如 A->1,B->2,……AA->27,AB->28。我的思路本来是想维护一个数组,然后根据辗转相除法,然后生成对应的下标,但是有问题:

function numToLetter(originNum = 53) {
  let letter = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
  let num = originNum; // 随意输入一个数字
  let numArr = []; // 得到num对应的字母下标
  // 辗转相除,然后取余数
  while (num > 0) {
    numArr.push(num % 26);
    num = Math.floor(num / 26);
  }
  console.log('**********************************')
  // 输出对应数字的字母下标
  console.log(`${originNum}对应的字母下标为`, numArr.reverse());
  let str = ''; // 数字对应的字符串
  numArr.forEach(v => {
    str += letter[v-1]
  })
  console.log('这个字符串为:', str)
}
numToLetter(53)
numToLetter(52)

请教一个算法问题,把数字转换为A,B,C……,如何实现?

53 = 26^1 * 2 + 26^0 * 152 = 26^1 * 2 + 26^0 * 1

26 进制是这样算的,但是转换为下标的话,这样写有问题,不知道如何优化,或者别的思路求数字转字母

回复
1个回答
avatar
test
2024-07-20

首先,这个“26 进制”不是标准 26 进制,是双射 26 进制(Bijective positional notation [wiki]

在双射 k 进制下,$$\overline{a_na_{n−1} \cdots a_1a_0} = a_nk^n + a_{n-1}k^{n-1} + \cdots + a_1k + a_0 $$

其中 $$\{1, 2, \cdots, k \}$$ 是双射 k 进制使用的数字。

所以,直接取余才会遇到没法处理余数是 0 的情况。

用我们更为熟悉的十进制来类比一下

在双射十进制中,假定使用 1-9A 这 10 个数字。

  • 10 -> (1, 0) -> A
  • 11 -> (1, 1) -> 11
  • 20 -> (2, 0) -> 1A
  • ...
  • 100 -> (1, 0, 0) -> 9A
  • 110 -> (1, 1, 0) -> AA
  • 111 -> (1, 1, 1) -> 111

那么,遇到余数是 0 怎么办?以双射十进制下表达 100 为例(手算过程,伪代码)

X = 100
MOD_1 = 100 % 10
if (! MOD_1) { // 余数是 0,但没有数字 0,怎么办?
    X -= 10 // 只好从上一位“借走”10
    MOD_1 = 10 // 这样,这一位就是数字 A 了
}
X /= 10 // 90 / 10 == 9

MOD_2 = 9 % 10
// 数字 9,没问题
X /= 10 // 9 / 10 == 0,结束

Y = MOD_2 ++ MOD_1 // 9A,没问题

现在我们可以改进原来的代码:

function numToLetter(originNum = 53) {
  let letter = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
  let num = originNum; // 随意输入一个数字
  let numArr = []; // 得到num对应的字母下标
  // 辗转相除,然后取余数
  while (num > 0) {
+   let mod = num % 26;
+    if (! mod) {
+     num -= 26;
+     mod = 26;
+   }
-   numArr.push(num % 26);
+   numArr.push(mod)
    num = Math.floor(num / 26);
  }
  console.log('**********************************')
  // 输出对应数字的字母下标
  console.log(`${originNum}对应的字母下标为`, numArr.reverse());
  let str = ''; // 数字对应的字符串
  numArr.forEach(v => {
    str += letter[v-1]
  })
  console.log('这个字符串为:', str)
}

结果:

numToLetter(52)
// **********************************
// 676对应的字母下标为 
// Array [ 1, 26 ]
// 这个字符串为: AZ

numToLetter(26 * 26) // 676
// **********************************
// 676对应的字母下标为 
// Array [ 25, 26 ]
// 这个字符串为: YZ

numToLetter(26 * 26 + 26) // 702
// **********************************
// 702对应的字母下标为 
// Array [ 26, 26 ]
// 这个字符串为: ZZ
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容