Created
June 8, 2022 23:18
-
-
Save rezafikkri/b31a43f286d7ac2fa46e990d190b764f to your computer and use it in GitHub Desktop.
Class for convert roman symbol to int and also validate roman symbol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Solution | |
{ | |
/** @var array SYMBOLS This is roman symbols cannot loop */ | |
const SYMBOLS = ['V' => 5, 'L' => 50, 'D' => 500]; | |
/** @var array LOOP_SYMBOLS This is roman symbols can loop */ | |
const LOOP_SYMBOLS = ['I' => 1, 'X' => 10, 'C' => 100, 'M' => 1000]; | |
private function romanValidate(string $s)//: bool | |
{ | |
foreach (static::SYMBOLS as $key => $val) { | |
// if roman symbol cannot loop looped > 1 | |
if (substr_count($s, $key) > 1) return false; | |
} | |
$roman = str_split($s); | |
$countSameRoman = 1; | |
foreach ($roman as $key => $val) { | |
if ($val != ($roman[$key - 1] ?? 0)) { | |
$countSameRoman = 1; | |
} elseif ($val == ($roman[$key - 1] ?? 0)) { | |
$countSameRoman++; | |
} | |
$nowRomanInt = static::LOOP_SYMBOLS[$val] ?? 0; | |
// if now roman is symbol can loop | |
if ($nowRomanInt) { | |
// if roman repeated in succession and looped > 3 | |
if ($countSameRoman > 3) return false; | |
} | |
$nextRomanInt = static::LOOP_SYMBOLS[$roman[$key + 1] ?? 0] ?? static::SYMBOLS[$roman[$key + 1] ?? 0] ?? 0; | |
// if roman symbol can loop looped <= 3 and > 1 | |
if ($countSameRoman <= 3 && $countSameRoman > 1) { | |
// if value of now roman symbol can loop < next roman symbol (can roman symbol cannot loop and can loop) | |
if ($nowRomanInt < $nextRomanInt) return false; | |
} | |
// if now roman is symbol cannot loop | |
if (!empty(static::SYMBOLS[$val])) { | |
// if now roman int < next roman int (can roman symbol cannot loop and can loop) | |
if (static::SYMBOLS[$val] < $nextRomanInt) return false; | |
} | |
// if now roman symbol can loop < next roman symbol (can roman symbol cannot loop and can loop) | |
if ($nowRomanInt < $nextRomanInt) { | |
$nextRoman = $roman[$key + 1] ?? 0; | |
// if now roman == I and next roman != V and X | |
if ($val == 'I' && $nextRoman != 'V' && $nextRoman != 'X') return false; | |
// if now roman == X and next roman != L and C | |
if ($val == 'X' && $nextRoman != 'L' && $nextRoman != 'C') return false; | |
// if now roman == C and next roman != D and M | |
if ($val == 'C' && $nextRoman != 'D' && $nextRoman != 'M') return false; | |
} | |
} | |
return true; | |
} | |
public function romanToInt(string $s): int | |
{ | |
// validate roman | |
if (!$this->romanValidate($s)) return 0; | |
$roman = str_split($s); | |
$countRoman = count($roman); | |
if ($countRoman == 1) { | |
return static::LOOP_SYMBOLS[$roman[0]] ?? static::SYMBOLS[$roman[0]] ?? null; | |
} | |
$romanInt = 0; | |
$i = 0; | |
while ($roman) { | |
// if $roman[$i] exist in LOOP_SYMBOLS | |
if (!empty(static::LOOP_SYMBOLS[$roman[$i]])) { | |
$nowRomanInt = static::LOOP_SYMBOLS[$roman[$i]]; | |
$nextRomanInt = static::LOOP_SYMBOLS[$roman[$i + 1] ?? 0] ?? static::SYMBOLS[$roman[$i + 1] ?? 0] ?? 0; | |
// if value $nowRomanInt < $nextRomanInt | |
if ($nowRomanInt < $nextRomanInt) { | |
$romanInt += $nextRomanInt - $nowRomanInt; | |
$i += 2; | |
} else { | |
$romanInt += $nowRomanInt; | |
$i++; | |
} | |
} elseif (!empty(static::SYMBOLS[$roman[$i]])) { | |
$romanInt += static::SYMBOLS[$roman[$i]]; | |
$i++; | |
} else { | |
return false; | |
} | |
if ($i == count($roman)) $roman = false; | |
} | |
return $romanInt; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment