坂本  篤司

坂本 篤司

1648119869

C#で数値をローマ字に変換する

序章

前回の記事では、ローマ数字を数値に変換する方法を見ました。この記事では、正反対のことを行います。

これは、難易度が中程度に設定されたリートコードの問題番号12です。前回行ったのは、現在のローマ字と次のローマ字を比較し、基本的な足し算と引き算を実行することです。

この問題は、少し余分なスペースがある場合とほぼ同じです。余分なスペースとはどういう意味ですか?さて、見てみましょう。 

問題

Leetcodeから直接出た問題は次のとおりです。

ローマ数字は、I、V、X、L、C、D、およびMの7つの異なる記号で表されます。

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

たとえば、2はローマ数字でIIと表記され、2つだけが足し合わされます。12はXIIと書かれていますが、これは単にX+IIです。番号27は、XX + V+IIであるXXVIIと表記されます。

ローマ数字は通常、左から右に最大から最小に書かれています。ただし、4の数字はIIIIではありません。代わりに、4番目の数字はIVと書かれています。1つは5の前にあるので、それを引いて4にします。同じ原則が、IXと書かれている9番にも当てはまります。減算が使用される6つの例があります。

  • V(5)とX(10)の前に置いて、4と9を作ることができます。
  • XをL(50)とC(100)の前に配置して、40と90を作成できます。
  • CをD(500)とM(1000)の前に配置して、400と900を作成できます。

整数を指定して、ローマ数字に変換します。

Example 1:
Input: num = 3
Output: "III"
Explanation: 3 is represented as 3 ones.

Example 2:
Input: num = 58
Output: "LVIII"
Explanation: L = 50, V = 5, III = 3.

Example 3:
Input: num = 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

ベーシック

ロジック

このソリューションには2つのアプローチがあります。1つ目はO(n * m)の複雑さで、2つ目はO(n)です。両方見てみましょう。

最初のアプローチ

この問題に必要なデータ構造は、  キーと値のペアを格納する必要があるため、辞書です。先ほど、余分なスペースが必要だと言いました。IV、IX、XL、XC、CD、CMの6つの条件を処理するには、追加のスペースが必要です。

if elseステートメントを使用するか、caseを切り替えてこれらの条件を処理するか、以下のようにデータ構造にこれらの値を追加するだけです。

Dictionary < string, int > romanNumbersDictionary = new() {
    {
        "I",
        1
    }, {
        "IV",
        4
    }, {
        "V",
        5
    }, {
        "IX",
        9
    }, {
        "X",
        10
    }, {
        "XL",
        40
    }, {
        "L",
        50
    }, {
        "XC",
        90
    }, {
        "C",
        100
    }, {
        "CD",
        400
    }, {
        "D",
        500
    }, {
        "CM",
        900
    }, {
        "M",
        1000
    }
};

C#

 リスト1:ローマ字から数字への辞書

ロジックの場合、必要なのは、辞書を大きい番号から小さい番号へと逆の順序でループすることだけです。

ヒント:逆の順序で保存されたディクショナリ値を保存できます。ここでは、デモンストレーションのために、ディクショナリのReverse()メソッドを使用しています。

辞書の各項目について、数を比較し、反復ごとに数を減らす必要があります。

たとえば、350を入力として取りましょう。

  • 辞書を逆の順序でトラバースします
  • 350未満の値が見つかるまで、350を辞書の各値と比較します。そこから100になり、350が辞書の次の値よりも小さくなるまで350の数値を縮小し始めます。
  • これには、100の3ラウンド、つまり100 * 3 = "CCC"が必要です。これで、50が残り、50が見つかるまでさらに下に移動し、50を縮小します。
  • 結果に「L」を連結します。したがって、最終結果はCCCLになります。
  • 数値が0未満であるかどうかを確認し、はいの場合はループを中断して結果を返します。

実行の流れを理解するには、以下のフローチャートを参照してください。たとえば、1994を使用しています。反復ごとに数値を更新する方法を確認できます。


図1:整数からローマ字へのフローチャート

ロジックコードを理解すれば、非常に簡単です。 

internal class NumbersToRoman {
    public string IntToRoman(int num) {
        string romanResult = "";
        Dictionary < string, int > romanNumbersDictionary = new() {
            {
                "I",
                1
            }, {
                "IV",
                4
            }, {
                "V",
                5
            }, {
                "IX",
                9
            }, {
                "X",
                10
            }, {
                "XL",
                40
            }, {
                "L",
                50
            }, {
                "XC",
                90
            }, {
                "C",
                100
            }, {
                "CD",
                400
            }, {
                "D",
                500
            }, {
                "CM",
                900
            }, {
                "M",
                1000
            }
        };
        foreach(var item in romanNumbersDictionary.Reverse()) {
            if (num <= 0) break;
            while (num >= item.Value) {
                romanResult += item.Key;
                num -= item.Value;
            }
        }
        return romanResult;
    }
}

C#

リスト2:Approach1.cs、O(n * m)の時間計算量、O(n)の空間計算量


図2:最初のアプローチの成功スナップショット

:ここでは、キーを値に手動でマップする必要がないため、このソリューションをお勧めします。しかし、ここではO(n * m)の時間計算量があり、O(n)の空間計算量があります。

このソリューションをO(n)にスケーリングできますが、トレードオフはスペースの複雑さを拡張することです。それをやってみましょう。1つはローマ数字用、もう1つは数字用の2つの配列が必要です。

2番目のアプローチ

public string IntToRoman(int num) {
    string romanResult = string.Empty;
    string[] romanLetters = {
        "M",
        "CM",
        "D",
        "CD",
        "C",
        "XC",
        "L",
        "XL",
        "X",
        "IX",
        "V",
        "IV",
        "I"
    };
    int[] numbers = {
        1000,
        900,
        500,
        400,
        100,
        90,
        50,
        40,
        10,
        9,
        5,
        4,
        1
    };
    int i = 0;
    while (num != 0) {
        if (num >= numbers[i]) {
            num -= numbers[i];
            romanResult += romanLetters[i];
        } else {
            i++;
        }
    }
    return romanResult;
}

C#

リスト3:アプローチ2、O(n)の時間計算量、O(n + m)の空間計算量

このソリューションでは、時間計算量O(n)でコードを最適化しましたが、空間計算量はO(n + m)になりました。


図3:ソリューション2の成功のスナップショット

あなた自身の冒険wrtアプローチを選択するのはあなた次第です。

私が感じているのは、2番目のアプローチはユーザーエラーにつながる可能性があるということです。入力中に、どちらかの配列の要素を簡単に一致させることができません。したがって、各キーが独自の値を表していることを確認するために、キーと値のペアを追跡する必要があります。

この問題の範囲については、入力が制限されているので問題ありませんが、将来入力が拡張されると、問題が発生する可能性があります。 

しかし、それは別の日の議論です。それまでは良いものがあります。 

ソース:https ://www.c-sharpcorner.com/article/convert-numbers-to-roman-characters-in-c-sharp/ 

#csharp 

What is GEEK

Buddha Community

C#で数値をローマ字に変換する
坂本  篤司

坂本 篤司

1648119869

C#で数値をローマ字に変換する

序章

前回の記事では、ローマ数字を数値に変換する方法を見ました。この記事では、正反対のことを行います。

これは、難易度が中程度に設定されたリートコードの問題番号12です。前回行ったのは、現在のローマ字と次のローマ字を比較し、基本的な足し算と引き算を実行することです。

この問題は、少し余分なスペースがある場合とほぼ同じです。余分なスペースとはどういう意味ですか?さて、見てみましょう。 

問題

Leetcodeから直接出た問題は次のとおりです。

ローマ数字は、I、V、X、L、C、D、およびMの7つの異なる記号で表されます。

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

たとえば、2はローマ数字でIIと表記され、2つだけが足し合わされます。12はXIIと書かれていますが、これは単にX+IIです。番号27は、XX + V+IIであるXXVIIと表記されます。

ローマ数字は通常、左から右に最大から最小に書かれています。ただし、4の数字はIIIIではありません。代わりに、4番目の数字はIVと書かれています。1つは5の前にあるので、それを引いて4にします。同じ原則が、IXと書かれている9番にも当てはまります。減算が使用される6つの例があります。

  • V(5)とX(10)の前に置いて、4と9を作ることができます。
  • XをL(50)とC(100)の前に配置して、40と90を作成できます。
  • CをD(500)とM(1000)の前に配置して、400と900を作成できます。

整数を指定して、ローマ数字に変換します。

Example 1:
Input: num = 3
Output: "III"
Explanation: 3 is represented as 3 ones.

Example 2:
Input: num = 58
Output: "LVIII"
Explanation: L = 50, V = 5, III = 3.

Example 3:
Input: num = 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

ベーシック

ロジック

このソリューションには2つのアプローチがあります。1つ目はO(n * m)の複雑さで、2つ目はO(n)です。両方見てみましょう。

最初のアプローチ

この問題に必要なデータ構造は、  キーと値のペアを格納する必要があるため、辞書です。先ほど、余分なスペースが必要だと言いました。IV、IX、XL、XC、CD、CMの6つの条件を処理するには、追加のスペースが必要です。

if elseステートメントを使用するか、caseを切り替えてこれらの条件を処理するか、以下のようにデータ構造にこれらの値を追加するだけです。

Dictionary < string, int > romanNumbersDictionary = new() {
    {
        "I",
        1
    }, {
        "IV",
        4
    }, {
        "V",
        5
    }, {
        "IX",
        9
    }, {
        "X",
        10
    }, {
        "XL",
        40
    }, {
        "L",
        50
    }, {
        "XC",
        90
    }, {
        "C",
        100
    }, {
        "CD",
        400
    }, {
        "D",
        500
    }, {
        "CM",
        900
    }, {
        "M",
        1000
    }
};

C#

 リスト1:ローマ字から数字への辞書

ロジックの場合、必要なのは、辞書を大きい番号から小さい番号へと逆の順序でループすることだけです。

ヒント:逆の順序で保存されたディクショナリ値を保存できます。ここでは、デモンストレーションのために、ディクショナリのReverse()メソッドを使用しています。

辞書の各項目について、数を比較し、反復ごとに数を減らす必要があります。

たとえば、350を入力として取りましょう。

  • 辞書を逆の順序でトラバースします
  • 350未満の値が見つかるまで、350を辞書の各値と比較します。そこから100になり、350が辞書の次の値よりも小さくなるまで350の数値を縮小し始めます。
  • これには、100の3ラウンド、つまり100 * 3 = "CCC"が必要です。これで、50が残り、50が見つかるまでさらに下に移動し、50を縮小します。
  • 結果に「L」を連結します。したがって、最終結果はCCCLになります。
  • 数値が0未満であるかどうかを確認し、はいの場合はループを中断して結果を返します。

実行の流れを理解するには、以下のフローチャートを参照してください。たとえば、1994を使用しています。反復ごとに数値を更新する方法を確認できます。


図1:整数からローマ字へのフローチャート

ロジックコードを理解すれば、非常に簡単です。 

internal class NumbersToRoman {
    public string IntToRoman(int num) {
        string romanResult = "";
        Dictionary < string, int > romanNumbersDictionary = new() {
            {
                "I",
                1
            }, {
                "IV",
                4
            }, {
                "V",
                5
            }, {
                "IX",
                9
            }, {
                "X",
                10
            }, {
                "XL",
                40
            }, {
                "L",
                50
            }, {
                "XC",
                90
            }, {
                "C",
                100
            }, {
                "CD",
                400
            }, {
                "D",
                500
            }, {
                "CM",
                900
            }, {
                "M",
                1000
            }
        };
        foreach(var item in romanNumbersDictionary.Reverse()) {
            if (num <= 0) break;
            while (num >= item.Value) {
                romanResult += item.Key;
                num -= item.Value;
            }
        }
        return romanResult;
    }
}

C#

リスト2:Approach1.cs、O(n * m)の時間計算量、O(n)の空間計算量


図2:最初のアプローチの成功スナップショット

:ここでは、キーを値に手動でマップする必要がないため、このソリューションをお勧めします。しかし、ここではO(n * m)の時間計算量があり、O(n)の空間計算量があります。

このソリューションをO(n)にスケーリングできますが、トレードオフはスペースの複雑さを拡張することです。それをやってみましょう。1つはローマ数字用、もう1つは数字用の2つの配列が必要です。

2番目のアプローチ

public string IntToRoman(int num) {
    string romanResult = string.Empty;
    string[] romanLetters = {
        "M",
        "CM",
        "D",
        "CD",
        "C",
        "XC",
        "L",
        "XL",
        "X",
        "IX",
        "V",
        "IV",
        "I"
    };
    int[] numbers = {
        1000,
        900,
        500,
        400,
        100,
        90,
        50,
        40,
        10,
        9,
        5,
        4,
        1
    };
    int i = 0;
    while (num != 0) {
        if (num >= numbers[i]) {
            num -= numbers[i];
            romanResult += romanLetters[i];
        } else {
            i++;
        }
    }
    return romanResult;
}

C#

リスト3:アプローチ2、O(n)の時間計算量、O(n + m)の空間計算量

このソリューションでは、時間計算量O(n)でコードを最適化しましたが、空間計算量はO(n + m)になりました。


図3:ソリューション2の成功のスナップショット

あなた自身の冒険wrtアプローチを選択するのはあなた次第です。

私が感じているのは、2番目のアプローチはユーザーエラーにつながる可能性があるということです。入力中に、どちらかの配列の要素を簡単に一致させることができません。したがって、各キーが独自の値を表していることを確認するために、キーと値のペアを追跡する必要があります。

この問題の範囲については、入力が制限されているので問題ありませんが、将来入力が拡張されると、問題が発生する可能性があります。 

しかし、それは別の日の議論です。それまでは良いものがあります。 

ソース:https ://www.c-sharpcorner.com/article/convert-numbers-to-roman-characters-in-c-sharp/ 

#csharp