LeetCode进制转换


LeetCode 504. 七进制数

题目

在这里插入图片描述

倒推+迭代

一个整数的七进制可表示为 n u m 7 : a 0 a 1 … a n − 1 ‾ num_{7}:\overline{a_{0}a_{1}\dots a_{n-1}} num7:a0a1an1,其中其中 n n n 为其七进制表示的位数, a 0 a_0 a0 为最高位, a n − 1 a_{n-1} an1 为最低位

其对应的十进制表示为:$num_{10}=\sum_{i=0}^{n-1}a_{i}\times 7^{n-1-i} $。

当要计算一个十进制数对应的七进制表示时,可以先计算最低位 a n − 1 = num 10   m o d   7 a_{n-1} = \textit{num}_{10} \bmod 7 an1=num10mod7因为 num 10 \textit{num}_{10} num10中对 7 有余的部分仅由 a n − 1 a_{n-1} an1 贡献。

从两边都减去最低位 a n − 1 a_{n-1} an1可得:
n u m 10 − a n − 1 = ∑ i = 0 n − 2 a i × 7 n − 1 − i num_{10}-a_{n-1}=\sum_{i=0}^{n-2}a_{i} \times 7^{n - 1 - i} num10an1=i=0n2ai×7n1i
两边都除以7,可得:
n u m 10 − a n − 1 7 = ∑ i = 0 n − 2 a i × 7 n − 2 − i \frac{num_{10}-a_{n-1}}{7}=\sum_{i=0}^{n-2}a_{i} \times 7^{n - 2 - i} 7num10an1=i=0n2ai×7n2i
此时, n u m 10 − a n − 1 7 \frac{num_{10}-a_{n-1}}{7} 7num10an1中对7有余的部分仅由 a n − 2 a_{n-2} an2贡献,可得:
a n − 2 = n u m 10 − a n − 1 7   m o d   7 a_{n-2} =\frac{num_{10}-a_{n-1}}{7} \bmod 7 an2=7num10an1mod7
不停迭代,可以从最低位到最高位还原出 num 7 \textit{num}_7 num7 的各位数字,直到 num 10 \textit{num}_{10} num10 归 0。

当输入为负时,可以先取 num \textit{num} num 的绝对值来求七进制,最后再添加负号。

class Solution {
    public String convertToBase7(int num) {
        if (num == 0) {
            return "0";
        }
        boolean negative = num < 0;
        num = Math.abs(num);
        StringBuffer digits = new StringBuffer();
        while (num > 0) {
            digits.append(num % 7);
            num /= 7;
        }
        if (negative) {
            digits.append('-');
        }
        return digits.reverse().toString();
    }
}
  • 时间复杂度: O ( log ⁡ ∣ num ∣ ) O(\log |\textit{num}|) O(lognum),其中 ∣ num ∣ |\textit{num}| num 表示 num \textit{num} num 的绝对值。循环中最多做 log ⁡ ∣ num ∣ \log |\textit{num}| lognum 次除法。

  • 空间复杂度: O ( log ⁡ ∣ num ∣ ) O(\log |\textit{num}|) O(lognum)。字符数组的长度最多为 log ⁡ ∣ num ∣ \log |\textit{num}| lognum

LeetCode 405. 数字转换为十六进制数

题目

在这里插入图片描述

在这里插入图片描述

方法一:位运算 + 分组换算

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

实现一:

class Solution {
    public String toHex(int num) {
        if (num == 0) {
            return "0";
        }
        char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        StringBuilder res = new StringBuilder();
        while (num != 0) {
            // num 的二进制数按照四位一组分组,依次将每一组转换为对应的十六进制数
            res.append(chars[num & 0xf]);
            // 无符号右移
            num >>>= 4;
        }
        return res.reverse().toString();
    }
}

实现二:

class Solution {
    public String toHex(int num) {
        if (num == 0) return "0";
        StringBuilder sb = new StringBuilder();
        while (num != 0) {
            int u = num & 15;
            char c = (char)(u + '0');
            if (u >= 10) c = (char)(u - 10 + 'a');
            sb.append(c);
            num >>>= 4;
        }
        return sb.reverse().toString();
    }
}

Java中:

>>:带符号右移。正数右移高位补0,负数右移高位补1

>>>:无符号右移。无论是正数还是负数,高位通通补0

实现三:

class Solution {
    public String toHex(int num) {
        if (num == 0) {
            return "0";
        }
        StringBuffer sb = new StringBuffer();
        // 从最高4位开始转换
        for (int i = 7; i >= 0; i --) {
            int val = (num >> (4 * i)) & 0xf;
            // 防止前导 0 
            if (sb.length() > 0 || val > 0) {
                char digit = val < 10 ? (char) ('0' + val) : (char) ('a' + val - 10);
                sb.append(digit);
            }
        }
        return sb.toString();
    }
}

方法二:倒推 + 迭代

可以利用通用的进制转换思路来做(例如504. 七进制数),不断循环 num % knum / k 的操作来构造出 k 进制每一位。

但需要处理「补码」问题:对于负数的 n u m num num,需要先在 n u m num num 基础上加上 2 32 2^{32} 232 的偏移量,再进行进制转换。

CSAPP第一章有介绍2’s Comp. -> Unsigned,也就是用Unsigned的大正数表示Signed负数。举个例子,8位int-1表示为0b11111111(T),无符号整数0b11111111(U)表示为 2 8 − 1 2^8 - 1 281,二者在计算机中二进制表示相同,差值为 2 8 2^8 28。因此先在负数的基础上加上 2 8 2^8 28即可转化为一个大正数,二者的二进制表示相同。在这里32位整形则将原始负数num加上 2 32 2^{32} 232先转换成大正数,以无符号整形表示。该无符号整形与原始有符号负数的2进制是一样的

class Solution {
    public String toHex(int _num) {
        if (_num == 0) return "0";
        long num = _num;
        StringBuilder sb = new StringBuilder();
        if(num < 0) num = (long)(Math.pow(2, 32) + num);
        while (num != 0) {
            long u = num % 16;
            char c = (char)(u + '0');
            if (u >= 10) c = (char)(u - 10 + 'a');
            sb.append(c);
            num /= 16;
        }
        return sb.reverse().toString();
    }
}
  • 时间复杂度:复杂度取决于构造的十六进制数的长度,固定为 C = 8 C = 8 C=8。整体复杂度为 O ( C ) O(C) O(C)
  • 空间复杂度:复杂度取决于构造的十六进制数的长度,固定为 C = 8 C = 8 C=8。整体复杂度为 O ( C ) O(C) O(C)

Reference

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
题目描述: 请你来实现一个 atoi 函数,使其能将字符串转换成整数。该函数需要丢弃无用的开头空格,找到第一个非空格字符,然后将其后面的字符(如果符合要求的话)转换成整数,如果第一个非空字符为正或者负号时,将该符号与后面尽可能多的连续数字组合起来,返回整数。如果第一个非空字符是非数字字符或者一开始没有给定任何数字,则返回 0。 注意: 假如只能存储有限的整数范围内,例如32位整数,则请返回 INT_MAX(231 − 1)或 INT_MIN(−231)。 示例: 输入: "42" 输出: 42 输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。 输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。 输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。因此无法执行有效的转换。 输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。因此返回 INT_MIN(−231)。 解题思路: 这道题比较繁琐,需要注意的地方很多,需要仔细考虑每一种情况。下面是一种比较清晰的思路: 1. 删除字符串前面的空格。 2. 判断第一个非空字符是否为正负号或数字,如果是数字则开始转换,否则直接返回0。 3. 转换过程中如果遇到非数字字符,则停止转换,返回当前已转换的数字。 4. 判断转换后的数字是否超出了32位有符号整数的范围,如果超出了则返回对应的极值。 代码实现: ```python class Solution: def myAtoi(self, str: str) -> int: # 删除字符串前面的空格 str = str.lstrip() # 判断第一个非空字符是否为正负号或数字 if not str or (not str[0].isdigit() and str[0] not in ['+', '-']): return 0 # 转换过程中如果遇到非数字字符,则停止转换 i = 1 while i < len(str) and str[i].isdigit(): i += 1 # 转换数字 num_str = str[:i] sign = -1 if num_str[0] == '-' else 1 num = 0 for c in num_str: if c.isdigit(): num = num * 10 + int(c) else: break # 判断转换后的数字是否超出了32位有符号整数的范围 max_int = 2**31 - 1 min_int = -2**31 num = num * sign if num > max_int: return max_int elif num < min_int: return min_int else: return num ``` 时间复杂度:$O(n)$,其中 $n$ 是字符串的长度。需要对字符串进行一次遍历。 空间复杂度:$O(1)$。除了常量空间之外,不需要额外的空间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xylitolz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值