class Solution:
def Find(self,target,array):
goal_array=[]
for ele in array:
goal_array.extend(ele)
for ele in goal_array:
if ele == target:
return True
return False
class Solution:
def replaceSpace(self,s):
s=list(s)
for i in range(len(s)):
if s[i]==' ':
s[i]='%20'
return ''.join(s)
class Solution:
def printListFromTailToHead(self,listNode):
list_node=[]
head=listNode
while head:
list_node.insert(0,head.val)
head=head.next
return list_node
class TreeNode:
def __init__(self,x):
self.val=x
self.left=None
self.right=None
class Solution:
def reConstructBinaryTree(self,pre,tin):
if len(pre)==0:
return None
if len(pre)==1:
return TreeNode(pre[0])
else:
root=TreeNode(pre[0])
i=tin.index(root.val)
tree_left=tin[:i]
tree_right=tin[i+1:]
root.left=self.reConstructBinaryTree(pre[i:i+1],tree_left)
root.right=self.reConstructBinaryTree(pre[i+1:],tree_right)
return root
class Solution:
def __init__(self):
self.stack1=[]
self.stack2=[]
# 栈的push是从从上压入,而队列push是入队尾,相当于List的append
def push(self,node):
self.stack1.append(node)
# 队列的pop是尾取
def pop(self):
if self.stack2==[]:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
class Solution:
def minNumberInRotateArray(self,rotateArray):
return min(rotateArray)
class Solution:
def Fibonacci(self,n):
temp=[0,1]
while len(temp)<=n:
temp.append(temp[-1]+temp[-2])
return temp[n]
-------------------------------------------------
# 解法二:
def Fibonacci(self,n):
if n==0:
return 0
if n==1:
return 1
return self.Fibonacci(n-1)+self.Fibonacci(n-2)
def Solution:
def jumpFloor(self,number):
temp=[1,1]
while len(temp)<=number:
temp.append(temp[-1]+temp[-2])
return temp[number]
class Solution:
def jumpFloorII(self,number):
return 2**(number-1)
class Solution:
def rectCover(self,number):
temp=[0,1,2]
while len(temp)<=number:
temp.append(temp[-1]+temp[-2])
return temp[number]
class Solution:
def Power(self,base,exponent):
temp=1
for _ in range(abs(exponent)):
temp*=base
return temp if exponent>0 else 1/temp
class Solution:
def reOrderArray(self,array):
odd,even=[],[]
for i in array:
odd.append(i) if i%2==1 else even.append(i)
return odd+even
class Solution:
def FindKthToTail(self,head,k):
node_list=[]
while head:
node_list.append(head)
head=head.next
if len(node_list)<k or k<1:
return
return node_list[-k]
题目:输入一个链表,反转链表后,输出新链表的表头
思路:
1.定义一个指向前节点的指针prev,一个头结点phead,一个当前节点curr
2.头节点遍历整个链表,直到phead为空为止;
3.当前节点始终指向头结点现在所在的位置,当前节点的.next指针指向prev
def ReerseList(phead):
prev=None
while phead:
curr=phead
phead=phead.next
#当前的头节点就是反转后链表的尾节点,所以尾节点的.next=None
curr.next=prev
prev=curr
return prev
输入两个单调递增的链表,输出两个链表合成后的链表,要求,合成后链表满足单调不递减规则
思路:
1.先判断两个链表是否为空,如果为空,无需排序,直接返回另一个非空链表
2.采用递归的方法
def Merge(pHead1, pHead2):
phead=ListNode(None)
if not pHead1:
return pHead2
if not pHead2:
return pHead1
if pHead1.val<pHead2.val:
phead=pHead1
phead.next=Merge(pHead1.next,pHead2)
else:
phead=pHead2
phead.next=Merge(pHead1,pHead2.next)
return phead
非递归方法
def Merge(l1,l2):
temp=ListNode(None)
cur=temp
while l1 and l2:
if l1.val
题目:输入两棵二叉树A,B,判断B是不是A的子结构(约定空树不是任意一棵树的子结构)
思路:采用递归的方法
class TreeNode:
def __init__(self,x):
self.val=x
self.left=None
self.right=None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
#先判断A,B两棵树是否存在空树,若有,直接返回False
if pRoot1==None or pRoot2==None:
return False
result=False
if pRoot1.val==pRoot2.val:
result=self.isSubtree(pRoot1,pRoot2)
if result==False:
#由于需要判断B是否是A的子结构,在根节点不相同的情况下,需要判断A的左子树和右子树是否和B有相同的结构
result=self.HasSubtree(pRoot1.left,pRoot2)|\
self.HasSubtree(pRoot1.right,pRoot2)
return result
def isSubtree(self,root1,root2):
#判断顺序很重要,现在要判断的是B是否是A的子树,不用判断A是否是B的子树
#且在pRoot1.val==pRoot2.val的情况下,说明A,B的根节点是相同的,均不是空树
if root2==None:
return True
if root1==None:
return False
if root1.val==root2.val:
return self.isSubtree(root1.left,root2.left)&\
self.isSubtree(root1.right,root2.right)
return False
给定n个非负整数a1,a2…an,每个数代表坐标中的一个点(i,ai)。在坐标内画n条垂线,垂线i的两端分别为(i,ai),和(i,0),找出其中的两条直线,使得他们与x轴共同构成的容器可以容纳最多的水
思路
1.可以使用两次for循环,将每个面积都求出来,放在列表内,通过max()函数找出最大值
2.可以在函数内动态维护一个最大面积
# 解法1:
def maxarea(target_list):
temp_s=[]
for i in range(len(target_list)-1):
for j in range(i+1,len(target_list)):
if target_list[i]>target_list[j]:
temp_s.append(target_list[j]*(j-i))
else:
temp_s.append(target_list[i]*(j-i))
return max(temp_s)
注:该种解法可以解决当前问题,但是时间复杂度为O(n^2),因为有两次for循环,时间复杂度较大
# 解法2:
left,right=0,len(target_list)-1
temp_s=0
while left<right:
width=right-left
area=(min(target_list[left]*width,target_list[right]*width))
if temp_s<area:temp_s=area
if target_list[left]>target_list[right]:
right-=1
else:
left+=1
return temp_s
L C I R
E T O E S I I G
E D H N
输出:LCIRETOESIIGEDHN
1.字符串s是以Z字形为顺序存储的字符串,目标是按行打印
2.设numrows行字符串分别为s1,s2,…,sn,容易发现:按照顺序遍历字符串s时,每个字符c在Z字形中对应的行索引先从s1增大到sn,再从sn减小到s1…如此反复
def convert(s,numRows):
if numRows<2:return s
res=["" for _ in range(numRows)] #res=["","",""]
i,flag=0,-1
for c in s:
res[i]+=c
if i==0 or i == numRows-1:flag=-flag
i+=flag
return "".join(res)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QBDtB1XV-1585654205504)(C:\Users\pxr\Desktop\一些文件夹\md图片\Z型打印图解.png)]
num=12345678 输出87654321负数要保留负号
思路:
先将int类型的数字转换成str类型,然后通过遍历的方法拿到目标数字
def func(x):
flag=0
restr=""
if x<0:
flag=1
x=str(abs(x))
res=[]
for i in x:
res.append(i)
for c in res[::-1]:
restr+=c
restr=int(restr)
if flag==1:
restr=-restr
return restr
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。
思路:定义一个辅助栈B,压栈的时候,如果A栈的栈顶元素比待压入元素大,则B不压入,小于等于则A压入;出栈时,若AB栈顶元素不等,则B出A不出
class Solution:
def __init__(self):
self.stack=[] # 定义的辅助栈
self.stack_min=[]
def push(self,node):
if not self.stack_min or self.stack_min[-1]>=node: # A栈的栈顶元素大于压入元素,则需要压入
self.stack_min.append(node)
self.stack.append(node)
def pop(self): # 从栈顶依次弹出
if self.stack[-1]==self.stack_min[-1]:
self.stack_min.pop()
self.stack.pop()
def top(self):
return self.stack[-1]
def min(self):
return self.stack_min[-1]
class Solution:
def IsPopOder(self,pushV,popV):
if not pushV or len(pushV)!=len(popV):
return False
stack=[] # 辅助栈
for i in pushV:
stack.append(i) # 向辅助栈中按照压栈顺序添加元素
while len(stack) and stack[-1]==popV[0]: # 如果辅助栈中有元素,且辅助栈中末尾元素和弹出栈头元素相等,则弹出相同元素
stack.pop()
popV.pop(0)
if len(stack): # 当遍历完压栈顺序后,如果辅助栈中仍存在元素,标明二者顺序不等
return False
return True
class Solution:
def PrintFromTopToBottom(self,root):
if not root :
return None
nqueue=[root] #创建一个队列,里面存入根节点
node_list=[]
while nqueue: # 循环开始
cur_node=nqueue.pop(0) # 当前节点就是最先放进队列的元素,将其取出,并添加到列表中
node_list.append(cur_node.val)
if cur_node.left: # 根据题目要求,先左后右,如果左子树存在,则放入队列
nqueue.append(cur_node.left)
if cur_node.right: # 右子树同理
nqueue.appende(cur_node.right)
return node_list
class Solution:
def VerifySquenceOfBST(self,sequence):
if sequence==None or len(sequence)==0:
return False
length=len(sequence)
root=sequence[-1] # 由于是后序遍历,所以最后一个值是根节点的值
for i in range(length):
if sequence[i]>root: # 当找到数组中大于根节点的数,则标明进入了右子树,其后的所有节点都应该大于根节点
break
for j in range(i,length): # 进入右子树部分,判断是否所有节点都大于根节点
if sequence[j]<root:
return False
left=bool
if i>0: # 由于拆分出来的两部分仍然为有序二叉树,利用递归判断左子树
left=self.VerifySquenceOfBST(sequence[0:i])
right=bool
if i<length-1: # 利用递归判断右子树
right=self.VerifySquenceOfBST(sequenct[i,-1])
return left and right
class Solution:
def FindPath(self,root,expectNumber):
if not root:
return []
if root and not root.left and not root.right and root.val=expectNumber: # 看根节点是否和目标值匹配
return [[root.val]]
res=[]
left=self.FindPath(root.left,expectNumber-root.val) # 递归判断左子树
right=self.FindPath(root.right,expectNumber-root.val) # 递归判断右子树
for i in left+right:
res.append([root.val]+i)
return res
题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路:1.把复制的节点链接在原始链表的每一个对应节点后面
2.把复制的节点的random指针指向被复制节点的random指针的下一个节点
3.拆分两个链表,奇数位置为原链表,偶数位置为复制链表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o7uAlcma-1585654205505)(C:\Users\pxr\Desktop\一些文件夹\md图片\复杂链表复制(1).png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WnU41v5T-1585654205506)(C:\Users\pxr\Desktop\一些文件夹\md图片\复杂链表复制(2).png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rWxKrh8C-1585654205506)(C:\Users\pxr\Desktop\一些文件夹\md图片\复杂链表复制(3).png)]
class Solution: # dummy:复制的
def Clone(self,pHead):
if not pHead:
return None
# 第一步:将复制的节点放在原节点后,其本质是链表的遍历
dummy=pHead
while dummy:
copynode=RandomListNode(dummy.label) # 复制节点
# 复制节点的下一个指针,指向原链表的下一个节点,见图1(A'->B)
copynode.next=dummy.next
# 而原节点的下一个指针不再指向链表的原本下一个节点,而是指向复制节点,见图1(A->A')
dummy.next=copynode
# 由于已经改变链表的原有结构,dummy.next指向的不是原链表的下一个节点,所以需要dummy.next.next才是原来节点的指针指向
dummy=dummy.next.next
# 第二步:规范复制后节点的random指针的指向,步骤和第一步一样,遍历链表
dummy=pHead
while dummy:
copynode=dummy.next # 在完成了第一步后,每一个输入节点的后面都是复制节点
if dummy.random: # 由于是随机指针,需要判断指针指向的下一个节点是否存在
copynode.random=dummy.random.next
dummy=copynode.next
# 第三步:取出复制的链表,由于完成前两步后两个链表仍拼接在一起见图2(A->A'),而正确的链表指针应该是A->B,所以需要拆分
dummy=pHead
copyHead=pHead.next # 分别定为表头
while dummy:
copyNode=dummy.next # 由于第一步,复制节点是在原节点之后
dummy.next=copyNode.next # 原节点的指针应该指向B,也就是复制节点之后
if dummy.next: # 判断是否是尾节点
copyNode.next=dummy.next.next
else:
copyNode.next=node # 给复制链表的尾节点复制(None)
dummy=dummy.next
return copyHead
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向
思路:1.将左子树构造成双链表,并返回链表头结点
2.定位至左子树双链表最后一个节点
3.如果左子树链表不为空的话,将当前root追加到左子树链表
4.将右子树构造成双链表,并返回头结点
5.如果右子树链表不为空的话,将该链表追加到root节点后
6.根据左子树链表是否为空,确定返回的节点
class Solution:
def Convert(self,pRootOfTree):
if not pRootOfTree:
return None
if pRootOfTree and not pRootOfTree.left and not pRootOfTree.right:
return pRootOfTree
# 递归处理左子树
self.Convert(pRootOfTree.left)
left=pRootOfTree.left
if left: # 如果左子树存在
while left.right: # 如果左子树的右子树存在
left=left.right # 找到左子树的右子树的叶节点
# 由于有序二叉树,左子树的所有值都比根节点小,当找到根节点左子树的右子树的叶节点后,就是该左子树中最大的节点,所以pRootOfTree.left=left(注意:此时的left就是左子树的右子树的叶子结点),left.right=pRootOfTree
pRootOfTree.left,left.right=left,pRootOfTree
# 递归处理右子树
self.Convert(pRootOfTree.right)
right=pRootOfTree.right
if right:
while right.left: # 如果右子树的左子树存在
right=right.left # 找到右子树的左子树的叶节点
pRootOfTree.right,right.left=right,pRootOfTree # 这里同理左子树
while pRootOfTree.left: # 如果根节点的左子树存在
pRootOfTree=pRootOfTree.left # 则向下遍历,直至找到左子树的叶子结点,该节点就是整个链表的头节点(因为最小)
return pRootOfTree
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路:假设有这个数字,那么他的数量一定比其他所有数字之和还要多
1.先要找到这个数字
2.再看这个数字是否出现次数超过半数
tip:因为如果一个数一旦出现次数过半,最极端的情况是插空分布在各个数字之间,最后的count计数也不会为0,所以只要找到count计数不为0的那个数字,就是目标数字,当然,要排除极端情况,也就是末尾囤积了大量相同数字
class Solution:
def MoreThanHalfNum_Solution(self,numbers):
if not numbers:
return 0
num=numbers[0] # 从第一个数字开始,找到出现过半的数字
count=1 # 并且开始计数
for i in range(1,len(numbers)):
if numbers[i]==num: # 从第二个数开始遍历数组,若数字相等,则计数+1,反之-1
count+=1
else:
count-=1
if count==0: # 若当前计数为0,则将标准数字设定为你当前数字,并且计数重新为1
num=numbers[i]
count=1
# 重新开始计数,计算num的出现次数
count=0
for i in numbers:
if i ==num:
count+=1
return num if count>len(numbers)/2 else 0
class Solution:
def GetLeastNumbers_Solution(self,tinput,k):
if tinput is None:
return None
if len(tinput)>k:
return[]
tinput=sorted(tinput)
return tinput[:k]
题目:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:动态维护一个最大数组
1.以dp[i]表示以元素array[i]结尾的最大连续子数组和,以[-2,-3,4,-1,-2,1,5,-3]为例
2.dp[0]=-2 dp[1]=-3 dp[2]=4 dp[3]=3
3.dp[i]=max(dp[i-1]+array[i],array[i])
class Solution:
def FindGreatestSumOfSubArray(self,array):
length=len(array)
dp=[i for i in array]
for i in range(1,length):
dp[i]=max(dp[i-1]+array[i],array[i])
return max(dp)
class Solution:
def PrintMinNumber(self,numbers):
if not numbers:return ''
# 先用map函数将所有数字变成str类型,再变成列表
numbers=list(map(str,numbers))
# 构造匿名函数,比较相邻两个数以不同顺序相加的大小,并按照从小到大排列
numbers.sotr(cmp=lambda x,y:cmp(x+y,y+x))
# lstrip()用于截掉字符串左边的空格或指定字符串
return ''.join(numbers).listrip('0') or '0'
题目:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数
思路:
质因子:也叫质因数,指能整除给定正整数的质数,连个没有共同质因子的正整数称为互质
一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,也就是说,一个丑数一定有另一个丑数乘以2或3或5得到,那么从1开始,乘以2,3,5得到2,3,5三个丑数,从这三个丑数触发,得到4,6,10,6,9,15,10,15,25九个丑数,但是通过这种方法得到的丑数会有重复,所以可以维护三个队列:
(1)丑数数组:1
乘以2的队列:2
乘以3的队列:3
乘以5的队列:5
选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列
(2)丑数数组:1,2
乘以2的队列:4
乘以3的队列:3,6
乘以5的队列:5,10
选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列
(3)丑数数组:1,2,3
乘以2的队列:4,6
乘以3的队列:6,9
乘以5的队列:5,10,15
选择三个队列头里最小的数4加入丑数数组,溶蚀将该最小的数乘以2,3,5放入三个队列
(4)丑数数组:1,2,3,4
乘以2的队列:6,8
乘以3的队列:6,9,12
乘以5的队列:10,15,20
选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列
…
class Solution:
def GetUglyNumber_Solution(self,index):
if index<1:
return 0
res=[1] # 创建一个结果列表
t2=t3=t5=0 # t2,t3,t5分别是三个队列(乘以2或3或5)
nextindex=1
while nextindex<index:
# 将每次乘以2,3,5的数取最小,加入到结果列表中
minNumber=min(res[t2]*2,res[t3]*3,res[t5]*5)
res.append(minNumber)
# 判断此次加入列表的数是哪个队列(乘以2,还是3,还是5),并将对应队列的游标+1
while res[t2]*2<=minNumber:
t2+=1
while tes[t3]*3<=minNumber:
t3+=1
while tes[t5]*5<=minNumber:
t5+=1
nextindex+=1
return res[nextindex-1]
class Solution:
def FirstNotRepeatingChar(self,s):
dict_s={}
# 遍历字符串,将字母依次存入字典,如果该字母第一次出现,则计数为1,反之则+1
for item in s:
dict_s[item]=1 if item not in dict_s else dict_s[item]+1
# 再次遍历字符串,找到出现次数为1的字符,将其索引返回
for item in s:
if dict_s[item]==1:
return s.index(item)
return -1
class Solution:
def InversePairs(self,data):
count=0
# 现将数组排序,采用快排
sort_data=self.quick_sort(data)
# 遍历排序后的数组,找到排序数组中数字在原数组中的索引,由于是按照从小到大排序的,所以该数字以前的数字都比他小,也就是逆序对,所以该数字的索引就是逆序对的个数
for ele in sort_data:
pos=data.index(ele)
count+=pos
# 将该数字从原数组中删除
data.pop(pos)
return count%1000000007
def quick_sort(self,data):
if len(data)<2:
return data
base=data[0]
left=[i for i in data if i<base]
right=[i for i in data if i>base]
return self.quikc_sort(left)+[base]+self.quick_sort(right)
class Solution:
def FindFirstCommonNode(self,pHead1,pHead2):
len1=self.getLength(pHead1)
len2=self.getLength(pHead2)
if len2>len1:
pHead1,pHead2=pHead2,pHead1
diff=abs(len1-len2)
while diff>0:
pHead1=pHead1.next
diff-=1
while pHead1!=pHead2:
pHead1=pHead1.next
pHead2=pHead2.next
return pHead1
def getLength(self,Head):
count=0
while Head:
count+=1
Head=Head.nex
return count
---------------------------------------------------------------
# 解法二:
def FindFirstCommonNode(self, pHead1, pHead2):
p1, p2 = pHead1, pHead2
while p1 != p2:
p1 = p1.next if p1 != None else pHead2
p2 = p2.next if p2 != None else pHead1
return p1
题目:统计一个数字在排序数组中出现的次数
思路:采用哈希表,由于是排序数组,将数字存入字典,出现一次,则计数+1(但是这种方法的时间复杂度是O(n))
正解:由于是有序数组,可用二分查找叨叨给定数字及其坐标,以该坐标为中点,向前向后找到这个数字的始 - 终位置
class Solution:
def GetNumberOfK(self,data,k):
dict_data={}
for ele in data:
# 遍历数组,将数组中的元素存入哈希表,如果是第一次出现,计数为1,反之计数+1
dict_data[ele]=1 if ele not in data else dict_data[ele]+1
for ele in data:
if ele == k:
return dict_data[ele]
return 0
-----------------------------------------------------------
# 解法二:
def GetNumberOfK(self,data,k):
if len(data)<1:
return 0
mid=len(data)//2 # 找到索引在中间的数
if data[mid]==k:
start,end=mid,mid # 如果该数恰好等于k,则从该数开始,start,end都等于mid
for i in range(mid,-1,-1): # 从中间数开始向前找,找数值等于k的数
if data[i]==k:start=-1 # 每找到一个,start-1
for j in range(mid+1,len(data)): # 向后找同理
if data[j]==k:end+=1
return end-start # 返回end-start就是该数字在数组中的出现次数
elif data[mid]>k: # 接下来是二分查找,递归调用
return self.GetNumberOfK(data[:mid],k)
else:return self.GetNumberOfK(data[mid+1:],k)
class Solution:
def TreeDeep(self,pRoot):
if not pRoot:
return 0
# 左子树递归,每次递归一个节点,计数+1,出口在not pRoot
left=self.TreeDeep(pRoot.left)+1
right=self.TreeDeep(pRoot.right)+1
return max(left,right)
题目:输入一棵二叉树,判断该二叉树是否是平衡二叉树
思路:
平衡二叉树:它是一颗空树,或者它的左右两个子树的高度差绝对值不超过1,并且左右两个子树都是平衡二叉树
上题求二叉树深度,从下到上,分别判断某节点的左右子树是否是平衡二叉树,即:根据该节点的左右子树高度差判断是否平衡
class Solution:
def IsBalanced_Solution(self,pRoot):
self.flag=True
self.Tree_depth(pRoot)
return self.flag
# 先求出二叉树的深度,然后分别在每个节点判断左右子树是否是平衡二叉树,并改变flag的值
def Tree_depth(self,pRoot):
if not pRoot or self.flag==False:
return 0
left=self.Tree_depth(pRoot.left)+1
right=self.Tree_depth(pRoot.right)+1
if abs(left-right)>1:
self.flag=False
return max(left,right)
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
思路:哈希表,将数字存入哈希表,键为数字,值为出现次数
解法二:用异或求解。
异或运算:任何一个数字异或他自己都等于0,也就是说,如果数组中只有一个数字出现过一次,其余数字都出现了两次,这样的话,如果从头到尾一次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字,因为那些出现过两次的数字全部在异或中抵消了。如果能够把原数组分为两个子数组,在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次,在两个子数组中分别求出这两个只出现一次的数字
还是从头到尾一次异或数组中的每个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果,因为其他数字都出现了两次,在异或中全部抵消。由于这两个数字肯定不同,那么这个异或结果肯定不是0,也就是说,在这个结果数字的二进制表示作用至少就有一位为1,我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0.现在我们已经把原数组分成了两个数组,每个数组都包含一个只出现一次的数字,而其他数字都出现了两次
class Solution:
def FindNumsAppearOnce(self,array):
if len(array)<2:
return None
dict={}
for ele in array:
dict_arr[ele]=1 if ele not in dict_arr else dict_arr[ele]+1
res=[k for k in dict_arr if dict_arr[k]==1]
return res
----------------------------------------------------------
# 解法二:
def FindNumsApperOnce(self,array):
if len(array)<2:
return None
remain,index=0,1
for num in array:
remain=remain ^ num
while (remain & index)==0:
index=index << 1
res1,res2=0,0
for num in array:
if(num & index)==0:
res1=res1 ^ num
else:
res2=res2 ^ num
return [res1,res2]
class Solution:
def FindContinuousSequenct(self,tsum):
if tsum<3:
return []
p_low=1
p_high=2
ans=[]
while p_low<p_high:
cur_sum=sum(range(p_low,p_high+1))
if cur_sum==tsum:
ans.append(range(p_low,p_high+1))
# 移动滑动窗口,并寻找下一组解
p_high+=1
elif cur_sun<tsum:
p_high+=1
else:
p_low+=1
return ans
class Solution:
defFindNumbersWithSum(self,array,tsum):
start,end=0,len(array)-1
while start<end:
if array[start]+array[end]==tsum:
return array[start],array[end]
elif array[start]+array[end]<tsum:
start+=1
else:end-=1
return []
class Solution:
def LeftRotateString(self,s,n):
s=list(s)
s=s+s[:n]
return ''.join(s[n:])
class Solution:
def ReverseSentence(self,s):
s=s.split(' ')
s=reversed(s)
return " ".join(s)
题目:LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0
思路:需要满足两个条件
1.除0外没有重复的数
2.max-min<5
class Solution:
def IsContinuous(self,numbers):
min,max,flag=14,-1,0
lf len(numbers)!=5:return False
for num in numbers:
if num==0:continue
if (flag>>num)&1==1:return False
flag=flag | (1<<num)
if num<max:max=num
if num<min:min=num
if max-min>=5:return Flase
return True
题目:每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)如果没有小朋友,请返回-1
思路:约瑟夫环
n个人的编号为n ~ n-1,当数到m-1的那个人出列
第一次出列:一开始,所有人的编号排成序列模式为:0,1,2,3,4…n-2,n-1,那么第一次出列的人的编号为(m-1)%n1,那么在第一个人出列后,从他的下一个人又开始从0报数,为方便,设k1=m%n1(n1为当前序列的总人数),那么在第一个人出列后,k1则是下一次新的编号序列的首位元素,那么我们得到的新的编号序列为k1,k1+1,k1+2,…,n-2,n-1,0,1,2,…,k1-3,k1-2(k1-1第一次已出列),那么在这个新的序列中,第一个人依旧是从0开始报数,每人报的相应数字为0,1,2,3,…,n-2,第二次每个人报的相应数字与第一次时自己相应的编号对应起来关系为:
0 -----> k1
1 -----> k1+1
2 -----> k1+2
…
n-2 ----> (k1+n-2)%n1 (n1为当前序列的总人数,因为是循环的序列,k1+n-1可能大于总人数)
那么要解决的就是n-1个人报数的问题,即n-1约瑟夫环的问题
class Solution:
def LastRemaining_Solution(self,n,m):
if n<1:
return -1
res,i=0,2
while i<=n:
res=(res+m)%i
i+=1
return res
class Solution:
def Sum_Solution(self,n):
if n==1:
return n
res=n
return res+self.Sum_Solution(n-1)
class Solution:
def duplicate(self,numbers,duplication):
dict_num={}
for ele in numbers:
dict_num[ele]=1 if ele not in dict_num else dict_num[ele]+1
for ele in dict_num:
if dict_num[ele]!=1:
duplication[0]=ele
return True
return False
题目:给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];) 好贱啊!!不能用除法,用除法老子分分钟搞定…
思路:B[0]=A[1]*…A[n-1] 没有A[0]
B[1]=A[0]*…A[n-1] 没有A[1]
class Solution:
def multiply(self,A):
B=[]
for i in range(len(A)):
temp=A[i]
b=1
for j in range(len(A)):
A[i]=1 # 因为B不要A[i],所以将A[i]置为1,然后连乘解决问题
b*=A[j]
B.append(b)
A[i]=temp
return B
题目:请实现一个函数用来匹配包括’.‘和’*‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
思路:当模式中的第二个字符不是*时:
1.如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的
2.如果字符串第一个字符和模式中的第一个字符不匹配,直接返回False
当模式中的第二个字符是*时
如果字符串第一个字符跟模式第一个字符不相匹配,则模式后移2个字符,继续匹配,如果字符串第一个字符跟模式第一个字符匹配,可以由3中匹配方式:
1.模式后移2个字符,相当于x*被忽略;
2.字符串后移1字符,模式后移2字符;
3.字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位(该种情况被1,2包含)
class Solution:
def match(self,s,pattern):
if s==pattern: # 最好的情况,完全匹配
return True
if len(pattern)>1 and pattern[1]=='*':
if s and (s[0]==pattern[0] or pattern[0]=='.'):
return self.match(s,pattern[2:]) or self.match(s[1:],pattern)
else:
return self.match(s,pttern[2:])
elif s and pattern and (s[0]==pattern[0] or pattern[0]=='.'):
return self.match(s[1:],pattern[1:])
return False
class Solution:
def isNumber(self,s):
import re
pattern=r'^[\+-]?[\d]*(\.[\d]*)?([eE][\+-]?[\d]+)?$'
match=re.match(pattern,s)
return match
class Solution:
def __init__(self):
self.s=''
self.dict1={}
def FirstAppearingOnce(self):
for i in self.s:
if self.dict1[i]==1:
return i
return '#'
def Insert(self,char):
self.s+=char
if char in self.dict1:
self.dict1[char]+=1
else:
self.dict1[char]=1
题目:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null
思路:首先要明确什么是环
如何确定链表中是否有环:
利用两个速度不同的指针,一个指针一次走一步,另一个指针一次走两步,如果走的快的指针追上了走得慢的指针,说明链表中有环,如果走的慢的指针走到了链表的末尾都还没又被走得快的指针追上,那么链表中没有环
如何找到环的入口节点:
使用两个指针,指针之间的距离为环的长度。也就是说,如果环中有n个节点,则第一个节点先在链表中移动n步,然后两个指针以相同的速度向前移动,当第二个指针指向环的入口节点时,第一个指针也已经走完这个环,并且重新指向入口节点了,那么,我们怎么知道链表中的环有几个节点呢?获取链表里的环中的节点数量是在第一步中实现的,当第一步中快、慢指针相遇后,从这两个指针指向的节点出发,并开始计数,当再次回到这个节点时,就得到了环中的节点数了
class ListNode(object):
def __init__(self,value,next_node=None):
self.value=value
self.next=next_node
def entry_node_of_loop(head):
finded_nodes={}
cur=head
while cur:
# 字典的get()方法,通过键找值,如果相应的键不存在,则返回None
if finded_nodes.get(cur.value)!=1:
finded_nodes[cur.value]=1
else:
return cur
cur=cur.next
return
class Solution:
def deleteDuplication(self,pHead):
first=ListNode(-1)
first.next=pHead
last=first
while pHead and pHead.next:
if pHead.val==pHead.next.val:
val=pHead.val
while pHead and val==pHead.val:
pHead=pHead.next
last.next=pHead
else:
last=pHead
pHead=pHead.next
return first.next
题目:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针
思路:中序遍历就是:左,根,右,有三种情况:
1.给定的节点为空,返回空
2.给定的节点有右子树,沿着该右子树,返回右子树的第一个左叶子节点
3.给定的节点没有右子树,如果位于某个节点的左子树中,则上溯直至找到该节点,否则返回空(因为按照中序遍历,“左中右”的遍历方式,该节点没有右子树时,要么遍历完毕,下一个节点为空,要么某个子树的左子树遍历完毕,下一个节点是子树的根节点)
class Solution:
def GetNext(self,pNode):
if pNode.right: # 如果该节点有右子树
p=pNode.right # 循环找该节点的左叶子结点,就是下一个节点
while p.left:
p=p.left
return p
while pNode.next: # 如果该节点没有右子树,则找第一个当前节点时父节点左孩子的节点
if pNode.next.left==pNode:
return pNode.next
pNode=pNode.next # 沿着父节点向上遍历
return
class Solution:
def isSymmetrical(self,pRoot):
if not pRoot:
return True
return self.recursiveTree(pRoot.left,pRoot.right)
def recursiveTree(self,left,right):
if not left and not right:
return True
if not left or not right:
return False
if left.val==right.val:
return self.recursiveTree(left.left,right.right) and self.recursiveTree(left.right,right.left)
return False
class Solution:
def print(self,pRoot): 1
if pRoot==None:
return [] 2 3
stack1=[pRoot] # 奇数栈 4 5 6 7
stack2=[] # 偶数栈
result=[]
while stack1 or stack2:
ret1=[] # 用来暂时存储各层节点的值
ret2=[] # 用来暂时存储各层节点的值
while stack1:
node=stack1.pop()
# 先左后右入偶数栈2
if node.left:
stack2.append(node.left)
if node.right:
stack2.append(node.right)
ret1.append(node.val)
# 上述while循环结束后,二叉树的所有节点就都按照先左后右的顺序进入了偶数栈
# 并且各层节点的值都存入了ret1
if len(ret1)!=0:
result.append(ret1)
while stack2:
# 先右后左入栈1
node=stack.pop()
if node.right:
stack1.append(node.right)
if node.left:
stack1.append(node.left)
ret2.append(node.val)
if len(ret2)!=0:
result.append(ret2)
return result
#-----------------------------------------------------------------
# 第一个while循环开始,stack1里面的内容是[root],将其pop出来 node=stack1.pop()
# 经过第一个while循环后stack2里面的内容是[2,3],然后将node里面的内容存入ret1 ret1.append(node.val)
# result.append(ret1) 其实添加的是根节点列表,此时的result里面的内容[[root.val]]
# 然后开始第二个while循环,经过第一个while循环后,stack2里面已经有了内容,将其pop出,注意,这里的pop是尾取,也就是说,先拿[3],然后判断3是否存在右,左子树,并将其放入stack1,在这里需要特别注意,因为奇数层需要反向输出,所以先存入的是右节点,所以经过第二个while循环后,stack1里面的内容[7,6,5,4]
# ret2里面的内容是[3,2],此时result里面的内容[[1],[3,2]]
# 然后最外层循环的判定条件是stack1 or stack2不为空,此时stack1里面仍有内容为[7,6,5,4]
# 一次尾取pop,放入ret1,此时ret1内容为[4,5,6,7],存入result
# 整个循环结束后,result内容为[[1],[3,2],[4,5,6,7]]
题目:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行
思路:二叉树的广度遍历,将每一行节点放入一个列表,append到一个结果列表即可
采用队列,每次头取队列中的节点pop,如果该节点存在左,右子树,则尾加到队列
class Solution:
def Print(self,pRoot):
result=[]
nqueue=[pRoot]
if not pRoot:
return []
while nqueue:
temp=[]
# 这一步的循环是将当前队列的所有元素存入临时列表
for ele in nqueue:
temp.append(ele.val)
# 这一步是最重要的,每次遍历的都是当前队列的长度,保证能将当前队列里的所有节点取出,并将其中节点的左右子节点加入队列
for i in range(len(nqueue)):
node=nqueue.pop(0)
if node.left:
nqueue.append(node.left)
if node.right:
nqueue.append(node.right)
result.append(temp)
return result
题目:请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树
思路:根据二叉树的广度遍历和深度遍历的任意一种方式,将二叉树的所有节点变成一个只有值的列表,其中空值用 “#” 表示,然后,再根据序列化的方式,还原二叉树,类似于二叉树的重建(第四题),这里采用先序遍历的方式实现,字符串间用’,‘ 隔开
class Solution:
def Serialize(self,root):
if not root:
return '#'
return str(root.val)+','+self.Serialize(root.left)+','+self.Serialize(root.right)
def Deserialize(self,s):
list=s.split(',')
return self.deserializerTree(list)
def deserializerTree(self,list):
if len(list)<=0:
return None
val=list.pop(0)
root=None
if val!='#':
root=TreeNode(int(val))
root.left=self.deserializerTree(lsit)
root.right=self.deserializerTree(list)
return root
class Solution:
count=0
def KthNode(self,pRoot,k):
if not pRoot:
return None
node=self.KthNode(pRoot.left,k)
if node:
return node
self.count+=1
if self.count==k:
return pRoot
node=self.KthNode(pRoot.right,k)
if node:
return node
class Solution:
data=[]
def Insert(self,num):
self.data.append(num)
self.data.sort()
def GetMedian(self,data):
length=len(self.data)
if length%2==0:
return self.data[int(length)//2]
else:
return (self.data[length//2]+self.data[length//2-1])/2
class Solution:
def maxInWindows(self,num,size):
if size<=0:
return []
res=[]
start,end=0,size-1
while end<len(num):
res.append(max(num[start:end+1]))
start+=1
end+=1
return res
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子
a b c e
s f c s
a d e e
矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子
思路:回溯算法
0.根据给定数组,初始化一个标志位数组,初始化为false,表示未走过,true表示已经走过,不能走第二次
1.根据行数和列数,遍历数组,先找到一个与path字符串第一个元素相匹配的矩阵元素,进入判断
2.根据 i 和 j 先确定一维数组的位置,因为给定的matrix是一个一维数组
3.确定递归终止条件:越界,当前找到的矩阵值不等于数组对应位置的值,已经走过的,这三类情况,都直接false,说明这条路不通
4.若k,就是待判定的字符串path的索引已经判断到了最后一位,此时说明是匹配成功的
5.递归不断地寻找周围四个格子是否符合条件,只要有一个格子符合条件,就继续再找这个符合条件的格子的四周是否存在符合条件的格子,直到 k 达到末尾或者不满足递归条件就停止
6.走到这一步,说明本次是不成功的,我们要还原一下表示位数组index处的标志位,进入下一轮判断
class Solution:
def hasPath(self,matrix,rows,cols,path):
# 首先需要明确,输入的矩阵有rows行,cols列
if not matrix:
return False
if not path:
return True
# 创建一个列表,列表中的每个元素是矩阵的每一行,也就是[[x,x,x,x],[x,x,x,x]]的形式
x=[list(matrix[cols*i:cols*i+cols] for i in range(rows))]
# 用一个双for循环遍历整个矩阵,判断矩阵的每个元素是否是path中的元素
for i in range(rows):
for j in range(cols):
# 将 x,i,j,path传入函数,路径是否存在
if self.exits_helper(x,i,j,path):
return True
return False
# 定义一个函数,用来找矩阵中是否存在路径,主要思想是递归
def exist_helper(self,matrix,i,j,p):
# 如果矩阵的第一个元素就是路径的开头,且路径中只有一个元素,返回True
if matrix[i][j]==p[0]:
if not p[1:]:
return True
# 讨论路径不止一个元素的情况,分四种情况
matrix[i][j]=''
if i > 0 and self.exist_helper(matrix,i-1,j,p[1:]):
return True
if i < len(matrix)-1 and self.exist_helper(matrix,i+1,j,p[1:]):
return True
if j > 0 and self.exist_helper(matrix,i,j-1,p[1:]):
return True
if j < len(matrix[0])-1 and self.exist_helper(matrix,i,j+1,p[1:]):
return True
matrix[i][j]=p[0]
return False
else:return False
class Solution:
def cutRope(self,number):
if number<2:
return 0
if number==2:
return 1
if number==3:
return 2
count=0
while number>4:
count+=1
number-=3
return 3**count*number
# 将 x,i,j,path传入函数,路径是否存在
if self.exits_helper(x,i,j,path):
return True
return False
# 定义一个函数,用来找矩阵中是否存在路径,主要思想是递归
def exist_helper(self,matrix,i,j,p):
# 如果矩阵的第一个元素就是路径的开头,且路径中只有一个元素,返回True
if matrix[i][j]==p[0]:
if not p[1:]:
return True
# 讨论路径不止一个元素的情况,分四种情况
matrix[i][j]=''
if i > 0 and self.exist_helper(matrix,i-1,j,p[1:]):
return True
if i < len(matrix)-1 and self.exist_helper(matrix,i+1,j,p[1:]):
return True
if j > 0 and self.exist_helper(matrix,i,j-1,p[1:]):
return True
if j < len(matrix[0])-1 and self.exist_helper(matrix,i,j+1,p[1:]):
return True
matrix[i][j]=p[0]
return False
else:return False
## 67.机器人的运动范围(未解决)
* 题目:地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子
* 思路:
## 68.剪绳子
* 题目:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18
* 思路:显然我们不希望最后的绳子有1存在,也就是说,希望绳子的长度>1,假设现在绳子的长度都是由2,3组成,3米的绳子是否还需要再剪一刀变成2米,不用!!因为3米的绳子剪过后,多出1米,对乘法结果来说没有作用,并且n>1,也就是说,最少要剪2刀,所以**我们的最终目的是在这根绳子中尽可能的多剪出3米的绳子,直到绳子的总长度<=4米**
~~~python
class Solution:
def cutRope(self,number):
if number<2:
return 0
if number==2:
return 1
if number==3:
return 2
count=0
while number>4:
count+=1
number-=3
return 3**count*number