算法修炼之路—【字符串】Leetcode 13 罗马数字转整数

题目描述

罗马数字包含以下七种字符:I, V, X, L, C, DM

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

例如,罗马数字2写作II,即为两个并列的I12写作XII,即为X + II27写作XXVII,即为XX + V + II.

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

  • I可以放在VX的左边,来表示数字 4, 9
  • X可以放在LC的左边,用来表示数字40, 90
  • C可以放在DM的左边,来表示数字400, 900

给定一个罗马数字,将其转换成整数。确保在1-3999的范围内。

示例1:

输入: s = “III”
输出: 3

示例2:

输入: s = “IV”
输出: 4

示例3:

输入: s = “IX”
输出: 9

示例4:

输入: s = “LVIII”
输出: 58
解释: L = 50, V = 5, III = 3.

示例5:

输入: s = “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

思路分析

这道题难度为简单, 通过题意我们可以先将其看作简单的转换,接着是一个数值累加的过程,只不过这里存在着一些特殊情况为减去值,那么我们将规律尽量统一化:

  1. 大多数情况下,为累加
  2. 特殊情况下,为减去当前值

对于情况1 大多数情况下的累加,观察字符串,我们采用从右至左的角度,当val(rightNum) >= val(curr)时,此时为加法;对于情况2 特殊情况下的减值,当val(currLeft) < val(curr)时,此时为减法。

通过以上简单分析我们可知,我们首先需要一个转换的标准,这里我们借用HashMap<Character, Integer>来存放题干中罗马数字字符与数字的转换原则;之后我们还需要存在一个记忆变量rightNum,但是仅需存放最新的右边值即可,即rightNum是随着遍历动态刷新的。我们直接给上代码:

解题代码

    public static int solution(String s){
        if(s == null || s == "") return 0;
        
        // HashMap to storage rules exchanged.
        Map<Character, Integer> map = new HashMap<>();
        map.put('I', 1);
        map.put('V', 5);
        map.put('X', 10);
        map.put('L', 50);
        map.put('C', 100);
        map.put('D', 500);
        map.put('M', 1000);       
        
        
        int len = s.length();
        int rightNum = map.get(s.charAt(len - 1));
        int res = rightNum;
        
        for(int i = len-2;i>=0;i--){
            int cur = map.get(s.charAt(i));
            if(cur < rightNum)
                res -= cur;
            else if(cur >= rightNum)
                res += cur;
            rightNum = cur;
        }
        return res;
    }

复杂度分析

时间复杂度: 我们对字符串进行了一次遍历,故时间复杂度为O(N);
空间复杂度: 我们虽然对转换规则进行了HashMap存储,但是其不随N变化,所以空间复杂度为O(1).

Github源码

完整可运行文件请访问GitHub

发布了53 篇原创文章 · 获赞 59 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u011106767/article/details/105744578
今日推荐