怒刷力扣(罗马数字转整数)

简介: 做算法题,还是要多思考,找到问题的本质,回头会发现,问题也许并没有我们想象的那么困难。加油吧,少年。

罗马数字转整数

WangScaler: 一个用心创作的作者。

声明:才疏学浅,如有错误,恳请指正。

题目

罗马数字包含以下七种字符: 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。 给定一个罗马数字,将其转换成整数。

分析

初步思考

从大到小遍历关键字M、D、C、L、X、V、I 。如果存在,则以关键字截取分割,分割完的数组长度如果是1或者2,则直接计算值。如果长度大于2,则递归计算值。

    public static int romanToInt(String s) {
        Map<String, Integer> hashMap = new LinkedHashMap<>(7);
        hashMap.put("M", 1000);
        hashMap.put("D", 500);
        hashMap.put("C", 100);
        hashMap.put("L", 50);
        hashMap.put("X", 10);
        hashMap.put("V", 5);
        hashMap.put("I", 1);
        String[] sToSpilt = new String[2];
        if (s.length() == 1) {
            return hashMap.get(s);
        }
        if (s.length() == 2) {
            for (String key : hashMap.keySet()) {
                if (s.contains(key)) {
                    sToSpilt = s.split(key);
                    if (sToSpilt.length == 1 && (sToSpilt[0] + key).equals(s)) {
                        return hashMap.get(key) - hashMap.get(sToSpilt[0]);
                    } else if (sToSpilt.length == 2 && (key + sToSpilt[1]).equals(s)) {
                        return hashMap.get(key) + hashMap.get(sToSpilt[1]);
                    } else {
                        return hashMap.get(key) * 2;
                    }
                }
            }
        }
        for (String key : hashMap.keySet()) {
            if (s.contains(key)) {
                return romanToInt(s.substring(0, s.indexOf(key) + 1)) + romanToInt(s.substring(s.indexOf(key) + 1));
            }
        }
        return 0;
    }

这样,虽然解决了问题,但是并没有看到问题的本质。上述解题的思路是我们常规的思考方式,以最大值为核心,分别计算两边。一是将整个字符串拆分,二是两边分别计算,无疑是耗时耗力。

继续思考

我们知道数字的加减不像乘除是有顺序的。那么我们在大的值左边就是要做差,在大的值右边就是要做和。我们从头到尾遍历,如果当前值比右边的值大,那么肯定就是加上当前值,如果当前值比右边值小,那么就是减去当前值。这样以来,问题是不是就变得简单明了,更加清晰了。

比如 :"MCMXCIV"对应的就是【1000、100、1000、10、100、1、5】。

  • result起始值为0。
  • 1000比100大;所以result=0+1000。
  • 100比1000小;所以result=0+1000-100。
  • 1000比10大;所以result=0+1000-100+1000。
  • 10比100小;所以result=0+1000-100+1000-10。
  • 100比1大;所以result=0+1000-100+1000-10+100。
  • 1比5小;所以result=0+1000-100+1000-10+100-1。
  • 最后一位,加上;所以result=0+1000-100+1000-10+100-1+5=1994。

这就是数学思维,一下问题就简单很多。

答案

 public static int romanToInt(String s) {
        Map<Character, Integer> hashMap = new HashMap<Character, Integer>();
        hashMap.put('I', 1);
        hashMap.put('V', 5);
        hashMap.put('X', 10);
        hashMap.put('L', 50);
        hashMap.put('C', 100);
        hashMap.put('D', 500);
        hashMap.put('M', 1000);
        int result = 0;
        for (int i = 0; i < s.length(); i++) {
            if (i == s.length() - 1 || hashMap.get(s.charAt(i)) >= hashMap.get(s.charAt(i + 1))) {
                result += hashMap.get(s.charAt(i));
            } else {
                result -= hashMap.get(s.charAt(i));
            }
        }
        return result;
    }

复杂度

  • 时间复杂度:O(n)。只需从左往右遍历一次整个字符串。
  • 空间复杂度:O(1)。我们只需要常数result存放结果和hashMap存放罗马数字和整数的关系。

总结

起初的思路就是之前的笨想法,只会按部就班。左边小右边大,那么就需要找到最大的分别计算就行了。这种方法,无疑是最慢的。如果是很长一串,让我们在草稿纸上计算,拆分字符串,肯定就能让我们晕头转向,更别说写出的程序的复杂度了。如果从数学角度看,这个问题就迎刃而解了。还是要多思考,看到问题的本质,再去解题。

都来了,点个赞再走呗!

关注WangScaler,祝你升职、加薪、不提桶!

目录
相关文章
|
2月前
|
存储
LeetCode整数反转
解决LeetCode上的整数反转问题的几种方法,包括错误的方法和优化后的解决方案,以及如何避免反转后的整数超出32位有符号整数范围的问题。
44 1
|
2月前
【LeetCode】整数翻转
【LeetCode】整数翻转
20 1
|
2月前
|
存储 C++
Leetcode第十二题(整数转罗马数字)
LeetCode第12题“整数转罗马数字”的解题方法,包括罗马数字的基本规则和特殊规则,以及如何使用C++实现整数到罗马数字的转换。
20 0
|
2月前
|
C++
Leetcode第十三题(罗马数字转整数)
这篇文章介绍了LeetCode第13题“罗马数字转整数”的解题方法,通过一个C++的类`Solution`中的`romanToInt`函数来实现,该函数使用哈希表和遍历字符串的方法,根据罗马数字的规则将输入的罗马数字字符串转换为对应的整数值。
56 0
|
2月前
|
算法 C++
Leetcode第八题(字符串转换整数(atoi))
这篇文章介绍了LeetCode上第8题“字符串转换整数(atoi)”的解题思路和C++的实现方法,包括处理前导空格、正负号、连续数字字符以及整数溢出的情况。
21 0
|
4月前
|
算法
LeetCode第12题目整数转罗马数字
该文章介绍了 LeetCode 第 12 题整数转罗马数字的解法,通过使用 TreeMap 按照整数从大到小排序,先使用大的罗马数字表示整数,再用小的,核心是先表示完大的罗马数字,想通此点该题较简单。
LeetCode第12题目整数转罗马数字
|
4月前
|
算法
LeetCode第8题字符串转换整数 (atoi)
该文章介绍了 LeetCode 第 8 题字符串转换整数 (atoi)的解法,需要对字符串进行格式解析与校验,去除前导空格和处理正负号,通过从高位到低位的计算方式将字符串转换为整数,并处理越界情况。同时总结了这几道题都需要对数字的表示有理解。
LeetCode第8题字符串转换整数 (atoi)
|
4月前
|
算法
LeetCode第13题目罗马数字转整数
该文章介绍了 LeetCode 第 13 题罗马数字转整数的解法,通过从大到小解析罗马数字,根据罗马数字的特点,按照从大到小的顺序匹配罗马数字和整数的关系,从而解决该问题,同时强调要注意观察题目考查的知识点特征。
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
125 2