Ruby를 사용하여 로마 숫자를 정수로 변환
13011 단어 rubyleetcodeprogramming
스포일러 경고: 이 게시물은 일반적인 코딩 문제에 대한 해결책을 보여줍니다. 다음은 leetcode의 문제에 대한 링크이며 계속 읽기 전에 먼저 자신의 방식으로 문제를 해결하려는 경우 지침이 포함되어 있습니다. 그렇지 않으면 아래에서 나와 함께하십시오!
소개
최근에는 leetcode 및 codewars 솔루션을 정기적으로 제출하여 코딩 작업을 유지하려고 노력하고 있습니다. 워밍업을 위해 먼저 '쉬운' 것부터 시작해야겠다고 생각했습니다. 이것은 쉬운 것으로 분류되었지만 합격률은 58%에 불과합니다.
문제 정의
기본적으로 목표는 로마 숫자 문자열이 입력으로 주어지면 동등한 정수를 출력하는 함수를 작성하는 것입니다. 예를 들어
"MCMXCIV" => 1994
.데이터 구조에 대한 생각.
내 첫 번째 생각은 기본 로마 숫자를 다음과 같이 해시 맵을 사용하여 해당 값에 매핑해야 한다는 것입니다.
def numerals
{
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000
}
end
나는 또한 문자열과 아마도 배열을 다루고 있다고 언급했습니다.
문자열 및 배열 조작
문자열의 문자도 평가해야 한다는 것을 깨달았습니다. Ruby에는 문자열의 개별 문자를 반복하는 편리한
string#each_char
메서드가 있으므로 'VIII'
는 ['V', 'I', 'I', 'I' ]
와 같은 문자 배열로 분할됩니다. 이제 배열로 작업하고 있으므로 각 숫자 문자를 해당 값에 매핑하는 데 사용할 수 있는 array#map
메서드에 액세스할 수 있습니다.
['V', 'I', 'I', 'I'].map { |n| numerals[n] }
# => [5, 1, 1, 1]
# using built-in array#sum method
['V', 'I', 'I', 'I'].map { |n| numerals[n] }.sum
# => [5, 1, 1, 1].sum
# => 8
이제 끝난거 맞죠? 우리는 이미 머릿속에서 하는 과정을 기본적으로 다루었습니다(5 + 1 + 1 + 1 = 8).
잡았다
그러나 까다로운 부분은 로마 숫자가 5 또는 10의 배수보다 하나의 인수보다 작은 숫자를 의미할 때 발생합니다. IV는 V보다 하나 적고 5에서 1을 빼고 4를 반환한다는 의미입니다. 위에 링크된 운동 지침에서:
위의 방법은 어쨌든 숫자를 "그룹화"하지 않기 때문에 문자열의 매핑된 문자를 단순히 합산하려는 계획에 렌치를 던집니다. 아마도 이러한 특별한 경우를 추출하는 방법이 있을 것입니다. IX 및 CM.
먼저 위와 같은 해시로 정의해 보겠습니다.
def special_numerals
{
'IV' => 4,
'IX' => 9,
'XL' => 40,
'XC' => 90,
'CD' => 400,
'CM' => 900
}
end
스캔 방법
이제 문자열을 스캔하고 이러한 특수 숫자를 확인하는 방법이 필요합니다. 고맙게도 Ruby는 문자열에서 찾은 일치 항목의 배열을 반환하는
string#scan
메서드를 사용하여 쉽게 만들 수 있습니다. s = "MCMXCIV" # 1994
special_matches = s.scan(/IV|IX|XL|XC|CD|CM/)
# => ["CM", "XC", "IV"]
이를 통해 위에서 사용한 것과 동일한 "매핑 및 합계"논리를 사용할 수 있습니다. 그러나 나머지 "비특수"문자는 어떻게 처리해야 할까요? 이것은 잠재적으로 일부 숫자를 두 번 세는 결과를 낳습니다. 간단한 점검으로 예방할 수 있습니다.
먼저 문자열에 사용된 특수 숫자가 있는지 확인합니다. 그렇다면 해당 값에 매핑하고 합산하십시오. 이 합계를 변수에 기록합니다.
gsub 방법
둘째, 나머지 숫자를 정확하게 합산할 수 있도록 문자열에서 "특수"숫자를 제거합니다. 이것은 편리한
string#gsub
방법이 들어오는 곳입니다. s = "MCMXCIV" # 1994
special_matches = s.scan(/IV|IX|XL|XC|CD|CM/)
# => ["CM", "XC", "IV"]
special_sum = special_matches.map { |m| special_numerals[m]}.sum
# => 900 + 90 + 4 == 994
special_matches.each { |m| s.gsub!(m, '') }
# s is modified in place with its special numerals removed.
# => s == "M"
# we still need to add 1000 to our result
따라서 입력 문자열은 이제 "M"이며 동일한 논리를 사용하여 합산할 수 있습니다. 이 경우에는 하나의 문자만 있지만 논리는 여러 문자에 대해 동일합니다.
normal_sum = s.each_char.map { |c| numerals[c] }.sum
# => numerals['M'] == 1000
# => [1000].sum
# => 1000
해결책
모두 합치면 문자열에 "특수"숫자가 있는 경우 "특수"숫자 합계와 "정상"숫자 합계를 반환합니다. 그렇지 않으면 "정상"합계를 반환합니다. 코드에서 이 논리를 다음 솔루션으로 변환했습니다.
def roman_to_int(s)
special_matches = s.scan(/IV|IX|XL|XC|CD|CM/)
if special_matches
special_sum = special_matches.map { |m| special_numerals[m]}.sum
special_matches.each { |m| s.gsub!(m, '') }
end
normal_sum = s.each_char.map { |c| numerals[c] }.sum
return (special_sum + normal_sum) if special_sum
normal_sum
end
def numerals
{
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000
}
end
def special_numerals
{
'IV' => 4,
'IX' => 9,
'XL' => 40,
'XC' => 90,
'CD' => 400,
'CM' => 900
}
end
roman_to_s("MCMXCIV")
# => 1994
결론
나는 이것이 leetcode에서 가장 빠른 솔루션이라고 생각하지 않지만 개인적으로 읽을 수 있다고 생각합니다. 이것은 숫자를 정수 값에 매핑하는 것을 간단하게 만든 해시 데이터 구조의 힘에 대한 증거입니다.
이 문제를 어떻게 해결했습니까? 아니면 무엇을 다르게 할 수 있습니까? 아래 댓글로 알려주세요!
Reference
이 문제에 관하여(Ruby를 사용하여 로마 숫자를 정수로 변환), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/joemccanndev/using-ruby-to-translate-roman-numerals-to-integers-3go6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)