[2] 3的幂和罗马数字转整数

文章介绍了如何使用Python解决LeetCode上的两个问题:判断一个整数是否为3的幂次方,以及将罗马数字转换为整数。对于3的幂次方问题,提供了除法和遍历3的幂的方法,以及递归实现。罗马数字转整数的解法包括逐字符处理和考虑特殊情况的转换规则。

内容来自LeetCode,使用Python完成

1. 3的幂

题目要求

给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。

整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x

示例 1:

输入:n = 27
输出:true
示例 2:

输入:n = 0
输出:false
示例 3:

输入:n = 9
输出:true
示例 4:

输入:n = 45
输出:false

进阶:你能不使用循环或者递归来完成本题吗?

思路

比较直观的可以想到可以用n一直除以3,如果有余则说明为False。还有一种办法是用从小开始遍历3的幂,遍历至与n相等则为True,如果遍历至大于n,则为False。两种思路都是比较暴力的解法。

#从小开始遍历3的幂
class Solution:
    def isPowerOfThree(self, n: int) -> bool:
        if n == 1:
            return True
        mi = 1
        flag = 0
        while mi < n:
            mi = mi * 3
            if mi == n:
                flag = 1
        if flag == 1:
            return True
        else:
            return False
#n持续除以3
class Solution:
    def isPowerOfThree(self, n: int) -> bool:
        if n == 0 :
            return False
        while n != 1:
            if n%3 != 0:
                return False
            n = n / 3
        return True

上面两种解法都还行,一个时间比较快一个内存占用比较小。下面再用递归尝试实现上面两种解法。

#n持续除以3 的递归实现
class Solution:

    def isPowerOfThree(self, n: int) -> bool:
        def digui(n: int) -> bool :
            if n == 1:
                return True
            if n % 3 != 0 or n == 0:
                return False
            else:
                return digui(n/3)
        return digui(n) 

官方题解的另一种办法为判断是否为最大3的幂的约数。题解论述如下:

在题目给定的 32位有符号整数的范围内,最大的 3 的幂为 3^{19} = 1162261467。我们只需要判断 n 是否是 3^{19}的约数即可。。。确实比较取巧

class Solution:
    def isPowerOfThree(self, n: int) -> bool:
        return n > 0 and 1162261467 % n == 0

2. 罗马数字转整数

题目要求

罗马数字包含以下七种字符: 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。
给定一个罗马数字,将其转换成整数。

思路

在没有特殊规则的情况下,很容易想到可以用多个if语句来解决(其实更直接想到了C 中的switch 语句,python3.10增加了类似的match...case 的条件判断,更为方便)。但是由于有特殊情况的存在,需要做更多的限制来准备转换。

class Solution:
    def romanToInt(self, s: str) -> int:
        num = 0
        for i in range(len(s)):
            if s[i] == 'I':
                num += 1

            if s[i] == 'V':
                if i == 0:
                    num += 5
                elif s[i-1] == 'I':
                    num += 3
                else:
                    num += 5

            if s[i] == 'X':
                if i == 0:
                    num += 10
                elif s[i-1] == 'I':
                    num += 8
                else:
                    num += 10

            if s[i] == 'L':
                if i == 0:
                    num += 50
                elif s[i-1] == 'X':
                    num += 30
                else:
                    num += 50

            if s[i] == 'C':
                if i == 0:
                    num += 100
                elif s[i-1] == 'X':
                    num += 80
                else:
                    num += 100

            elif s[i] == 'D':
                if i == 0:
                    num += 500
                elif s[i-1] == 'C':
                    num += 300
                else:
                    num += 500

            elif s[i] == 'M':
                if i == 0:
                    num += 1000
                elif s[i-1] == 'C':
                    num += 800
                else:
                    num += 1000
        return num

虽然写的很麻烦,但是实际运行结果也还行。

接下来是学习的解法

官方解题

通常情况下,罗马数字中小的数字在大的数字的右边。若输入的字符串满足该情况,那么可以将每个字符视作一个单独的值,累加每个字符对应的数值即可。

若存在小的数字在大的数字的左边的情况,根据规则需要减去小的数字。对于这种情况,我们也可以将每个字符视作一个单独的值,若一个数字右侧的数字比它大,则将该数字的符号取反。(同时还用到了字典)

class Solution:

    SYMBOL_VALUES = {
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000,
    }

    def romanToInt(self, s: str) -> int:
        ans = 0
        n = len(s)
        for i, ch in enumerate(s):
            value = Solution.SYMBOL_VALUES[ch]
            if i < n - 1 and value < Solution.SYMBOL_VALUES[s[i + 1]]:
                ans -= value
            else:
                ans += value
        return ans

另有人提出使用正则表达式来解决

先空着

上述解题都是从左向右来看的,有人提出可以从右向左遍历,纪录遇到的最大的数字,遇到更大的加,遇到小的减。

class Solution:
    def romanToInt(self, s: str) -> int:
        roman = {
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000,
        }
        num = 0
        highest = 0
        for i in s[::-1]:
            if highest <= roman[i]:
                num += roman[i]
                highest = roman[i]
            else:
                num -= roman[i]
        return num

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值