Search a 2D matrix
把它看成是sorted list
def find(matrix,target):
if not matrix:
return False
if not matrix[0]:
return False
m,n=len(matrix),len(matrix[0])
start=0; end=m*n-1
while start<=end:
middle=(start+end)/2
if matrix[middle//n][middle%n]<target:
start=middle+1
elif matrix[middle//n][middle%n]>target:
end=middle-1
else:
return True
return False
第二种方法:先二分搜索行index(最后一个小于等于target的number),再二分搜索列index(等于target的number)
九章算法解答
def searchMatrix(matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
if not matrix[0]:
return False
m,n=len(matrix),len(matrix[0])
# find the row index, the last number<=target
start=0;end=m-1
while start+1<end:
mid=(start+end)//2
if matrix[mid][0]==target:
return True
elif matrix[mid][0]<target:
start=mid
else:
end=mid
if matrix[end][0]<=target:
row=end
elif matrix[start][0]<=target:
row=start
else:
return False
#find the col index, the number==target:
start=0;end=n-1
while start<=end:
mid=(start+end)//2
if matrix[row][mid]==target:
return True
elif matrix[row][mid]<target:
start=mid+1
else:
end=mid-1
return False
两种方法的时间复杂度都是O(log(mn))
Search a 2D matrix 2
第一种方法,每行二分搜索,时间复杂度为O(m*log(n))
def searchMatrix( matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
if not matrix[0] or matrix[-1][-1]<target:
return False
m,n=len(matrix),len(matrix[0])
for row in matrix:
if row[-1]<target:
continue
start=0; end=n-1
while start<=end:
mid=(start+end)//2
if row[mid]<target:
start=mid+1
elif row[mid]>target:
end=mid-1
else:
return True
return False
第二种方法,从top right 到left bottom,每次排除一行或者一列,时间复杂度为O(m+n)
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
if not matrix[0]:
return False
m,n=len(matrix),len(matrix[0])
rowindex=0;colindex=n-1
while rowindex<=m-1 and colindex>=0:
if matrix[rowindex][colindex]<target: #排除该行
rowindex+=1
elif matrix[rowindex][colindex]>target: #排除该列
colindex-=1
else:
return True
return False
替换空格
直接用python正则表达
\s: Matches any whitespace character; this is equivalent to the class [ \t\n\r\f\v].
def replaceSpace(s):
# write code here
import re
pt=re.compile('\s')
return pt.sub('%20',s)
def replaceSpace2(self, s):
# write code here
newS=""
for letter in s:
if letter==" ":
newS+="%20"
else:
newS+=letter
return newS
从尾到头打印链表
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
#时间复杂度O(n^2)
# write code here
arr=[]
while listNode:
arr.insert(0,listNode.val)
listNode=listNode.next
return arr
def printListFromTailToHead(self, listNode):
# 时间复杂度为O(n)
res=[]
def helper(res,listNode):
if not listNode:
return
helper(res,listNode.next)
res.append(listNode.val)
helper(res,listNode)
return res
数组中的逆序对
参考解答
利用归并的思想
class Solution:
"""
@param A: an array
@return: total of reverse pairs
"""
def reversePairs(self, A):
if not A:
return 0
start=0
end=len(A)-1
temp=[0]*len(A)
return self.countPairs(A,start,end,temp)
def countPairs(self,A,start,end,temp):
count=0
if start>=end:
return 0
mid=(start+end)//2
count+=self.countPairs(A,start,mid,temp) #统计左边子数组的逆序对
count+=self.countPairs(A,mid+1,end,temp) #统计右边子数组的逆序对
count+=self.countPairsBetweenArrs(A,start,end,temp) #统计左右数组之间的逆序对
return count
def countPairsBetweenArrs(self,A,start,end,temp):
if start>=end:
return 0
mid=(start+end)//2
leftindex=start
rightindex=mid+1
tempindex=start
count=0
while leftindex<=mid and rightindex<=end:
if A[leftindex]>A[rightindex]:
# for i in range(leftindex,mid+1):
# print (A[i],A[rightindex])
count=count+(mid-leftindex+1)
temp[tempindex]=A[rightindex]
rightindex+=1
tempindex+=1
else: # A[leftindex]<=A[rightindex]
temp[tempindex]=A[leftindex]
leftindex+=1
tempindex+=1
while leftindex<=mid:
temp[tempindex]=A[leftindex]
tempindex+=1
leftindex+=1
while rightindex<=end:
temp[tempindex]=A[rightindex]
rightindex+=1
tempindex+=1
A[start:(end+1)]=temp[start:(end+1)]
return count
丑数
def uglynumber(num):
for p in [2,3,5]:
while num%p==0 and num>0:
num=num//p
return num==1
丑数2
def nthUglyNumber(n):
"""
:type n: int
:rtype: int
"""
if n==0:
return None
ugly=[1]
i2,i3,i5=0,0,0
for i in range(n-1):
num=min(ugly[i2]*2,ugly[i3]*3,ugly[i5]*5)
ugly.append(num)
if num==ugly[i2]*2:
i2+=1
if num==ugly[i3]*3:
i3+=1
if num==ugly[i5]*5:
i5+=1
return ugly[-1]
两个链表的第一个公共结点
分别求出二者的长度,求出二者的差dis,而后将指向长的链表的指针先在长链表上走dis步,而两个链表同时走,二者会同时走到第一个公共节点处。
def FindFirstCommonNode(pHead1,pHead2):
p1=pHead1
p2=pHead2
len1=0; len2=0
while p1:
len1+=1
p1=p1.next
while p2:
len2+=1
p2=p2.next
for i in range(abs(len1-len2)):
if len1>len2:
pHead1=pHead1.next
else:
pHead2=pHead2.next
while pHead1:
if pHead1==pHead2:
return pHead1
pHead1=pHead1.next
pHead2=pHead2.next
return None
最小的k个数
def GetLeastNumbers_Solution(tinput, k):
# 利用最小堆,时间复杂度为O(n+klog(n))
if k>len(tinput):
return []
from heapq import heappush,heappop
q=[]
for num in tinput:
heappush(q,num)
res=[]
for i in range(k):
res.append(heappop(q))
return res
def GetLeastNumbers_Solution(tinput, k):
# 维护k个最大堆,时间复杂度为O(k+(n-k)logk)
if k>len(tinput) or k==0:
return [] #
import heapq
output=heapq.nlargest(k,tinput[:k])
for e in tinput[k:]:
if e<output[0]:
output[0]=e
output=heapq.nlargest(k,output)
return output[::-1]
连续子数组的最大和
def FindGreatestSumOfSubArray(array):
# 动态规划:maxSum[i]:以array[i]结尾的最长连续子序列的和
# maxSum[i]=max(maxSum[i-1]+array[i],array[i]) 要么重新开始一个子序列,要么接上前一个位置
if not array:
return 0
maxSum=[-float('inf')]*len(array)
maxSum[0]=array[0]
maxV=-float('inf')
for i in range(1,len(array)):
maxSum[i]=max(maxSum[i-1]+array[i],array[i])
maxV=max(maxV,maxSum[i])
return maxV
整数中1出现的次数
def NumberOf1Between1AndN_Solution(n):
# write code here
m=1
count=0
while m<=n:
curNum=(n//m)%10
if curNum>1:
count+=(n//m//10+1)*m
elif curNum==1:
count+=(n//m//10)*m+(n%m+1)
else:
count+=(n//m//10)*m
m*=10
return count
把数组排成最小的数
def PrintMinNumber(self, numbers):
#Bubble Sort
strLst=[str(n) for n in numbers]
for i in range(len(strLst)):
for j in range(len(strLst)-i-1):
if self.strCmp(strLst[j],strLst[j+1]):
strLst[j],strLst[j+1]=strLst[j+1],strLst[j]
return "".join(strLst)
def strCmp(self,s1,s2):
return s1+s2>s2+s1
数字在排序数组中出现的次数
def GetNumberOfK(data, k):
# 利用二分查找找到第一个等于k的数
if not data:
return 0
start=0
end=len(data)-1
#find first number equal k
while start+1<end:
mid=(start+end)//2
if data[mid]<k:
start=mid
else: #data[mid]>=target
end=mid
if data[start]==k:
firstindex=start
elif data[end]==k:
firstindex=end
else:
return 0
count=0
#判断的先后顺序很重要,while data[firstindex]==k and firstindex<len(data)会报错
while firstindex<len(data) and data[firstindex]==k:
count+=1
firstindex+=1
return count
二叉树的深度
def TreeDepth(self,node):
if not node:
return 0
leftdepth=self.TreeDepth(node.left)
rightdepth=self.TreeDepth(node.right)
depth=max(leftdepth,rightdepth)+1
return depth
判断平衡二叉树
class Solution:
def __init__(self):
self.bal=True
def isBalanced(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def helper(node):
if not node:
return 0
leftdepth=helper(node.left)
rightdepth=helper(node.right)
if abs(leftdepth-rightdepth)>1:
self.bal=False
depth=max(leftdepth,rightdepth)+1
return depth
helper(root)
return self.bal
数组中只出现一次的数字
任何一个数字异或他自己都等于0,0异或任何一个数都等于那个数。数组中出了两个数字之外,其他数字都出现两次,那么我们从头到尾依次异或数组中的每个数,那么出现两次的数字都在整个过程中被抵消掉,那两个不同的数字异或的值不为0,也就是说这两个数的异或值中至少某一位为1。我们找到结果数字中最右边为1的那一位i,然后一次遍历数组中的数字,如果数字的第i位为1,则数字分到第一组,数字的第i位不为1,则数字分到第二组。这样任何两个相同的数字就分到了一组,而两个不同的数字在第i位必然一个为1一个不为1而分到不同的组,然后再对两个组依次进行异或操作,最后每一组得到的结果对应的就是两个只出现一次的数字。
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, lst):
if not lst:
return []
xor=lst[0]
for num in lst[1:]:
xor^=num
res=self.findFirstBits1(xor)
num1=0;num2=0
for num in lst:
if self.isBits1(num,res):
num1^=num
else:
num2^=num
return [num1,num2]
def findFirstBits1(self,n):
#对于一个数字X,X&(-X)之后得到的数字,是把X中最右边的1保留下来,其他位全部为0。注意,这里的-X是X的相反数,-X=~X+1,这里的~X意思是对X所有位取反,
return n&(-n)
def isBits1(self,n1,n2):
if n1&n2==0:
return False
else:
return True
########方法二
def FindNumsAppearOnce(lst):
# 利用字典存储频率
freq={}
for num in lst:
freq[num]=freq.get(num,0)+1
res=[x for x in lst if freq[x]==1]
res.sort()
return res
def FindNums
和为S的连续正数序列
设定两个指针,先分别指向数字1和数字2,并设这两个指针为small和big,对small和big求和,如果和大于目标值,则从当前和中删除small值,并把small值加一,如果和小于目标值,则把big值加一,再把新的big值加入和中。如果和等于目标值,就输出small到big的序列,同时把big加一并加入和中,继续之前的操作。
def TreeDepth(self,node):
if not node:
return 0
leftdepth=self.TreeDepth(node.left)
rightdepth=self.TreeDepth(node.right)
depth=max(leftdepth,rightdepth)+1
return depth
和为S的连续正数序列
class Solution:
def FindContinuousSequence(self, tsum):
# write code here
small=1
big=2
middle=(tsum+1)//2 # small必须小于middle, middle*2=tsum+1
res=[]
cursum=small+big
while small<middle:
if cursum==tsum:
res.append(range(small,big+1))
big+=1 #big往后走一个
cursum+=big
elif cursum>tsum:
cursum-=small #small往后走一个
small+=1
else: #cursum<tsum
big+=1 # big往后走一个
cursum+=big
return res
和为s的两个数字
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
left=0
right=len(array)-1
res=[]
while left+1<=right:
t=array[left]+array[right]
if t==tsum:
res=[array[left],array[right]]
break
if t<tsum:
left+=1
else: # t>tsum
right-=1
return res
左旋转字符串
class Solution:
def LeftRotateString(self,s, n):
# 通过reverse
# reverse(0,n-1);
# reverse(n,lens-1);
# reverse(0,lens-1);
s=list(s)
s[:n]=self.reverse(s[:n])
s[n:]=self.reverse(s[n:])
s=self.reverse(s)
return "".join(s)
def reverse(self,s):
left = 0
right = len(s) - 1
while left + 1 <= right:
s[left], s[right] = s[right], s[left]
left+=1
right-=1
return s
class Solution:
def LeftRotateString(self,s,n):
#重新拼接
return s[n:]+s[:n]
def LeftRotateString2(self, s, n):
# 找出下标之间的关系
lens=len(s)
newS=[""]*lens
for i in range(lens):
newS[(i+1-n)%lens-1]=s[i]
return "".join(newS)
翻转单词顺序列
class Solution:
def ReverseSentence(self,s):
#先翻转整个句子,再逐个翻转每个单词
s=list(s)
s=self.reverse(s)
left=0
right=0
while right<=len(s):
if right==len(s) or s[right]==" ":
s[left:right]=self.reverse(s[left:right])
left=right+1
right+=1
return "".join(s)
def reverse(self,s):
left=0
right=len(s)-1
while left+1<=right:
s[left],s[right]=s[right],s[left]
left+=1
right-=1
return s
def ReverseSentence2(self,s):
#直接用python的语句
l=s.split(" ")
return " ".join(l[::-1])
def ReverseSentence3(self, s):
s=s.split(" ")
left=0
right=len(s)-1
while left+1<=right:
s[left],s[right]=s[right],s[left]
left+=1
right-=1
return " ".join(s)
扑克牌顺子
最直观的方法是把数组排序。值得注意的是,由于0可以当成任意数字,我们可以用0去补满数组中的空缺。如果排序之后的数组不是连续的,即相邻的两个数字相隔若干个数字,但只要我们有足够的0可以补满这两个数字的空缺,这个数组实际上还是连续的。举个例子,数组排序之后为{0,1,3,4,5},在1和3之间空缺了一个2,刚好我们有一个0,也就是我们可以把它当成2去填补这个空缺。
于是我们需要做3件事:
- 首先把数组排序
- 再统计数组中的0的个数
- 最后统计排序之后的数组中相邻数字之间的空缺总数。
如果空缺的总数小于或者等于0的个数,那么这个数组就是连续的;反之则不连续。
最后,我们还需要注意一点:
如果数组中的非0数字重复出现,则该数组不是连续的。
class Solution:
def IsContinuous(self, numbers):
if not numbers:
return False
numbers.sort() #排序
count=self.countingZero(numbers) #统计0的个数
gap=0 #统计不连续的间隔数
for i in range(count,len(numbers)-1):
if numbers[i]==numbers[i+1]:
return False
gap+=numbers[i+1]-numbers[i]-1
return gap<=count
def countingZero(self,numbers):
count=0
for num in numbers:
if num>0:
break
count+=1
return count
圆圈中最后剩下的数
解题思路
f[i]
f
[
i
]
记为让
i
i
个人报后最后剩下的数,
f[1]=0
f
[
1
]
=
0
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n<1 or m<1:
return -1
f=[0]*(n+1)
f[1]=0
for i in range(2,n+1):
f[i]=(f[i-1]+m)%i
return f[-1]
二叉搜索树的最低公共祖先
对于二叉搜索树而言,每个节点的左子节点都小于这个数,右子节点都大于这个数,因此,我们比较当前节点和需要比较的结点m,n的大小,如果当前节点的值均大于m,n,则在当前节点的左子树继续操作,如果当前节点均小于m,n,则在当前节点的右子树继续操作,反之,则当前结点是最小公共祖先。
'''
查找二叉树搜索树两个结点的最低公共祖先
'''
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def findCommonParent(self,node1, node2, root):
if root is None or node1 is None or node2 is None:
return None
if node1 == node2:
return node1
val1 = node1.val
val2 = node2.val
while root:
val = root.val
if (val1 - val) * (val2 - val) <= 0: # 在左右子树两边
return root
elif val1 < val and val2 < val:
root = root.left
else:
root = root.right
return None
pNode1 = TreeNode(8)
pNode2 = TreeNode(6)
pNode3 = TreeNode(10)
pNode4 = TreeNode(5)
pNode5 = TreeNode(7)
pNode6 = TreeNode(9)
pNode7 = TreeNode(11)
pNode1.left = pNode2
pNode1.right = pNode3
pNode2.left = pNode4
pNode2.right = pNode5
pNode3.left = pNode6
pNode3.right = pNode7
S = Solution()
print(S.findCommonParent(pNode3, pNode7, pNode1))
二叉树中两个结点的最低公共祖先
对于普通的二叉树而言,我们如果希望找到两个结点的最低公共祖先,那么我们可以先从树的根节点开始,找到根节点到结点m和结点n的路径,这时候我们就有两个List或者两个链表,然后就像前面题中遇到的寻找两个链表的公共结点一样,从后往前遍历两个List找到最靠后的第一个公共结点即可。
class Solution:
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
path1=self.findpath(root,p)
path2=self.findpath(root,q)
len1,len2=len(path1),len(path2)
for i in reversed(range(min(len1,len2))):
if path1[i]==path2[i]:
return path1[i]
return None
def findpath(self,root,node):
if root==node:
return [root]
if root is None:
return []
left=self.findpath(root.left,node)
right=self.findpath(root.right,node)
if len(left):
return [root]+left #在左子树中找到
elif len(right):
return [root]+right #在右子树中找到
else:
return [] #都没有找到
正则表达式
class Solution:
# s, pattern都是字符串
def match(self, s, pattern):
# write code here
f = [[False] * (len(pattern) + 1) for _ in range(len(s) + 1)]
f[0][0] = True
for i in range(len(s) + 1):
for j in range(len(pattern) + 1):
if j == 0 and i >= 1:
f[i][j] = False
continue
if j>=1 and pattern[j - 1] != "*":
if i >= 1 and j >= 1 and (s[i - 1] == pattern[j - 1] or pattern[j - 1] == "."):
f[i][j] = f[i - 1][j - 1]
else: # pattern[j-1]=="*"
if j >= 2:
f[i][j] = f[i][j - 2] # 匹配0次
if i >= 1 and (s[i - 1] == pattern[j - 2] or pattern[j - 2] == "."):
f[i][j] |= f[i - 1][j]
return f[-1][-1]
删除链表中的重复结点
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
def deleteDuplication(pHead):
dummy=ListNode(0)
dummy.next=pHead
p=dummy
while p.next and p.next.next:
if p.next.val==p.next.next.val:
val=p.next.val
while p.next and p.next.val==val:
p.next=p.next.next
else:
p=p.next
return p.next
链表中环的入口结点
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
fast=pHead
slow=pHead
meet=None
while fast and slow:
slow=slow.next
fast=fast.next
if fast:
fast=fast.next
if fast==slow:
meet=fast
break
if not meet:
return None
while meet!=pHead:
meet=meet.next
pHead=pHead.next
return meet
二叉树打印成多行
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if not pRoot:
return []
queue=[]
queue.append(pRoot)
res=[]
while queue:
size=len(queue)
level=[]
for i in range(size):
node=queue.pop(0)
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(level)
return res
对称二叉树
class Solution:
def isSymmetrical(self, pRoot):
# write code here
def helper(leftT,rightT):
if not leftT and not rightT:
return True
if leftT and rightT and leftT.val==rightT.val:
return helper(leftT.left,rightT.right) and helper(leftT.right,rightT.left)
return helper(pRoot,pRoot)
二叉树的镜像
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if not root:
return
left=self.Mirror(root.left)
right=self.Mirror(root.right)
root.right=left
root.left=right
return root