leetcode刷题笔记Day2

leetcode Day2

今天我才发现,同一段代码,每次提交出来的时间以及内存结果可能是不一样的,所以一下结果对比只能作为参考。可能是因为每次提交时测试的示例不同

1、罗马数字转整数

题目描述:

罗马数字包含以下七种字符: IVXLCDM

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II27 写做 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。

给定一个罗马数字,将其转换成整数。

示例:

输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.

解法一:直接法

思路:

1、遍历字符串,正常情况下是每个罗马字符代表的数字相加,额外判断特殊的3种情况;

2、额外判断的情况:

  • IV,IX,XL,XC,CD、CM

3、将每个罗马字符代表的整数存放在字典中;

代码:

class Solution(object):
    def romanToInt(self, s):
        """
        :type s: str
        :rtype: int
        """
        # 字典
        thisdict = {
            "I":1,
            "V":5,
            "X":10,
            "L":50,
            "C":100,
            "D":500,
            "M":1000
        }
        num=0
        i=0# 遍历字符串的指针
        while i < len(s):
            if i < len(s) and s[i] == "I":
                #判断情况IV,IX,同时需要注意字符串溢出的情况
                if i + 1 < len(s) and (s[i + 1] == "V" or s[i + 1] == "X"):
                    num = num + thisdict[s[i + 1]] - thisdict[s[i]]
                    i += 2 #如果是相减的情况,例如IX,那就已经在上一步完成了计算,就不必再对X进行循环,跳过就好
                    continue
                else:
                    # 正常情况下,直接相加
                    num = num + thisdict[s[i]]
            elif s[i] == "X":
                #判断情况XL,XC,同时需要注意字符串溢出的情况
                if i + 1 < len(s) and (s[i + 1] == "L" or s[i + 1] == "C"):
                    num = num + thisdict[s[i + 1]] - thisdict[s[i]]
                    i += 2
                    continue
                else:
                    num = num + thisdict[s[i]]
            elif s[i] == "C":
                #判断情况CD,CM,同时需要注意字符串溢出的情况
                if i + 1 < len(s) and (s[i + 1] == "D" or s[i + 1] == "M"):
                    num = num + thisdict[s[i + 1]] - thisdict[s[i]]
                    i += 2
                    continue
                else:
                    num = num + thisdict[s[i]]
            else:
                # 正常情况,直接相加
                num = num + thisdict[s[i]]
            # 循环指针下移
            i += 1
        return num

结果:

在这里插入图片描述

解法二、思路简化

思路:

1、罗马数字转整数其实只有两种情况:

  • 小的数字在右边,那就正常相加;
  • 如果小的数字出现在左边,那就是相减。

2、相减的情况其实不必列举,并在跳过那次循环,而是直接相减,结果是一样的

3、使用enumerate函数

代码:

class Solution(object):
    def romanToInt(self, s):
        """
        :type s: str
        :rtype: int
        """
        list = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
        num = 0
        for i,ch in enumerate(s):
            if i<len(s)-1 and list[ch]<list[s[i+1]]:# 数字小的在左边,因此是减去该值
                num -= list[ch]
            else:
                num += list[ch]
        return num

结果:

在这里插入图片描述

解法三、缩短时间

思路:

1、在解法二的基础上,我们发现最后一位一定是相加的

2、情况一:可保留当前位的值,当遍历到下一位的时,对比保留值与遍历位的大小关系,再确定保留值为加还是减。最后一位做加法即可。

3、情况二:往后看多一位,对比当前位与后一位的大小关系,从而确定当前位是加还是减法。当没有下一位时,做加法即可。

代码:

#情况一
class Solution:
    def romanToInt(self, s: str) -> int:
        list = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
        num = 0
        preNum = list[s[0]]# 保留前一位值
        i=1
        while i<len(s):
            nowNum = list[s[i]]
            if preNum < nowNum:# 前位值比当前位小
                num -= preNum
            else:# 前位值比当前位大
                num += preNum
            preNum = nowNum
            i+=1
        num += preNum# 最后一位,直接相加
        return num
#情况二
class Solution:
    def romanToInt(self, s: str) -> int:
        list = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
        num = 0
        i = 0 
        while i<len(s):
            if i<len(s)-1 and list[s[i]]<list[s[i+1]]:# 对比当前值和下一位的值,小于则相减
                num -= list[s[i]]
            else:
                num += list[s[i]]
            i+=1
        return num

结果:

情况一:

在这里插入图片描述

情况二:

在这里插入图片描述

这种时间相差很大的情况,我认为是情况一其实罗马字符串的每一位其实都只访问了一次,而情况二中除首尾两个字符外,都访问了两次,所以时间长。

相关知识介绍

enumerste

定义:

enumerate()在Python中是一个内置函数,简单来说该函数就是把一个可迭代对象实例(如列表、元组或字符串)变为一个带索引的enumerate对象实例返回,本质上这个enumerate也是一个可迭代对象。

用法:

enumerate(iterable, start=0)
# 参数解释:
# iterable->一个可遍历的数据对象实例
# start->索引对象实例的起始索引值  
# 默认起始索引值为0,也可以使用start参数控制。
# 示例:
list1=[1,2,3,4,5]
for i in enumerate(list1):
    print(i)
#运行结果为:(0,1)(1,2)(2,3)(3,4)(4,5)
list1=[1,2,3,4,5]
for index,i in enumerate(list1):  # 把索引和元素一起获取,索引默认从0开始
    print(i) 
#运行结果为:1 2 3 4 5
字典

定义:

字典用花括号编写,拥有键和值。

  • *词典(Dictionary)*是一个无序,可变和有索引的集合。没有重复的成员。

用法:

# 创建并打印字典
thisdict =	{
  "brand": "Porsche",
  "model": "911",
  "year": 1963
}
print(thisdict)
# 或者
thisdict = dict(brand="Porsche", model="911", year=1963)
# 请注意,关键字不是字符串字面量
# 请注意,使用了等号而不是冒号来赋值
#########################################################################################
# 访问字典
x = thisdict["model"]# 通过键名来访问字典
x = thisdict.get("model")# 通过get()函数来访问字典  结果911
#########################################################################################
# 更改特定项的值
thisdict["year"] = 2019
#########################################################################################
# 遍历字典
for x in thisdict:# for循环遍历
  print(thisdict[x])# x键,thisdict[x]值
for x in thisdict.values():# values()函数遍历x字典的值
  print(x)
for x, y in thisdict.items():# items()函数遍历键和值
  print(x, y)
#########################################################################################
# 字典长度
len(thisdict)# 要确定字典有多少项目(键值对),请使用 len() 方法。
#########################################################################################
# 检查键是否存在
if "model" in thisdict:# 要确定字典中是否存在指定的键,请使用 in 关键字:
#########################################################################################
# 添加项目
thisdict["color"] = "red"# 通过使用新的索引键并为其赋值,可以将项目添加到字典中
#########################################################################################
# 删除项目
thisdict.pop("model")# pop() 方法删除具有指定键名的项
thisdict.popitem()# popitem() 方法删除最后插入的项目(在 3.7 之前的版本中,删除随机项目)
del thisdict["model"]# del 关键字删除具有指定键名的项目
del thisdict# del 关键字也可以完全删除字典
print(thisdict) #this 会导致错误,因为 "thisdict" 不再存在。
thisdict.clear()# clear() 关键字清空字典
#########################################################################################
# 复制字典
mydict = thisdict.copy()# 使用 copy() 方法来复制字典
mydict = dict(thisdict)# 使用 dict() 方法创建字典的副本
#########################################################################################
# 嵌套字典
myfamily = {
  "child1" : {
    "name" : "Phoebe Adele",
    "year" : 2002
  },
  "child2" : {
    "name" : "Jennifer Katharine",
    "year" : 1996
  },
  "child3" : {
    "name" : "Rory John",
    "year" : 1999
  }
}
# 或者
child1 = {
  "name" : "Phoebe Adele",
  "year" : 2002
}
child2 = {
  "name" : "Jennifer Katharine",
  "year" : 1996
}
child3 = {
  "name" : "Rory John",
  "year" : 1999
}

myfamily = {
  "child1" : child1,
  "child2" : child2,
  "child3" : child3
}

2、最长公共前缀

题目描述:

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例:

输入:strs = ["flower","flow","flight"]
输出:"fl"
    
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

解法一、直接求解

思路:

1、需要注意的是这个题目是最长前缀,而不是所包含的公共子串;

2、编写函数先判断两个字符串的公共前缀,好判断,也是基础;

3、当列表为空时,输出肯定是“”

4、当列表非空时,设置一个保留暂时结果的变量pre,初始值设为strs[0]

5、从strs[1]开始遍历,判断pre和当前元素的公共前缀,并将结果作为pre的新值,直至遍历完整个列表,pre就是我们需要的结果,且一旦pre值为"",则可停止遍历。

代码:

class Solution:
    # 两个字符串的公共前缀
    def lcp(self, str1, str2):
        length = min(len(str1), len(str2))
        index = 0
        while index < length and str1[index] == str2[index]:
            index += 1
        return str1[:index]

    def longestCommonPrefix(self, strs: List[str]) -> str:
        # 列表是否为空
        if not strs:
            return ""
        pre = strs[0]
        i = 1
        while i < len(strs):
            pre = self.lcp(pre, strs[i])
            # 当前结果为"",则代表了这组数组无公共前缀,直接退出循环
            if pre == "":
                break
            i += 1
        return pre

结果:

在这里插入图片描述

解法二、利用any函数

思路:

1、以第一个字符串为依据,从左往右依次遍历所有字符串,如果字符一致,则继续,如果字符不一致,则停止遍历,结果就是该列之前的字符串;或者是当后续字符串的长度小于第一个字符串时,也是循环结束的标值。

2、或许有人问,为什么循环次数的最大值不直接设置为最短字符串的长度,但这样的话,我们需要另外的方法或者代码去获得最短字符串,不方便。

2、利用any函数来简化代码。

代码:

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs:
            print("")
        # 以第一个字符串为依据
        length = len(strs[0])
        for i in range(length):
            # for循环写在一行
            if any( i == len(strs[j]) or strs[j][i] != strs[0][i] for j in range(len(strs))):
                return strs[0][:i]
        return strs[0]

结果:

在这里插入图片描述

在leetcode官方题解中,还有利用分治和二分查找的解法,我是认为在这种题中,没有必要,而且分治法费时,感兴趣的可以去查看。

官方解答链接

相关知识介绍

列表

定义:

*列表(List)*是一种有序和可更改的集合。允许重复的成员。

列表用方括号编写。

用法:

# 创建列表
thislist = ["apple", "banana", "cherry"]
thislist = list(("apple", "banana", "cherry")) # 请注意双括号
#########################################################################################
# 访问项目
thislist[0]# 用索引号类似于C++中的数组
thislist[-1]# 最后一项
thislist[0:2]# 索引范围,第一项和第二项
thislist[:2]# 从第一项开始,一直到第2项
#########################################################################################
# 更改项目值
thislist[1] = "mango"
#########################################################################################
# 遍历列表
for x in thislist:# for循环
#########################################################################################
# 查询
if "apple" in thislist:
#########################################################################################
# 列表长度
len(thislist)
#########################################################################################
# 添加项目
thislist.append("orange")# 如需将项目添加到列表的末尾,请使用 append() 方法
thislist.insert(1, "orange")# 插入项目作为第二个位置
#########################################################################################
# 删除项目
thislist.remove("banana")# remove() 方法删除指定的项目
thislist.pop()# pop() 方法删除指定的索引(如果未指定索引,则删除最后一项)
del thislist[0]# del 关键字删除指定的索引
del thislist# del 关键字也能完整地删除列表
thislist.clear()# clear() 方法清空列表
#########################################################################################
# 复制列表
mylist = thislist.copy()
mylist = list(thislist)
#########################################################################################
# 合并列表
list1 = ["a", "b" , "c"]
list2 = [1, 2, 3]
list3 = list1 + list2
list1.extend(list2)# 使用 extend() 方法将 list2 添加到 list1 的末尾
字符串

定义:

python 中的字符串字变量由单引号或双引号括起。

'hello' 等同于 "hello"

用法:

# 多行字符串
# 使用三个引号将多行字符串赋值给变量
a = """Python is a widely used general-purpose, high level programming language. 
It was initially designed by Guido van Rossum in 1991 
and developed by Python Software Foundation. 
It was mainly developed for emphasis on code readability, 
and its syntax allows programmers to express concepts in fewer lines of code."""
# 裁剪
a[2:5]# 获取从位置 2 到位置 5(不包括)的字符
# 长度
len(a)
# 字符串方法
strip() 方法删除开头和结尾的空白字符
lower() 返回小写的字符串
upper() 方法返回大写的字符串
replace() 用另一段字符串来替换字符串 # a.replace("World", "Kitty")
split() 方法在找到分隔符的实例时将字符串拆分为子字符串 # a.split(",")  returns ['Hello', ' World!']
innot in:如需检查字符串中是否存在特定短语或字符,我们可以使用 innot in 关键字
+:如需串联或组合两个字符串,您可以使用 + 运算符
format() 组合字符串和数字 # txt.format(age)
format() 方法接受不限数量的参数,并放在各自的占位符中
    quantity = 3
    itemno = 567
    price = 49.95
    myorder = "I want {} pieces of item {} for {} dollars."
    print(myorder.format(quantity, itemno, price))
	# I want 5 pieces of item 789 for 24.36 dollars.
    quantity = 3
    itemno = 567
    price = 49.95
    myorder = "I want to pay {2} dollars for {0} pieces of item {1}."
    print(myorder.format(quantity, itemno, price))
    # I want to pay 24.36 dollars for 5 pieces of item 789.
any、all
any:

定义:

any函数用来判断一个可迭代对象中是否至少有一个值为True,如果是则返回True,否则返回False

用法:

print(any([1, 2, 3])) # True
print(any(['', 0, False])) # False
print(any(['', 1, False])) # True
all:

定义:

all()是判断可迭代对象中每一个元素是否都是True,是则返回True,否则返回False。也就是说只要有一个是False则返回False。

注意:

它们对于空的迭代对象的返回结果是不一样的:

print(any([]))# False
print(all([]))# True
写在一行的for循环

例子:

a=[True for j in range(5)]
print(a)
#[True, True, True, True, True]

a=[i for i in range(0,5) if i>2]
print(a)
#[3, 4]

if any(i == len(strs[j]) or strs[j][i] != c for j in range(1, count)):
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值