Skip to content

Instantly share code, notes, and snippets.

@rezafikkri
Created June 8, 2022 23:18
Show Gist options
  • Save rezafikkri/b31a43f286d7ac2fa46e990d190b764f to your computer and use it in GitHub Desktop.
Save rezafikkri/b31a43f286d7ac2fa46e990d190b764f to your computer and use it in GitHub Desktop.
Class for convert roman symbol to int and also validate roman symbol
<?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