python编程比赛初赛 组成最小罗马数字_leetcode 题解 12python3@ 通过使用罗马数字的最单元位来构造数组 + 构造数字算法...

题目描述

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值

I 1

V 5

X 10

L 50

C 100

D 500

M 1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。

X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。

C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

解题思路

由题意可知,从整数转化为罗马数字的时候,每个位上的数字(0~9)都是由四种类型的罗马数字组成的

比如个位数:

'(null)'

I

V

X

通过此思路,我们可以构造一个二维list。

self.Glossary = [

['I','V','X'],

['X','L','C'],

['C','D','M'],

['M'],

]

傲娇脸(感觉这种思路更深一点)

相比其他巨佬(我是菜鸡)的题解中构造的数组,比如@liweiwei1419的题解:

nums = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]

romans = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]

这种思路相当于是将每个位数(比如个位数)的1-4-5-9给单独列出来了。其中1 5 10 是构造数字的单元(最底层)的单元字符,而因为4和9的构造规则和123 678的规则不一样,所以题主将1-4-5-9单独列出来再进行算法匹配,就更顺畅。这位巨佬的每个位数需要构造4个字符,但是上述的构造方法只需要定义三个单元字符。

m = [

['', 'M', 'MM', 'MMM'],

['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'],

['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],

['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX']

]

可能大家看到这种的时候会想,这么直接的吗,把每个位数的1-9全部列出来了,但是我感觉这种方法相比上面第一个巨佬的方法更好一些,因为这种方法的思路比较清晰:我分位数来构造数组,将每个位的所有出现的情况全部列出来,这种方式就相当于我们先花最大的空间来构造我们需要的(类似哈希表吧),然后再用复杂度比较低的算法来进行简单的匹配。

class Solution:

def intToRoman(self, num):

m = [

['', 'M', 'MM', 'MMM'],

['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'],

['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],

['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX']

]

d = [1000, 100, 10, 1]

r = ''

for k, v in enumerate(d):

r += m[k][int(num/v)]

num = num % v

return r

妙啊,点个赞。(这种思路将算法最简单化,但是空间的使用也是最大的)

好了,上述引用的两个大佬,我真的觉得很牛逼,将空间略微复杂化了然后使用最巧妙地算法。

那使用这种最底层地单元化地构造方法:

self.Glossary = [

['I','V','X'],

['X','L','C'],

['C','D','M'],

['M'],

]

如何来写算法呢

罗马数字地构造思路:

在每一个(十分)位上

用1单元位来叠加构造1-3 比如I,II,III 或者X,XX,XXX

用1和5单元位来构造4 比如IV 或者XL

用5来直接使用 比如V 或者L

用1和5来构造6-8 比如VI,VII,VIII或者LX,LXX,LXXX

用1和10来构造9 比如IX 或者XC

说到这里其实,罗马数字是一种5进制地数,(个人认为哈)。

但是由于我们地整数时10进制地,所以4和9地构造相当于就是两种不同地构造方法(用此十分位的1和5来构造、用此此十分位的1和下个十分位的10来构造)

那我们需要将这几个特例拿出来:

while _

res+=v[0]

_+=1

if _==4:

res=v[0]+v[1]

elif _==5:

res=v[1]

elif _==9:

res=v[0]+v[2]

具体代码如下:

def viaDict(self, num:int) -> str:

resl,nlist=[],list(str(num))

for k,v in enumerate(self.Glossary):

try:

_,res,x=0,'',int(nlist.pop())

while _

res+=v[0]

_+=1

if _==4:

res=v[0]+v[1]

elif _==5:

res=v[1]

elif _==9:

res=v[0]+v[2]

resl.insert(0,res)

except (StopIteration,IndexError):

# 遇到StopIteration就退出循环

break

return "".join(resl)

代码

#

# @lc app=leetcode.cn id=12 lang=python3

#

# [12] 整数转罗马数字

#

# @lc code=start

class Solution:

def __init__(self):

self.Glossary = [

['I','V','X'],

['X','L','C'],

['C','D','M'],

['M'],

]

def viaDict(self, num:int) -> str:

resl=[]

# get the Iterator Object first:

nlist = list(str(num))

for k,v in enumerate(self.Glossary):

try:

_=0

res=''

x=int(nlist.pop())

while _

res+=v[0]

_+=1

if _==4:

res=v[0]+v[1]

elif _==5:

res=v[1]

elif _==9:

res=v[0]+v[2]

resl.insert(0,res)

except (StopIteration,IndexError):

# 遇到StopIteration就退出循环

break

return "".join(resl)

def intToRoman(self, num: int) -> str:

return {

1:lambda num:self.viaDict(num),

}[1](num)

# @lc code=end

if __name__ == "__main__":

solve = Solution()

# print(solve.Glossary.items())

print(solve.intToRoman(444))

一百个人读哈姆雷特就有一百个哈姆雷特。

leetcode

leetcode解题得的源码,解题思路在代码的注释里。

本作品采用《CC 协议》,转载必须注明作者和本文链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值