Некоторые люди предлагают преобразовать римские цифры в целые числа, сортировать и отображать обратно. Есть более простой способ. Все, что нам действительно нужно сделать, это сравнить любые две произвольные римские цифры и позволить usort
сделать все остальное. Вот код, и я объясню его дизайн ниже.
$base = array( 'I' => 0, 'V' => 1, 'X' => 2, 'L' => 3,
'C' => 4, 'D' => 5, 'M' => 6 );
function single($a) { global $base; return $base[$a]; }
function compare($a, $b) {
global $base;
if(strlen($a) == 0) { return true; }
if(strlen($b) == 0) { return false; }
$maxa = max(array_map('single', str_split($a)));
$maxb = max(array_map('single', str_split($b)));
if($maxa != $maxb) {
return $maxa < $maxb;
}
if($base[$a[0]] != $base[$b[0]]) {
return $base[$a[0]] < $base[$b[0]];
}
return compare(substr($a, 1), substr($b, 1));
}
$a = array('XIX', 'LII', 'V', 'MCCXCIV', 'III', 'XIII');
usort($a, compare);
print_r($a);
Сначала мы создаем поисковый массив, чтобы назначить «величину» римским цифрам из одной цифры. Обратите внимание, что это не их десятичное значение, а просто числа, назначенные таким образом, что большие цифры получают большие значения. Затем мы создаем вспомогательную функцию single
, используемую некоторыми функциями PHP для получения величин.
Хорошо, теперь к сути алгоритма. Это функция compare
, которая иногда должна вызывать себя рекурсивно, когда ей нужно разорвать связь. По этой причине мы начнем с некоторых тестов, чтобы увидеть, достигло ли оно конечных состояний в рекурсии. Не обращайте на это внимания и посмотрите на первый интересный тест. Он проверяет, имеет ли сравниваемая цифра цифру, которая затмевает любую цифру другой. Например, если у одного из них X
, а у другого только I
и V
, то выигрывает тот, у кого X
. Это основывается на соглашении о том, что некоторые римские цифры недопустимы, например, VV
или VIIIII
или IIIIIIIII
. По крайней мере, я никогда не видел их написанными таким образом, поэтому считаю их недействительными.
Чтобы выполнить эту проверку, мы сопоставляем цифры с величинами и сравниваем максимумы. Ну, этот тест не может решить проблему. В этом случае безопасно сравнивать первые цифры каждого номера, поскольку нам не придется сталкиваться с такими запутанными проблемами, как V < IX
, когда первые цифры не говорят правду. Эти запутанные ситуации были решены путем сравнения самых больших цифр.
Наконец, если первые цифры равны, удалите их и повторите. В какой-то момент одна из цифр будет уменьшена до пустой строки, и те начальные тесты, которые мы временно игнорировали, позаботятся об этом.
Этот метод прошел все тесты, которые я ему проводил, но сообщите мне, если найдете ошибку или оптимизацию.