Swift - LeetCode - 数字转换为十六进制数

·  阅读 1320

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

题目

给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。

注意:

  1. 十六进制中所有字母(a-f)都必须是小写。
  2. 十六进制字符串中不能包含多余的前导零。如果要转化的数为0,那么以单个字符'0'来表示;对于其他情况,十六进制字符串中的第一个字符将不会是0字符。 
  3. 给定的数确保在32位有符号整数范围内。

示例 1:

  • 输入: 26
  • 输出: "1a"

示例 2:

  • 输入: -1
  • 输出: "ffffffff"

方法一:位运算

思路及解法

题目要求将给定的整数 num\textit{num} 转换为十六进制数,负整数使用补码运算方法。

在补码运算中,最高位表示符号位,符号位是 00 表示正整数和零,符号位是 11 表示负整数。3232 位有符号整数的二进制数有 3232 位,由于一位十六进制数对应四位二进制数,因此 3232 位有符号整数的十六进制数有 88 位。将 num\textit{num} 的二进制数按照四位一组分成 88 组,依次将每一组转换为对应的十六进制数,即可得到 num\textit{num} 的十六进制数。

假设二进制数的 88 组从低位到高位依次是第 00 组到第 77 组,则对于第 ii 组,可以通过 (nums>>(4×i)) & 0xf(\textit{nums} >> (4 \times i))~\&~\text{0xf} 得到该组的值,其取值范围是 001515(即十六进制的 f\text{f})。将每一组的值转换为十六进制数的做法如下:

  • 对于 0099,数字本身就是十六进制数;
  • 对于 10101515,将其转换为 a\text{a}f\text{f} 中的对应字母。

对于负整数,由于最高位一定不是 00,因此不会出现前导零。对于零和正整数,可能出现前导零。避免前导零的做法如下:

  • 如果 num=0\textit{num}=0,则直接返回 00
  • 如果 num>0\textit{num}>0,则在遍历每一组的值时,从第一个不是 00 的值开始拼接成十六进制数。

代码

class Solution {
    func toHex(_ num: Int) -> String {
        if 0 == num {
            return "0"
        }
        var sb: String = ""
        var i: Int = 7
        while i >= 0 {
            let val: Int = (num >> (i * 4)) & 0xf
            if sb.count > 0 || val > 0 {
                let digit: String = val < 10 ? String(val) : String(Character(UnicodeScalar(Int(Character("a").asciiValue!) + val - 10)!))
                sb += digit
            }
            i -= 1
        }
        return sb
    }
}
复制代码

复杂度分析

  • 时间复杂度:O(k)O(k),其中 kk 是整数的十六进制数的位数,这道题中 k=8k=8。无论 num\textit{num} 的值是多少,都需要遍历 num\textit{num} 的十六进制表示的全部数位。

  • 空间复杂度:O(k)O(k),其中 kk 是整数的十六进制数的位数,这道题中 k=8k=8。空间复杂度主要取决于中间结果的存储空间,这道题中需要存储 num\textit{num} 的十六进制表示中的除了前导零以外的全部数位。

收藏成功!
已添加到「」, 点击更改