56. 合并区间
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
if not intervals:
return intervals
intervals=sorted(intervals,key=lambda x:(x[0],x[1]))
res=[]
res.append(intervals[0])
for i in range(1,len(intervals)):
if intervals[i][0]>res[-1][1]:
res.append(intervals[i])
else:
left=min(res[-1][0],intervals[i][0])
right=max(res[-1][1],intervals[i][1])
res.pop()
res.append([left,right])
return res
986. 区间列表的交集
假设拥有最小末端点的区间是 A[0],
在数组 B 的区间中, A[0] 只可能与数组 B 中的至多一个区间相交。(如果 B 中存在两个区间均与 A[0] 相交,那么它们将共同包含 A[0] 的末端点,但是 B 中的区间应该是不相交的,所以存在矛盾)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
例如 如果 A[0] 拥有最小的末端点,那么它只可能与 B[0] 相交。然后我们就可以删除区间 A[0],因为它不能与其他任何区间再相交了。
相似的,如果 B[0] 拥有最小的末端点,那么它只可能与区间 A[0] 相交,然后我们就可以将 B[0] 删除,因为它无法再与其他区间相交了。
我们用两个指针 i 与 j 来模拟完成删除 A[0] 或 B[0] 的操作
class Solution:
def intervalIntersection(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
res=[]
i,j=0,0
while i<len(A) and j<len(B):
left=max(A[i][0],B[j][0])
right=min(A[i][1],B[j][1])
if left<=right:
res.append([left,right])
if A[i][1]<B[j][1]:
i+=1
else:
j+=1
return res
385. 迷你语法分析器
#class NestedInteger:
# def __init__(self, value=None):
# """
# If value is not specified, initializes an empty list.
# Otherwise initializes a single integer equal to value.
# """
# def add(self, elem):
# """
# Set this NestedInteger to hold a nested list and adds a nested integer elem to it.
# :rtype void
# """
class Solution:
def deserialize(self, s: str) -> NestedInteger:
if s[0]!='[':
return NestedInteger(int(s))
num,sign,stack=0,1,[]
is_num=False
for c in s:
if c.isdigit():
#计算十进制数字
num=num*10+int(c)
is_num=True
elif c=='-':
sign=-1
elif c=='[':
# 栈append一个空的NestedInteger对象
stack.append(NestedInteger())
elif c==']' or c==',':
if is_num:
cur_list=stack.pop()
cur_list.add(NestedInteger(sign*num))
stack.append(cur_list)
num,sign,is_num=0,1,False
#嵌套列表
if c==']' and len(stack)>1:
cur_list=stack.pop()
#加到上一个
stack[-1].add(cur_list)
return stack[0]
71. 简化路径
把当前目录压入栈中,遇到…弹出栈顶,最后返回栈中元素.
class Solution:
def simplifyPath(self, path: str) -> str:
path=path.split('/')
res=[]
for item in path:
#返回上一级则弹出栈顶
if item=='..':
if res:
res.pop()
elif item and item!='.':
res.append(item)
return '/'+'/'.join(res)
848. 字母移位
因为对第 i 个字母及后面字母的移位都会导致第 i 个字母移位,所以第 i 个字母共移位 shifts[i] + shifts[i+1] + … + shifts[shifts.length - 1] 次。
假设第 i 个字母移位 X 次,那么第 i + 1 个字母移位 X - shifts[i] 次。
当 i 增加时,令 X -= shifts[i] 计算下一个字母的移位次数。
class Solution:
def shiftingLetters(self, S: str, shifts: List[int]) -> str:
#对第i个字母及其后面字母的移位都会影响第I个字母移位,后面每个字母移位都比当前字母移位少shifts[i]
x=sum(shifts)%26
res=[]
for i,c in enumerate(S):
idx=ord(c)-ord('a')
res.append(chr(ord('a')+(idx+x)%26))
#下一个字母的移位次数
x=(x-shifts[i])%26
return ''.join(res)
58. 最后一个单词的长度
class Solution:
def lengthOfLastWord(self, s: str) -> int:
return len(s.strip(' ').split(' ')[-1])
class Solution:
def lengthOfLastWord(self, s: str) -> int:
if not s:
return 0
count = 0
flag = 0
for i in s[::-1]:
#最后面的空格,后面没有数字
if i is " " and flag == 0:
continue
if i is not " ":
count += 1
flag = 1
else:
break
return count
816. 模糊坐标
itertools.product:类似于求多个可迭代对象的笛卡尔积
主要是判断特殊情况
#1:在n个数中间加逗号
#2:给第一步产生的字符串加小数点(并判断合法),下面是判断规则
if S == “”: return []
if S == “0”: return [S]
if S == “0XXX0”: return []
if S == “0XXX”: return [“0.XXX”]
if S == “XXX0”: return [S]
return [S, “X.XXX”, “XX.XX”, “XXX.X”…]
class Solution:
def ambiguousCoordinates(self, S: str) -> List[str]:
#去掉括号
S=S[1:-1]
def f(s):
#首尾都为0,字符串不符合要求
if not s or(len(s)>1 and s[0]=='0' and s[-1]=='0'):
return []
if s=='0':
return [s[0]]
# 第一位为0,小数点只能加到0后面
if len(s)>1 and s[0]=='0':
return [s[0]+'.'+s[1:]]
#最后一位为0,且长度大于1,只能返回整个字符串,无法加小数点
if len(s)>1 and s[-1]=='0':
return [s]
return [s]+ [s[:i]+'.'+s[i:] for i in range(1,len(s))]
#分割数字
res=[]
#可以加,的地方
for i in range(1,len(S)):
#前后组合
for x,y in itertools.product(f(S[:i]),f(S[i:])):
res.append('(%s, %s)'%(x,y))
return res
1130. 叶值的最小代价生成树
中序遍历就决定了arr数组(0…n-1)里的第k位元素的所有左边元素(包括它自己)都在左子树里,而其右边元素都在右子树里,而此时左右两边子树分别选出最大值的乘积就是此时的根,也就是题目中说的非叶节点
中序遍历,叶子节点从左到右,每个点都会发起组合,组合可能是和左边的也可能是和右边的组合,同时小的那个元素就不再需要了,我们只看大的那个元素可能还会和别的值相乘。所以大的元素保存下来
每个非叶结点都是左右子树叶节点中最大值的乘积,所以每次只消掉小的数,每次用相邻的两个较小的叶节点合成中间节点,最终可以得到最小代价生成树。
用单调递减栈保存
如果栈不空,剩下的叶子节点要乘起来
时间复杂度为 O(N)
class Solution:
def mctFromLeafValues(self, arr: List[int]) -> int:
stack=[float('inf')]
res=0
for i in arr:
#单调递减栈,消除小的元素
while stack and stack[-1]<=i:
mid=stack.pop()
res+=mid*(min(stack[-1],i))
stack.append(i)
#因为有哨兵元素,长度等于2的时候弹出
while len(stack)>2:
#栈不为空,要把叶子结点相乘获得根
res+=stack.pop()*stack[-1]
return res
682. 棒球比赛
class Solution:
def calPoints(self, ops: List[str]) -> int:
stack=[]
for c in ops:
#负数对isdigit是False
if (c.startswith('-') and c[1:] or c).isdigit():
stack.append(int(c))
elif stack and c=='C':
stack.pop()
elif stack and c=='D':
stack.append(2*stack[-1])
elif len(stack)>1 and c=='+':
stack.append(stack[-1]+stack[-2])
return sum(stack)
856. 括号的分数
我们用一个栈来维护当前所在的深度,以及每一层深度的得分。当我们遇到一个左括号 ( 时,我们将深度加一,并且新的深度的得分置为 0。当我们遇到一个右括号 ) 时,我们将当前深度的得分乘二并加到上一层的深度。这里有一种例外情况,如果遇到的是 (),那么只将得分加一。
class Solution:
def scoreOfParentheses(self, S: str) -> int:
stack=[0]
for i in S:
if i=='(':
stack.append(0)
elif i==')':
v=stack.pop()
stack[-1]+=max(2*v,1)
return stack[0]
第二种写法:
https://leetcode-cn.com/problems/score-of-parentheses/solution/kan-bu-dong-bie-ren-de-ti-jie-zi-ji-you-xie-liao-y/
class Solution:
def scoreOfParentheses(self, S: str) -> int:
stack=[]
for i in S:
if i=='(':
stack.append(i)
elif i==')':
#() 得1分
if stack[-1]=='(':
stack.pop()
stack.append(1)
#(1,2。。):(1+2)*2
elif stack[-1]!='(':
tmp=0
while stack[-1]!='(':
a=stack.pop()
tmp+=a
stack.pop()
stack.append(2*tmp)
return sum(stack)