树的旋转(当平衡因子不在-1,1,0中)
红黑树
遍历每个位置的元素,与相邻的数字作比较,不断交换位置。
def main(nums):
n=len(nums)
for i in range(n):
for j in range(0,n-i-1):
if nums[j]>nums[j+1]:
nums[j],nums[j+1]=nums[j+1],nums[j]
print(nums)
每次遍历都找到当前最小值的下标,按照顺序依次放到列表对应位置
def main(nums):
n=len(nums)
for i in range(n):
cur_min = i
for j in range(i+1,n):
if nums[j]<nums[cur_min]:
cur_min=j
nums[i],nums[cur_min]=nums[cur_min],nums[i]
print(nums)
def main(nums):
n=len(nums)
for i in range(1,n):
j=i
while j>0:
if nums[j]<nums[j-1]:
nums[j],nums[j-1]=nums[j-1],nums[j]
j-=1
else:
break
print(nums)
def main(list):
n=len(list)
gap=n//2
while gap>0:
for i in range(gap,n):
j=i
while j>=gap:
if list[j-gap]>list[j]:
list[j],list[j-gap]=list[j-gap],list[j]
j-=gap
else:
break
gap//=2
return list
def quick_sort(nums,left,right):
if left>=right:
return
mid=nums[left]
low=left
high=right
while low<high:
while nums[high]>=mid and low<high:
high-=1
nums[low]=nums[high]
while nums[low]<=mid and low < high:
low+=1
nums[high]=nums[low]
nums[low]=mid
quick_sort(nums,left,low)
quick_sort(nums,low+1,right)
def merge_sort(list):
n=len(list)
mid=n//2
if n<=1:
return list
left_list=merge_sort(list[:mid])
right_list=merge_sort(list[mid:])
left_cur=0
right_cur=0
result=[]
while left_cur<len(left_list) and right_cur<len(right_list):
if left_list[left_cur]<right_list[right_cur]:
result.append(left_list[left_cur])
left_cur+=1
else:
result.append(right_list[right_cur])
right_cur+=1
result.extend(left_list[left_cur:])
result.extend(right_list[right_cur:])
return result
题目描述
解题思路
将arr1中的值和对应出现的位置存储在字典中,建立一个cmp函数如果当前x在rank中返回0,rank[i],如果不在返回(1,x),根据这个key对arr1进行排序
代码实现
class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
def cmp(x):
return (0,rank[x]) if x in rank else(1,x)
rank={k:i for i,k in enumerate(arr2)}
arr1.sort(key=cmp)
return arr1
之前使用的是哈希表来存储s和t,这里使用排序对列表化字符串进行排序然后再变成字符串进行比较。
代码实现
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
def str2list(words):
li=list(words)
li.sort()
return "".join(li)
return str2list(s)==str2list(t)
题目描述
解题思路
这道题其实没什么难度,主要是返回topk的总数,这里的做法参考了题解,即把字典中的value拿出来排序存储于列表,再统计k个的组合。也可以直接对字典进行排序然后遍历k次。感觉应该都差不多。如果用heap直接压堆可能会更快一点。
代码实现
class Leaderboard:
def __init__(self):
#建立一个字典
self.dic=collections.defaultdict(int)
def addScore(self, playerId: int, score: int) -> None:
self.dic[playerId]+=score
def top(self, K: int) -> int:
#先要根据value进行排序
dic1=sorted([v for v in self.dic.values()],reverse=True)
return sum(dic1[:K])
def reset(self, playerId: int) -> None:
self.dic[playerId]=0
题目描述
解题思路
首先将区间根据区间起始位置进行排序,然后遍历每个区间,维护一个列表,如果当前列表没有或者当前区间的起始位置大于列表中最后一个区间的终止位置,那么就无需合并,直接添加。如果当前区间的起始位置小于了上个区间的终止位置,需要合并。将列表最后一个区间的终止位置改成当前区间的终止位置。
代码实现
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
#先根据起始位置进行排序
intervals.sort(key=lambda x:x[0])
res=[]
#遍历每个区间
for interval in intervals:
#如果当前已经加入res的区间的结束位置小于当前interval的起始位置,直接添加即可
if not res or res[-1][-1]<interval[0]:
res.append(interval)
#如果当前interval的起始值小于merge中存储interval的终止位置,那要将它们合并
else:
res[-1][-1]=max(res[-1][-1],interval[1])
return res
题目描述
代码实现
class Solution:
def reversePairs(self, nums: List[int]) -> int:
tmp=[0]*len(nums)
#归并排序
def merge_sort(l,r):
#终止条件:
if l>=r:
return 0
#递归的mid
mid=(l+r)//2
#左右分别递归
res=merge_sort(l,mid)+merge_sort(mid+1,r)
#合并阶段
#定义两个指针
i,j=l,mid+1
#找到当前列表的值域
tmp[l:r+1]=nums[l:r+1]
#遍历tmp
for k in range(l,r+1):
#如果左指针已经走完,那就不算添加右边的值
if i==mid+1:
nums[k]=tmp[j]
j+=1
#如果右指针已经走完或者当前左指针的值小于右指针
elif j==r+1 or tmp[i]<=tmp[j]:
nums[k]=tmp[i]
i+=1
#如果当前左指针大于右指针,那在添加右指针的同时还要统计逆序对的数量
else:
nums[k]=tmp[j]
j+=1
#逆序对的数量为左边列表个数减去当前位置i
res+=mid-i+1
return res
return merge_sort(0,len(nums)-1)
题目描述
解题思路
这道题讲道理花费了很长时间,想从上一题直接添加一个判断是否两倍的条件来输出,发现不是很对,因为对于2,3;1这两个子序列,如果在比较2和1不满足两倍以上这个条件后,1就会被加入列表,j的下标也会移动就无法判断3,1了。想了半天发现还是在比较外再添加两个元素,再遍历一遍去添加。
代码实现
class Solution:
def reversePairs(self, nums: List[int]) -> int:
tmp=[0]*len(nums)
#归并排序
def merge_sort(l,r):
#终止条件
if l>=r:
return 0
#求出mid的位置
mid=(l+r)//2
res=merge_sort(l,mid)+merge_sort(mid+1,r)
#合并阶段,定义两个指针,指向两个子列表的开头
i,j=l,mid+1
#找到当前左右子列表的值域
tmp[l:r+1]=nums[l:r+1]
#开始遍历
for k in range(l,r+1):
#如果左指针走完,就把每个位置对应右指针
if i==mid+1:
nums[k]=tmp[j]
j+=1
#如果右指针走完或者当前左指针的值小于右指针的值
elif j==r+1 or tmp[i]<=tmp[j]:
nums[k]=tmp[i]
i+=1
#如果当前左指针的值大于右指针的值
else:
nums[k]=tmp[j]
j+=1
ti, tj = l, mid + 1
while ti <= mid and tj <= r:
if tmp[ti] <= 2 * tmp[tj]:
ti += 1
else:
res+= mid - ti + 1
tj += 1
return res
return merge_sort(0,len(nums)-1)
这道题超级简单,就不做描述了
class Solution:
def toLowerCase(self, str: str) -> str:
#建立一个空字符串
word=""
#遍历str
for char in str:
word+=char.lower()
return word
第一遍提交报错是因为没有考虑多个空格的情况。所以通过判断切割后的字列表的长度判断是否全为空格。
class Solution:
def lengthOfLastWord(self, s: str) -> int:
#将字符串分隔开
word_list=s.split()
#如果为空
if len(word_list)==0:
return 0
return len(word_list[-1])
题目描述
代码实现
class Solution:
def numJewelsInStones(self, jewels: str, stones: str) -> int:
#将宝石类型列表化
list_j=list(jewels)
#统计变量
count=0
#遍历stones
for stone in stones:
if stone in list_j:
count+=1
return count
解题思路
代码实现
class Solution:
def firstUniqChar(self, s: str) -> str:
if len(s)==0:
return " "
#先统计s的每个词出现的次数
dic=collections.defaultdict(list)
i=0
for char in s:
#把每个字母出现在s的位置作为value
dic[char].append(i)
i+=1
#遍历哈希表
for k,v in dic.items():
#第一次出现字母对应的位置只有一个的时候,返回其值
if len(v)==1:
return k
#如果遍历完都没出现
return " "
题目描述
解题思路
使用re.findall(str)匹配正则,正则表达式:字符串形式,以正负号开头的数字(d)
上下界都要有规定。
代码实现
import re
class Solution:
def myAtoi(self, str: str) -> int:
INT_MAX = 2**31-1
INT_MIN = -2**31
str = str.lstrip() #清除左边多余的空格
num_re = re.compile(r'^[\+\-]?\d+') #设置正则规则
num = num_re.findall(str) #查找匹配的内容
num = int(*num) #由于返回的是个列表,解包并且转换成整数
return max(min(num,INT_MAX),INT_MIN) #返回值
不使用正则的方法:
class Solution:
def myAtoi(self, s: str) -> int:
#判断是否为空
#去除空格
slices=list(s.strip())
if len(slices)==0:return 0
#对于正负号的处理
signal= -1 if slices[0]=="-" else 1
#删除正负号
if slices[0] in ["+","-"]: del slices[0]
res,i=0,0
#遍历字符串且只考虑是数字的字符
while i <len(slices) and slices[i].isdigit():
res=res*10+ord(slices[i])-ord("0")
i+=1
#返回
return max(-2**31,min(signal*res,2**31-1))
题目描述
分治代码
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
#分治的方法
def dfs(start,end):
#终止条件
if start==end:return strs[start]
#开始递归
mid=(start+end)//2
left=dfs(start,mid)
right=dfs(mid+1,end)
#对比两个词的长度取最小
min_len=min(len(left),len(right))
#遍历这个最小长度
for i in range(min_len):
if left[i]!=right[i]:
return left[:i]
#如果一直相同,就返回最短的词
return left[:min_len]
return "" if len(strs)==0 else dfs(0,len(strs)-1)
纵向比较代码
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
#特殊情况
if not strs:
return ""
#拿出一个字作为标准,因为是公共前缀,所以哪个都可以
length=len(strs[0])
#统计有多少个词
count=len(strs)
#遍历标准词的每一个位置
for i in range(length):
#如果i到达了其他词的最大长度或者当前标准词的位置和其他词的相同位置不同,结束
if any(i==len(strs[j]) or strs[j][i]!=strs[0][i] for j in range(1,count)):
return strs[0][:i]
#如果完全相同
return strs[0]
题目描述
代码实现
这种题是真实存在的么,。。。。。
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
return s.reverse()
题目描述
解题思路
其实这道题作为简单题唯一的一点小的难点在于不足2k个的时候怎么处理,在下面的代码中可以看到,我们是隔2k个一取得,当最后不足k个的时候依然进行了反转,当在k和2k之间时,大于k得就没有反转,满足题意。
代码实现
class Solution:
def reverseStr(self, s: str, k: int) -> str:
n=len(s)
li=list(s)
for i in range(0,n,k*2):
#将前k个进行交换
li[i:i+k]=s[i:i+k][::-1]
return "".join(li)
题目描述
解题思路
代码实现
class Solution:
def reverseWords(self, s: str) -> str:
#先将单词取出储存于列表
word_list=s.split()
#将列表反转
word_list.reverse()
#输出
return " ".join(word_list)
题目描述
解题思路
没看题解,不知道还有没有更好的方法。步骤:
代码实现
class Solution:
def reverseWords(self, s: str) -> str:
res=[]
#切片
word_list=[list(word) for word in s.split()]
for word in word_list:
word.reverse()
res.append("".join(word))
return " ".join(res)
题目描述
解题思路
感觉自己的代码写的真的很繁琐。。。。
代码实现
class Solution:
def reverseOnlyLetters(self, S: str) -> str:
#先把S中的纯字母倒叙拿出
char_list=[char for char in S if char.isalpha()]
#翻转一下
char_list.reverse()
#遍历S,把char为纯字母的地方插入char_list
i,j=0,0
pre_list=list(S)
while i < len(S):
if S[i].isalpha():
pre_list[i]=char_list[j]
i+=1
j+=1
else:
i+=1
return "".join(pre_list)
参考了题解,直接用栈取存储需要反转的字母,这样不需要要反转只要每次pop就可以,真的妙极了!!!!!!!!!
class Solution(object):
def reverseOnlyLetters(self, S):
letters = [c for c in S if c.isalpha()]
ans = []
for c in S:
if c.isalpha():
ans.append(letters.pop())
else:
ans.append(c)
return "".join(ans)
解题思路
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
#排序
li1=list(s)
li2=list(t)
li1.sort()
li2.sort()
return li1==li2
写过好多次了,不解释了,哈希表用起来,返回list of list
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
#建立字典
dic=collections.defaultdict(list)
#遍历单词
for word in strs:
key="".join(sorted(word))
dic[key].append(word)
return [ v for k,v in dic.items()]
题目描述
解题思路
规定两个个p和s得长度为26得列表存储它们对应的词,第一次先查看s得前m个字符(m为p的长度),判断一下他们是否相同,然后在遍历s的过程中不算的对s_cnt进行加减,新位置的字母对应的位置相加,原来位置的字母在s_cnt得位置减掉,当s_cnt和p_cnt相等时,代表当前为字母异位词,添加当前位置的第一个索引i-(m-1)到res中。
代码实现
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
n, m, res = len(s), len(p), []
if n < m: return res
p_cnt = [0] * 26
s_cnt = [0] * 26
for i in range(m):
p_cnt[ord(p[i]) - ord('a')] += 1
s_cnt[ord(s[i]) - ord('a')] += 1
if s_cnt == p_cnt:
res.append(0)
for i in range(m, n):
s_cnt[ord(s[i - m]) - ord('a')] -= 1
s_cnt[ord(s[i]) - ord('a')] += 1
if s_cnt == p_cnt:
res.append(i - m + 1)
return res
代码实现
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
#特殊条件:text1或者text2有一个不存在
if not text1 or not text2:
return 0
m,n=len(text1),len(text2)
#建立dp
dp=[[0]*(n+1) for _ in range(m+1)]
#开始遍历
for i in range(1,m+1):
for j in range(1,n+1):
#如果当前字符相同
if text1[i-1]==text2[j-1]:
dp[i][j]=1+dp[i-1][j-1]
#如果不同,对比i,j-1和i-1,j得更大的
else:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
return dp[-1][-1]
题目描述
解题思路
也可以直接把第二步变成压栈的形式然后pop
代码实现
class Solution:
def isPalindrome(self, s: str) -> bool:
n=len(s)
#先把数字和字母添加到列表中
word_list=[c.lower() for c in s if c.isdigit() or c.isalpha()]
#定义双指针起始位置
i,j=0,len(word_list)-1
while i < j:
if word_list[i]==word_list[j]:
i+=1
j-=1
else:
return False
return True
题目描述
解题思路
一开始的做法是因为只删除一次,所以先返回所有的结果,再判断这些结果是否有一个是回文串,但时间复杂度太高了。下面的做法是,因为只允许删除一次,所以当左右指针移动的过程中遇到不相等的时候,删除low或者high的其中一个,然后用一层递归,去判断删除后的是不是。
代码实现
class Solution:
def validPalindrome(self, s: str) -> bool:
def valids(left,right):
while left<right:
if s[left]==s[right]:
left+=1
right-=1
else:
return False
return True
#定位左右指针
low,high=0,len(s)-1
#循环
while low<high:
if s[low]==s[high]:
#直接移动左右指针
low+=1
high-=1
else:
#删除当前low或者high
return valids(low+1,high) or valids(low,high-1)
#如果遍历完都是相同得
return True
题目描述
解题思路
中心扩展法或者动态规划均可
代码实现
class Solution:
def expandAroundCenter(self, s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return left + 1, right - 1
def longestPalindrome(self, s: str) -> str:
start, end = 0, 0
for i in range(len(s)):
left1, right1 = self.expandAroundCenter(s, i, i)
left2, right2 = self.expandAroundCenter(s, i, i + 1)
if right1 - left1 > end - start:
start, end = left1, right1
if right2 - left2 > end - start:
start, end = left2, right2
return s[start: end + 1]
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
dp = [[False] * n for _ in range(n)]
ans = ""
# 枚举子串的长度 l+1
for l in range(n):
# 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
for i in range(n):
j = i + l
if j >= len(s):
break
if l == 0:
dp[i][j] = True
elif l == 1:
dp[i][j] = (s[i] == s[j])
else:
dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
if dp[i][j] and l + 1 > len(ans):
ans = s[i:j+1]
return ans
写过好多遍了,滚瓜烂熟,直接上代码
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m,n=len(word1),len(word2)
#建立dp
dp=[[0]*(n+1) for _ in range(m+1)]
#当word1为空时
for i in range(n+1):
dp[0][i]=i
#当word2为空时,
for j in range(m+1):
dp[j][0]=j
#开始遍历
for i in range(1,m+1):
for j in range(1,n+1):
#如果当前相同
if word1[i-1]==word2[j-1]:
dp[i][j]=dp[i-1][j-1]
else:
dp[i][j]=min(dp[i-1][j-1],
dp[i-1][j],
dp[i][j-1])+1
return dp[-1][-1]
题目描述
解题思路
对于当前不是 “ * ” 的就只匹配当前对应位置的i和j,如果是 “ * ”,就匹配i和j-2,因为j-1可以选择不匹配。如果是.就直接返回true即可,不需要对比。
代码实现
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m, n = len(s), len(p)
def matches(i: int, j: int) -> bool:
if i == 0:
return False
if p[j - 1] == '.':
return True
return s[i - 1] == p[j - 1]
f = [[False] * (n + 1) for _ in range(m + 1)]
f[0][0] = True
for i in range(m + 1):
for j in range(1, n + 1):
if p[j - 1] == '*':
f[i][j] |= f[i][j - 2]
if matches(i, j - 1):
f[i][j] |= f[i - 1][j]
else:
if matches(i, j):
f[i][j] |= f[i - 1][j - 1]
return f[m][n]
题目描述
代码实现
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m,n=len(s),len(p)
#建立dp,当p为空时一定是false
dp=[[False]*(n+1) for _ in range(m+1)]
dp[0][0]=True
#当s为空,p不为空时,要看p对应的*
for i in range(1,n+1):
if p[i-1]=="*":
dp[0][i]=True
else:
break
#开始循环
for i in range(1,m+1):
for j in range(1,n+1):
#当j为*号时
if p[j-1]=="*":
dp[i][j]=dp[i][j-1]|dp[i-1][j]
elif p[j-1]=="?" or s[i-1]==p[j-1]:
dp[i][j]=dp[i-1][j-1]
return dp[-1][-1]
再写的时候觉得比较需要思考的是即使当si和tj想同时,可以匹配也可以不匹配,因为没准i后面的还可以匹配到j,所以是两种情况加和的关系。
代码实现
class Solution:
def numDistinct(self, s: str, t: str) -> int:
#统计两个字符串的长度
m,n=len(s),len(t)
#以t为子串,如果t比s长,不符合题意
if m<n:
return 0
#建立储存的状态矩阵
dp=[[0]*(n+1) for _ in range(m+1)]
#初始化,如果n=0,那么它可以使s的任何子串
for i in range(m+1):
dp[i][n]=1
#如果m=0,没有字串
#开始遍历
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
#如果当前字母匹配
if s[i]==t[j]:
#那么有可能是从s+1,j+1转移,也可能是s+1,j转移
dp[i][j]=dp[i+1][j+1]+dp[i+1][j]
else:
#如果不相等,只能考虑s+1,j
dp[i][j]=dp[i+1][j]
return dp[0][0]