Valid Roman Numeral

正则表达式

思路

首先我们要熟悉罗马数的表达方式。M是1000,D是500,C是100,L是50,X是10,V是5,I是1。验证字符串是否是罗马数,我们先看一下有效的罗马数是什么样的,假设该数字小于5000,从千位到个位依次拆解。
千位的表达方式 M{0,4}

MMMM      4000
MMM       3000
MM        2000
M         1000

百位的表达方式 (CM|CD|D?C{0,3})

CM        900
DCCC      800
DCC       700
DC        600
D         500
CD        400
CCC       300
CC        200
C         100

十位的表达方式 (XC|XL|L?X{0,3})

XC        90
LXXX      80
LXX       70
LX        60
L         50
XL        40
XXX       30
XX        20
X         10

个位的表达方式 (IX|IV|V?I{0,3})

IX        9
VIII      8
VII       7
VI        6
V         5
IV        4
III       3
II        2
I         1

所以我们正则表达式的就是将这四个部分顺序组合在一起就行了。

注意

  • 罗马数字没有0

  • 正则表达式以^开头,以$结尾

代码

public boolean isRoman(){
    if(s.matches("^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$")) return true;
    return false;
}

Roman to Integer

减大加小法

复杂度

时间 O(N) 空间 O(1)

思路

如果我们通过Valid Roman Numeral确定了一个字符串是罗马数字后,我们就可以用一个非常简单的技巧来计算罗马数字的值,而不用考虑那些非法情况。我们知道罗马数字中较小的字母在较大的字母之前意味着较大的字母减去较小的字母,而较小的字母在较大的字母之后意味着较大的字母加上较小的字母。而且这种前面最多只有1个较小字母。所以我们只要在遍历的过程中记住该字母的上一个就行了。如果该字母比上一个小,说明可以直接加上。如果该字母比上一个大,说明正确的值应该是该字母减去上一个字母,而我们之前已经加上了上一个字母,所以我们要减去两倍的上一个字母,然后再加上当前字母。

代码

public class Solution {
    public int romanToInt(String s) {
        int total = charToInt(s.charAt(0));
        for(int i = 1; i < s.length(); i++){
            int prev = charToInt(s.charAt(i-1));
            int curr = charToInt(s.charAt(i));
            if(curr <= prev){
                total += curr;
            } else {
                total = total - 2 * prev + curr;
            }
        }
        return total;
    }

    public int charToInt(char c) {
        int data = 0;

        switch (c) {
            case 'I':
                data = 1;
                break;
            case 'V':
                data = 5;
                break;
            case 'X':
                data = 10;
                break;
            case 'L':
                data = 50;
                break;
            case 'C':
                data = 100;
                break;
            case 'D':
                data = 500;
                break;
            case 'M':
                data = 1000;
                break;
        }

        return data;
    }
}

Integer to Roman

贪心法

复杂度

时间 O(N) 空间 O(1)

思路

因为罗马数字都是由最大化的表示,比如10会表示成X而不是VV,所以我们可以从最大可能的表示向小的依次尝试。因为提示1-3999,所有的可能性不多,我们可以直接打表来帮助我们选择表示方法。在一个数量级中有四种可能的表示方法,以1-9为例,1-3是由I表示出来的,4是IV,5是V,6-8是V和若干个I,9是IX。

代码

public class Solution {
    public String intToRoman(int num) {
        String[] symbol = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        int[] value = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
        StringBuilder res = new StringBuilder();
        int i = 0;
        while(num>0){
            if(num>=value[i]){
                res.append(symbol[i]);
                num -= value[i];
            } else {
                i++;
            }
        }
        return res.toString();
    }
}

ethannnli
858 声望360 粉丝