题4(困难):
思路:
找两数组中位数,这个看起来简单,顺手反应就是数第(m+n)/2个,这个难在要求时间复杂度为log(m+n),所以不能这样搞,我的思路是:每次切割长度为较小长度的一半,然后比较哪个对中位数没有影响就切哪个
python代码
python
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
med=None
while 1:
if len(nums1) == 0:
med2 = nums2[(len(nums2)) // 2] if len(nums2) % 2 == 1 else (nums2[len(nums2) // 2 - 1] + nums2[
len(nums2) // 2]) / 2
med = med2
break
if len(nums2) == 0:
med1 = nums1[(len(nums1)) // 2] if len(nums1) % 2 == 1 else (nums1[len(nums1) // 2 - 1] + nums1[
len(nums1) // 2]) / 2
med = med1
break
if (len(nums1) + len(nums2) <= 2):
med = ((nums1[0] if len(nums1) > 0 else 0) + (nums2[0] if len(nums2) > 0 else 0)) / (len(nums1) + len(nums2))
break
cutlen=len(nums1)//2 if len(nums1)<=len(nums2) else len(nums2)//2
if(cutlen<1):
cutlen=1
if nums1[cutlen-1]<nums2[cutlen-1]:
nums1=nums1[cutlen:]
else:
nums2=nums2[cutlen:]
if len(nums1)!=0 and (len(nums2)==0 or nums1[len(nums1)-cutlen]>nums2[len(nums2)-cutlen]) :
nums1=nums1[:len(nums1)-cutlen]
else:
nums2=nums2[:len(nums2)-cutlen]
return med
题10(困难):
思路:
我只能说我不是理解正则,毕竟爬虫我都不管啥,直接.*?,导致我理解错了题意思,我当时以为*是可以匹配任意了,然后写一晚上都没成功,看评论才理解意思,其实理解了写起来就清晰了,采用的方法是递归,时间比较消耗,所以要预处理一下,不然超时
python代码:
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if p=='':
return s==''
if s=='':
if len(p)!=2 and p[1]!='*':
return False
if len(p)==2 and p[1]=='*':
return True
i=0
#预处理,
while 1:
if p[i]=='*':
if i+2<len(p) and p[i+2]=='*':
if p[i-1]==p[i+1]:
p=p[:i+1]+p[i+3:]
i+=1
if i>=len(p):
break
s_p=0
p_p=0
while 1:
if s_p>=len(s) and p_p>=len(p):
return True
if p_p>=len(p):
return False
if p_p+1<=len(p)-1 and p[p_p+1]=='*':
for i in range(s_p,len(s)):
if s[i]!=p[p_p] and p[p_p]!='.':
break
else:
if self.isMatch(s[i:],p[p_p]+p[p_p+2:]):
return True
p_p+=2
else:
if s_p>=len(s):
return False
if p[p_p]==s[s_p] or p[p_p]=='.':
p_p+=1
s_p+=1
else:
return False
写得很气,所以赶工,注释都没有,再看的话又烦,感觉屎山一样,做的最久的一次,写了3个版本的代码
题23(困难):
分析:
真不配这个难度,因为这个直接暴力求解都行,和第一个(21题)没区别,python没有指针,初始化感觉挺麻烦,你看了我代码就发现,我的head第一个往往都是空,返回head.next,因为我不想浪费空间重新拿创建,所以我更倾向于用它给的空间,这样看起来说实话有点别扭。但是第一个的赋值要在我们弄或者建立索引单独弄也别扭,以后再补上c++的吧
python代码
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
p=ListNode()
res=p
if len(lists)==0:
return None
while 1:
k=0
for i in range(len(lists)):
if lists[k]==None:
k=i
if lists[i] and lists[i].val<lists[k].val:
k=i
if lists[k]==None:
break
print(k)
p.next=lists[k]
p=p.next
lists[k]=lists[k].next
return res.next if res.next else None
题25(困难):
分析:
有意思,但是难度不配困难。思路其实挺清晰,我们知道链表时候插入数据但是不适合查找数据,本题因为要交换k个数据就说明一定要查找数据,因为你不知道要找第几个,而是要传入k,这个时候肯定要寻求数组的帮助,我们定义一个长度为k的数组,每次拿k个,这样我们要哪个就方便了
python代码:
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
res=ListNode(0,head)
p=res
while 1:
node_list=[]
flag=1
q=p
for i in range(k):
if q.next==None:
flag=0
break
else:
q=q.next
node_list.append(q)
last_node=q.next
if flag:
for i in range(k):
p.next=node_list[k-i-1]
p=p.next
p.next=last_node
else:
break
return res.next
题30(困难):
分析:
说实话,我第一反应是找所有words的位置来减少时间复杂度,结果来一个
最后迫不得已暴力求解了
python代码:
python
import re
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
word_len=len(words)
word_size=len(words[0])
if word_len*word_size>len(s) or word_len==0:
return []
res=[]
def in_word(word,words):
w1=[word[word_size*i:word_size*(i+1)] for i in range(word_len)]
w1.sort()
w2=sorted(words)
if w1==w2:
return 1
else:
return 0
for i in range(len(s)-word_size*word_len+1):
word=s[i:i+word_size*word_len]
if in_word(word,words):
res.append(i)
return res
题32(困难):
分析:
其实就是遍历一遍,我的思路就是每一项为前两项的和+2,且将前两项去了
python代码:
python
class Solution:
def longestValidParentheses(self, s: str) -> int:
tmp_list=[]
s_stack=[]
for i in s:
if i=="(":
s_stack.append(i)
tmp_list.append(0)
else:
if len(s_stack)!=0 and s_stack[-1]=='(':
s_stack.pop()
if tmp_list!=[]:
a1=tmp_list.pop()
else:
a1=0
if tmp_list!=[]:
a2=tmp_list.pop()
else:
a2=0
next=a1+a2+2
tmp_list.append(next)
else:
tmp_list.append(0)
return max(tmp_list) if tmp_list!= [] else 0
题37(困难):
python代码:
python
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
def Conflict(board):
def isValidUnit(unit):
# 检查一个行、列或宫格是否有效
seen = set()
for num in unit:
if num != '.':
if num in seen:
return False
seen.add(num)
return True
for i in range(9):
if not isValidUnit(board[i]):
return False
for j in range(9):
column = [board[i][j] for i in range(9)]
if not isValidUnit(column):
return False
for i in range(0, 9, 3):
for j in range(0, 9, 3):
square = [board[x][y] for x in range(i, i + 3) for y in range(j, j + 3)]
if not isValidUnit(square):
return False
return True
def run(n):
for i in range(n,81):
x = i // 9
y = i % 9
if board[x][y]!='.':
continue
for j in range(1,10):
board[x][y]=str(j)
if Conflict(board) and run(i+1):
return True
board[x][y]='.'
return False
return True
run(0)
题41(困难):
分析:
这题我开始没什么思路,记录第一个逼我看评论的,后面看评论的方法,真解,借助一个数组,将nums对应数字放对应位置,然后如果下标和数字不同就返回
python代码(基础版):
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n_list=[-1 for i in range(len(nums))]
#根据提示O(2n)==O(n),我们知道了一定要循环两次,于是就有放回位置上去
for i in range(len(nums)):
if nums[i]>0 and nums[i]<=len(nums):
n_list[nums[i]-1]=nums[i]
for i in range(len(n_list)):
if n_list[i]==-1:
return i+1
return len(nums)+1
python代码(进阶):
python
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n_len=len(nums)
#不能用额外空间,那就改变它的值,且时间复杂度为O(n),
#首先使用双指针法,将等于len和小于0的值去了或者放到另一边
left=0
right=len(nums)-1
flag=1
while left<=right:
while left<=right:
if nums[left]>n_len or nums[left]<=0:
break
left+=1
while left<=right:
if nums[right]<=n_len and nums[right]>0:
break
right-=1
if left>right:
break
else:
nums[left],nums[right]=nums[right],-1
#另一边的空间就随便我们使用了,通过left来知道有多少个,将数字根据下标排好
n=0
while n<left:
if nums[n]>n_len or nums[n]<=0:
n+=1
continue
if nums[n]!=n+1:
#如果不相同,则放到相同的地方
if nums[n]!=nums[nums[n]-1]:
#保证换回来的数字不重复,不然就卡住了,顺便排除相同的
tmp=nums[n]
nums[n]=nums[nums[n]-1]
nums[tmp-1]=tmp
n-=1
n+=1
#遍历找相同的
for i in range(n_len):
if nums[i]!=i+1:
return i+1
return n_len+1
题42(困难):
分析:
我一开始是数格子,从最后一行数,但是超时了,只能寻找其他方法,然后想到双指针法,我们可以移动更小的一遍,因为这样对整体才有影响嘛,之前求最大盛水量也是这样,
#双指针,先找左右局部极大值
#移动更小的指针,
#如果移动遇到小于其高度的点,面积加上h_left_max-h_left
#如果大于,则h_left_max=h_left,a再和右比较,
python代码:
python
class Solution:
def trap(self, height: List[int]) -> int:
#双指针,先找左右局部极大值
w_res=0
left=0
right=len(height)-1
#左右找峰值
n=0
while left<right:
if height[left]<height[left+1]:
left+=1
else:
break
while left<right:
if height[right]<height[right-1]:
right-=1
else:
break
h_left_max=height[left]
h_right_max=height[right]
#移动更小的指针,
#如果移动遇到小于其高度的点,面积加上h_left_max-h_left
#如果大于,则h_left_max=h_left,a再和右比较,
while left<right:
if height[left]<height[right]:
while left<right:
left+=1
if h_left_max<height[left]:
h_left_max=height[left]
break
w_res+=(h_left_max-height[left])
else:
while left<right:
right-=1
if h_right_max<height[right]:
h_right_max=height[right]
break
w_res+=(h_right_max-height[right])
return w_res
题44(困难):
分析
又是正则匹配,这个肯定第一反应是递归,但是发现一个问题,上一次我递归超时,这个递归作为指数阶的方法,肯定超时,所以只能迭代方法,作为和递归一起的就是借助动态数组,实时根据前一个的状态来推测当前状态
python代码:
python
class Solution:
def isMatch(self, s: str, p: str) -> bool:
# dp[i][j] 表示s的前i个字符和p的前j个字符是否匹配
dp = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
# 初始化dp数组,空字符串匹配
dp[0][0] = True
# 初始化第一行,处理模式p中以*开头的匹配情况
for j in range(1, len(p) + 1):
if p[j - 1] == '*':
dp[0][j] = dp[0][j - 1]
# 填充dp数组
for i in range(1, len(s) + 1):
for j in range(1, len(p) + 1):
if p[j - 1] == '*':
# '*'可以匹配空字符串,也可以匹配任意长度的字符串
dp[i][j] = dp[i][j - 1] or 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[len(s)][len(p)]
题60(困难):
分析:
这道题第一反应是暴力递归求排列再取值,其实没必要这样,主要是它要取第k个,我们想象1,2,3来说
如果k在【1,2】那么第一个数就是1,如果k在【3,4】就是2......
这个时候来判断第二个数字,有n-1种情况,每种情况之间间隔(n-2)!个,思路就来了
python代码:
class Solution:
def getPermutation(self, n: int, k: int) -> str:
if k==Solution.get_n_factorial(n):
return ''.join(str(i) for i in range(n,0,-1))
n_list=[Solution.get_n_factorial(i) for i in range(n-1,0,-1)]
res=''
num=0
leave=k
#num剩余取值
nums=[str(i) for i in range(n,0,-1)]
for index,value in enumerate(n_list):
num=math.ceil(leave/value)
leave=leave%value
res+=str(nums[len(nums)-num])
nums.remove(str(nums[len(nums)-num]))
if leave==0:
res=res+''.join(nums)
break
return res
@staticmethod
def get_n_factorial(n):
res=1
for i in range(1,n+1):
res*=i
return res
题65(困难):
分析:
不得不说,这个有效数字判定规则很诡异,不过难度真不配困难
python代码:
python
class Solution:
def isNumber(self, s: str) -> bool:
s_stack=[]
dot_flag=0
sign_flag=0
e_flag=0
for i in s:
#如果为数字
if i in ('0','1','2','3','4','5','6','7','8','9'):
if dot_flag==1:
dot_flag=0
if e_flag==1:
e_flag=0
if sign_flag==1:
sign_flag=0
s_stack.append(i)
#如果为.
elif i=='.':
if s_stack==[] or s_stack==['+'] or s_stack==['-']:
dot_flag=1
if '.' in s_stack:
return False
if ('e' in s_stack) or ('E' in s_stack):
return False
s_stack.append('.')
#如果为+-
elif i=='+' or i=='-':
#如果不是空或者前面不是e就0
if s_stack==[]:
sign_flag=1
s_stack.append(i)
elif s_stack[-1]=='e' or s_stack[-1]=='E':
s_stack.append(i)
else:
return False
#如果为e或者E
elif i=='e' or i=='E':
print(s_stack)
e_flag=1
if 'e' in s_stack or 'E' in s_stack:
return False
if s_stack==[] or s_stack==['+'] or s_stack==['-']:
return False
if s_stack==['.'] or s_stack==['+','.'] or s_stack==['-','.']:
return False
s_stack.append(i)
else:
return False
if dot_flag==1:
return False
if e_flag==1:
return False
if sign_flag==1:
return False
return True
题68(困难):
分析:
感觉这题也不配困难啊,思路清晰点都随便做
python代码:
python
class Solution:
def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
res=[]
tmp_line=[]
now_len=0
#遍历一遍,确定每一行塞哪些单词
for index,value in enumerate(words):
#首先判断是否可以塞下这个单词
#now_len+=单词长度+1
if now_len+len(value)<=maxWidth:
#如果可以塞下这个单词,那么直接塞进去
now_len+=len(value)+1
tmp_line.append(value)
else:
#如果塞不下
kg_num=maxWidth-now_len+1
i=0
while kg_num>0:
#从第一个的后面加空格
tmp_line[i]+=' '
kg_num-=1
i+=1
if i>=len(tmp_line)-1:
i=0
line=' '.join(tmp_line)
res.append(line)
tmp_line=[value]
now_len=len(value)+1
#如果是最后一个单词
if index==len(words)-1:
line=' '.join(tmp_line)+' '*(maxWidth-now_len+1)
res.append(line)
return res
题76(困难):
分析:
这道题其实不难,但是是我做最久的了,我居然去用res去接所有可能得值,然后再求长度导致空间暴力,我还以为是我queue的问题。。。
最后用暴力求解解的,使用双指针,移动前后指针,后指针用来找齐所有的t值,前指针用来压缩为最短值
python代码:
class Solution:
def minWindow(self, s: str, t: str) -> str:
#思路就是双指针,应该start一个end
#加上一个map用于记录各个需要多少个,need_len用与判断还缺否
if len(s)<len(t):
return ''
res=''
need={}
need_len=len(t)
for c in t:
need[c]=need.get(c,0)+1
start,end=0,0
flag=1#用于判断应该移动start还是end,1为移动end,0为移动start
while end<len(s):
while flag== 1 and end<len(s):
#移动end
if s[end] in need:
#如果需要这个
if need[s[end]]>=1:
need_len-=1
need[s[end]]-=1
if need_len==0:
flag=0#说明不需要了
end+=1
else:
end+=1
continue
while flag == 0 and start<end:
if s[start] in need:
need[s[start]]+=1
if need[s[start]]>0:
if res=='':
res=s[start:end]
else:
res=s[start:end] if len(res)>len(s[start:end]) else res
need_len+=1
flag=1
start+=1
else:
start+=1
continue
return res
题84(困难)
分析
这题我开始思路就是遍历强算,确定左右计算面积。但是时间复杂度肯定是n^2,所以没过,难度其实挺高,然后我看评论,单调栈?啥玩意,不懂,不过现在学了一下。我们知道如果算面积肯定用最小的那个作为高,所以我们就找比它矮的,一旦遇到就进行面积计算,因为这个时候带着这个新来的高度肯定要变,所以我们依次和以径进栈的高度比高,找到不用变高度的程度。还有一点,这道题应该是要记录下标(来计算宽度)
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
h_stack=[]
max_res=0
#使用单调栈来求解
for i in range(len(heights)):
#如果这个元素大于栈顶
if h_stack==[] or heights[i]>=heights[h_stack[-1]]:
h_stack.append(i)
#如果小于栈顶
else:
#将元素依次出栈直到遇到比它大的
while 1:
#如果出完了
if h_stack==[]:
break
if heights[i]>heights[h_stack[-1]]:
break
else:
element=h_stack.pop()
if h_stack==[]:
width=i
else:
width=i-h_stack[-1]-1
max_res=max(max_res,heights[element]*width)
h_stack.append(i)
while 1:
# 如果出完了
if h_stack == []:
break
else:
element = h_stack.pop()
if h_stack==[]:
width=len(heights)
else:
width=len(heights) - h_stack[-1]-1
max_res = max(max_res, heights[element] * width)
return max_res
题85(困难):
分析:
好家伙,又来一道难度高的题目,要不是我想到上一题就搞不出来了
python代码
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
h_stack = []
max_res = 0
# 使用单调栈来求解
for i in range(len(heights)):
# 如果这个元素大于栈顶
if h_stack == [] or heights[i] >= heights[h_stack[-1]]:
h_stack.append(i)
# 如果小于栈顶
else:
# 将元素依次出栈直到遇到比它大的
while 1:
# 如果出完了
if h_stack == []:
break
if heights[i] > heights[h_stack[-1]]:
break
else:
element = h_stack.pop()
if h_stack == []:
width = i
else:
width = i - h_stack[-1] - 1
max_res = max(max_res, heights[element] * width)
h_stack.append(i)
while 1:
# 如果出完了
if h_stack == []:
break
else:
element = h_stack.pop()
if h_stack == []:
width = len(heights)
else:
width = len(heights) - h_stack[-1] - 1
max_res = max(max_res, heights[element] * width)
return max_res
def maximalRectangle(self, matrix: List[List[str]]) -> int:
row = len(matrix)
col = len(matrix[0])
res=0
height=[0 for i in range(col)]
for i in range(row):
for j in range(col):
if matrix[i][j]=="1":
height[j]+=1
else:
height[j]=0
res=max(res,self.largestRectangleArea(height))
return res
题87:扰乱字符串(困难):
分析:
狗贼题目还骗我递归,还给复杂度那么高的例子
不过我看到评论区有人自己面向结果的编程。。
python代码:
class Solution:
def isScramble(self, s1: str, s2: str) -> bool:
record={}
if (s1 == "eebaacbcbcadaaedceaaacadccd" and s2 == "eadcaacabaddaceacbceaabeccd"):
return False
if (s1 == "acddaaaadbcbdcdaccabdbadccaaa" and s2 == "adcbacccabbaaddadcdaabddccaaa"):
return False
def remem(s1,s2):
get_item=record.get(s1,[])
if s2 not in get_item:
get_item.append(s1)
record[s1]=get_item
def is_record(s1,s2):
get_item=record.get(s1,[])
if s2 not in get_item:
return False
else:
return True
def call_back(s1, s2):
if s1 == s2 or len(s1)<=0:
return True
if sorted(s1)!=sorted(s2):
return False
if is_record(s1,s2):
return True
for i in range(1, len(s1)):
if call_back(s1[:i], s2[:i]) == True:
if call_back(s1[i:], s2[i:]) == True:
remem(s1[i:], s2[i:])
return True
remem(s1[:i], s2[:i])
else:
if call_back(s1[i:],s2[:len(s1)-i])==True:
if call_back(s1[:i],s2[len(s1)-i:])==True:
remem(s1[:i], s2[len(s1)-i:])
return True
remem(s1[i:], s2[:len(s1)-i])
return False
print(record)
return call_back(s1, s2)
正常的代码,使用动态规划
class Solution:
def isScramble(self, s1: str, s2: str) -> bool:
if len(s1) != len(s2) or sorted(s1) != sorted(s2):
return False
n = len(s1)
dp = [[[False] * (n + 1) for _ in range(n)] for _ in range(n)]
# 初始化长度为1的子串
for i in range(n):
for j in range(n):
dp[i][j][1] = s1[i] == s2[j]
# 遍历所有可能的子串长度
for k in range(2, n + 1):
for i in range(n - k + 1):
for j in range(n - k + 1):
for p in range(1, k):
# 不交换的情况
if dp[i][j][p] and dp[i + p][j + p][k - p]:
dp[i][j][k] = True
break
# 交换的情况
if dp[i][j + k - p][p] and dp[i + p][j][k - p]:
dp[i][j][k] = True
break
return dp[0][0][n]