美文网首页
Leetcode --- 整数转换(数学问题)

Leetcode --- 整数转换(数学问题)

作者: _code_x | 来源:发表于2021-05-03 17:24 被阅读0次

    写在前

    • 对于整数反转问题,可以采用栈结构,也可以先转字符串,然后反转,但均不友好。使用数学方式是最优解。
    • 对于整数(阿拉伯数字)和罗马数字转换,主要是根据规则进行映射。

    1.整数反转(7 - 易)

    题目描述:给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

    假设环境不允许存储 64 位整数(有符号或无符号)。

    示例 :

    输入:x = 120
    输出:21
    
    输入:x = -123
    输出:-321
    

    思路:注意反转结果用long类型进行存储,最终强转int类型,判断是够存在溢出情况。

    代码实现:

    public int reverse(int x) {
        long n = 0; 
        while (x != 0) {
            n = x % 10 + n * 10;
            x /= 10; 
        }
        return (int)n == n ? (int)n : 0;
    }
    

    2.字符串转换整数 (8 - 中)

    题目描述:函数 myAtoi(string s) 的算法如下:

    • 读入字符串并丢弃无用的前导空格
    • 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
    • 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
    • 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
    • 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
    • 返回整数作为最终结果。

    注意:

    • 本题中的空白字符只包括空格字符 ' ' 。
    • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
    • 0 <= s.length <= 200
    • s 由英文字母(大写和小写)、数字(0-9)、' ''+''-''.' 组成

    示例 :

    输入:x = 121
    输出:true
    
    输入:x = -121
    输出:false
    

    思路:字符串转数字注意几个要点:

    • 去掉前导空格
    • 判断第一个字符+和-的情况,可以用变量flag,初始化1,遇到-,flag修正为-1
    • 判断是否为数字,使用ascii码进行判断
    • 遇到第一个不为数字字符情况,就停止转换,退出循环
    • 如果转换以后的数字超过了 int 类型的范围,需要截取。这里不能将结果 res 变量设计为 long 类型,注意:由于输入的字符串转换以后也有可能超过 long 类型,因此需要在循环内部就判断是否越界,只要越界就退出循环,这样也可以减少不必要的计算

    特别注意

    • 由于题目中说「环境只能保存 32 位整数」,因此这里在每一轮循环之前先要检查乘以 10 以后是否溢出
    • Java 、Python 和 C++ 字符串的设计都是不可变的,所以使用 trim() 会产生新的变量,因此我们尽量不使用库函数,使用一个变量 index 去做遍历,这样遍历完成以后就得到转换以后的数值。

    代码实现:

    public int myAtoi(String s) {
        int n = s.length();
        char[] chs = s.toCharArray();
        int index = 0;
        // 1.去掉先导空格
        while (index < n && chs[index] == ' ') {
            index++;
        }
        // 特殊情况,全是空格,已经完成遍历
        if (index == n) return 0;
        // 2.判断正负
        int flag = 1;
        char sign = chs[index];
        if (sign == '+') {
            index++;
        } else if (sign == '-') {
            flag = -1;
            index++;
        }
        // 3.将字符转换为数字,ans为int类型,题目要求
        int ans = 0;
        while (index < n) {
            char curChar = chs[index];
            // 不为数字字符,直接终止
            if (curChar < '0' || curChar > '9') {
                break;
            }
            // 环境只能保存 32 位整数, 转化之前,先判断是否溢出
            if (ans > Integer.MAX_VALUE / 10 || ans == Integer.MAX_VALUE / 10 && (curChar - '0') > Integer.MAX_VALUE % 10) {
                return flag > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            }
            // 符合条件的进行转化
            ans = ans * 10 + curChar - '0';
            index++;
        }
        return flag > 0 ? ans : ans * flag;
    }
    

    3.回文数(9 - 易)

    题目描述:给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

    示例 :

    输入:x = 121
    输出:true
    
    输入:x = -121
    输出:false
    

    思路定义一个变量right记录右部分,对于左部分直接复用x,最终记得判断一下整数位数奇偶情况

    :负数一定不回文,0是回文。

    代码实现:

    public boolean isPalindrome(int x) {
        if (x == 0) return true;
        if (x < 0 || x % 10 == 0) return false;
        int right = 0;
        while (x > right) {             
            right = x % 10 + right * 10; //更新右半部分
            x = x / 10;                  //更新左半部分(复用x)
        }
        return x == right || x == right / 10;
    }
    

    4.整数转罗马数字(12 - 中)

    题目描述:罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

    字符          数值
    I             1
    V             5
    X             10
    L             50
    C             100
    D             500
    M             1000
    

    例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

    通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

    • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
    • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
    • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
      给你一个整数,将其转为罗马数字。

    示例 :

    输入: num = 58
    输出: "LVIII"
    解释: L = 50, V = 5, III = 3.
    

    思路:建立映射,然后从左到右构建罗马数字,优先构建数值高的罗马字符(如果有足够的分值,尽量尝试构建 "M",直到分值不够,再尽量尝试构建 "CM" ... )

    代码实现:

    public String intToRoman(int num) {
        int[] val = new int[] {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        String[] str = new String[] {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        StringBuilder ans = new StringBuilder();
    
        for (int i = 0; i < val.length && num > 0; i++) {
            int cv = val[i];
            String cs = str[i];
            while (num >= cv) {
                ans.append(cs);
                num -= cv;
            }
        }
        return ans.toString();
    }
    

    5.罗马数字转整数(13 - 易)

    示例 :

    输入: "IV"
    输出: 4
    

    思路:与上题类似,从左向右构建整数,优先匹配数值高的罗马字符即可。

    代码实现:

    public int romanToInt(String s) {
        int[] val = new int[] {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        String[] str = new String[] {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        int n = s.length();
        int ans = 0, j = 0;
    
        for (int i = 0; i < str.length && j < n; i++) {
            int cv = val[i];
            String cs = str[i];
            int size = cs.length();
            while (j + size <= n && s.substring(j, j + size).equals(cs)) {
                ans += cv;
                j += size;
            }
        }
        return ans;
    }
    

    巨人的肩膀
    https://leetcode-cn.com/problems/string-to-integer-atoi/solution/jin-liang-bu-shi-yong-ku-han-shu-nai-xin-diao-shi-/

    相关文章

      网友评论

          本文标题:Leetcode --- 整数转换(数学问题)

          本文链接:https://www.haomeiwen.com/subject/cdnfdltx.html