1. 二维数组中的查找
从右上到左下 注意while中内容怎么写
class Solution:
# array 二维列表
def Find(self,target, array):
# write code here
rows = len(array) - 1 #行数
cols= len(array[0]) - 1 #列数
i = rows
j = 0
while j<=cols and i>=0: #这里是<=和>=,一开始没习惯这么写
if target<array[i][j]:
i -= 1
elif target>array[i][j]:
j += 1
else:
return True
return False
a = Solution()
print(a.Find(3,[[1,2],[3,5]]))
2. 替换空格
直接用python里的函数replace(old,new)。
法一:
class Solution:
# s 源字符串
def replaceSpace(self, s):
s = s.replace(' ','%20')
return news
a = Solution()
print(a.replaceSpace("as d "))
法二:
class Solution:
# s 源字符串
def replaceSpace(self, s):
news = ''
for j in s:
if j == ' ':
news = news + '%20'
else:
news = news + j
return news
a = Solution()
print(a.replaceSpace("as d "))
反转链表 从尾到头打印链表
1.用stack实现;2.用递归实现,python中,a=[1,2],a=a+[3],则a=[1,2,3]
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
if listNode is None:
return []
return self.printListFromTailToHead(listNode.next)+[listNode.val]
node1=ListNode(10)
node2=ListNode(11)
node3=ListNode(12)
node1.next=node2
node2.next=node3
a = Solution()
print(a.printListFromTailToHead(node1))
重建二叉树
根据根节点,区分左子树、右子树。再分别对中序遍历的左子树右子树做相同操作。前序遍历的位置每次后移一位。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if not pre or not tin: # 并不是None,所以if pre == None or tin == None:这是错的
return None
root = TreeNode(pre.pop(0)) #每次弹出一个
index = tin.index(root.val)
root.left = self.reConstructBinaryTree(pre,tin[:index])
root.right = self.reConstructBinaryTree(pre,tin[index+1:])
return root
S = Solution()
p = S.reConstructBinaryTree([1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6])
print(p.val)
或者改成
root = TreeNode(pre[0])
index = tin.index(root.val)
root.left = self.reConstructBinaryTree(pre[1:index+1],tin[:index])
root.right = self.reConstructBinaryTree(pre[index+1:],tin[index+1:])
也是一样的,因为pre[1:]从1开始,重新进去迭代,就是下一个了。
用两个栈来实现队列
入队:将元素进栈A
出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈;
如果不为空,栈B直接出栈。
class Solution:
def __init__(self):
self.stackA = []
self.stackB = []
def push(self, node):
# write code here
self.stackA.append(node)
def pop(self):
# return xx
if self.stackB:
return self.stackB.pop(0)
elif not self.stackA:
return None
else:
while self.stackA:
self.stackB.append(self.stackA.pop(0)) #可以写pop()或pop(0)
return self.stackB.pop(0)
S = Solution()
S.push(7)
S.push(5)
S.push(4)
print(S.pop())
旋转数组的最小数字
数组中的第一个数大于等于最后一个数,用二分查找,看中间值和第一个数比较,如果比第一个大,那肯定是前面是递增的。
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray)==0:
return 0
if len(rotateArray)==1:
return rotateArray[0]
if len(rotateArray)==2:
if rotateArray[0]<=rotateArray[1]:
return rotateArray[0]
else:
return rotateArray[1]
#start = rotateArray[0]
#stop = rotateArray[len(rotateArray[0])-1]
index = int(len(rotateArray)/2)
middle = rotateArray[index]
if middle>=rotateArray[0] :
return self.minNumberInRotateArray(rotateArray[index:])
else:
return self.minNumberInRotateArray(rotateArray[:index+1])
S = Solution()
p = S.minNumberInRotateArray([3,3,3,1,3])
print(p)
斐波那契数列
不能用递归啊,从上向下不好,要从下向上,知道两个初始值,慢慢推上去
class Solution:
def Fibonacci(self, n):
# write code here
f1=0
f2=1
if n==0:
return 0
elif n==1:
return 1
else:
for i in range(n+1)[2:]:
f = f1+f2
f1 = f2
f2 = f
return f
S = Solution()
p = S.Fibonacci(7)
print(p)
法二:
class Solution:
def Fibonacci(self, n):
result = [0,1]
a=n
while n>=2:
result.append(result[-1]+result[-2]) #不是result=result.append,就是result.append
n=n-1
return result[a]
S = Solution()
p = S.Fibonacci(8)
print(p)
或者:
res = [0,1]
while(len(res)<=n):
res.append(res[-1]+res[-2])
return res[n]
反转链表
不要while pHead.next!=None:
就用while pHead:
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
prev = None
pcur = pHead
while pcur:
tmp = pcur.next #暂存pcur.next
pcur.next = prev #反转
prev = pcur #移到下一位 # 不是prev.next = pcur (.next想成一个指针 指向某处)移动的只有pcur。
#或者想成prev是指针,只有指向的地址变了,它本身没有.next的概念的。
pcur = tmp #移到下一位
return prev #新表头 就是末尾
合并两个排序的链表
这题做了很久,用递归和非递归版本。以下是非递归实现:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
temp = ListNode(None) #或者ListNode(0) 这里可以引用其他的类的,可以在类中引用其他类!
node = temp #不能返回temp,因为temp已经到了末尾,node是一个指针,指向temp的初始地址
#这里很奇怪,写成上面形式,或者 node = ListNode(None) temp = node都可以
while pHead1 or pHead2:
if pHead1==None:
temp.next = pHead2 #注意.next的使用,一开始就这样,忽略了初始的None
break
if pHead2 == None:
temp.next = pHead1
break
else:
if pHead1.val <=pHead2.val:
temp.next = pHead1
pHead1 = pHead1.next
else:
temp.next = pHead2
pHead2 = pHead2.next
temp = temp.next
return node.next #不要初始的第一个自己初始化的结点了
树的子结构
这个题要好好理清楚,多刷几遍。
思路是肯定要用两个函数的,step1.遍历 找到是否有相同的第一个结点,step2.在有第一个相同结点的基础上,才跳进新函数,去分别遍历左子树和左子树匹配,右子树和右子树匹配。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
# write code here
result = False
if pRoot1 and pRoot2:
if pRoot1.val == pRoot2.val:
result = self.zishu(pRoot1,pRoot2)
if result == False:
result = self.HasSubtree(pRoot1.left,pRoot2)
if result == False:
result = self.HasSubtree(pRoot1.right,pRoot2)
return result
def zishu(self,pRoot1,pRoot2):
if pRoot2 == None:
return True
if pRoot1 == None:
return False
if pRoot1.val != pRoot2.val:
return False
return (self.zishu(pRoot1.left,pRoot2.left) and self.zishu(pRoot1.right,pRoot2.right))
二叉树的镜像
交换左右子结点,子节点下的子树也会搬到另一边的。
代码关键点1. return。并不是有return,递归时就要一定要将结果赋给某个变量。
2.self
的使用,temp = TreeNode(0)。一开始用的temp = self.TreeNode(0)。错的。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
if root == None:
return root
if root.left or root.right: #这句话可有可无
temp = TreeNode(0) #这句话可有可无,注意self用法,不写成 self.TreeNode(0)/(None)
temp = root.left
root.left = root.right
root.right = temp
self.Mirror(root.left) #注意 这里返回值,没有赋给某变量。直接执行语句。
self.Mirror(root.right)
return root
顺时针打印矩阵
这个用python还是有点麻烦的,for循环range的使用。还有就是用res.append。这题看答案的,首先要设置top bottom left right。
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
rows = len(matrix)-1 #行
cols = len(matrix[0])-1 #列
left=0
right=cols
top=0
bottom=rows
res = []
while top<=bottom and left<=right:
for i in range(left,right+1):
res.append(matrix[top][i])
for i in range(top+1,bottom+1):
res.append(matrix[i][right])
if top!=bottom: #判断 上等于下的时候,就不需要从右到左再遍历了
for i in range(right-1,left-1,-1): #很复杂 从大到小 这里是left-1而不是left+1
res.append(matrix[bottom][i])
if left!=right: #判断 左等于右的时候,就不需要从下到上再遍历了
for i in range(bottom-1,top,-1): #右边取闭区间top+1,所以这里是top
res.append(matrix[i][left])
left=left+1
right = right-1
top = top+1
bottom = bottom-1
return res
a = Solution()
matrix = [[1,2,3],[4,5,6]]
print(a.printMatrix(matrix))
包含mini函数的栈
栈的问题,都一个一个入栈地分析,要想成初始栈里就有元素,从空栈,一个个压入开始分析。
辅助栈
概念。
错题集:1.self
;2.self.min()
忘记加(),函数记得加括号
class Solution:
def __init__(self):
self.stack = []
self.assist = []
def push(self, node):
# write code here
if not self.min() or node < self.min(): #之前写成self.min,忘记加()了
self.assist.append(node)
else:
self.assist.append(self.min()) #或self.assist.append(self.assist[-1]不过不好
self.stack.append(node)
def pop(self):
# write code here
if self.stack:
self.assist.pop()
return self.stack.pop()
def top(self):
# write code here
if self.stack:
return self.stack[-1]
def min(self):
# write code here
if self.assist:
return self.assist[-1]
栈的压入、弹出序列
class Solution:
def IsPopOrder(self, pushV, popV):
stack, k = [], 0
# write code here
# 用一个辅助栈 保存pushV的元素,重要的是if判断,先判断pushV[i]和popV[k]是否相等
#再判断stack栈顶元素是否和pop[k]相等,相等就pop,k++。
for i in range(len(popV)):
stack.append(pushV[i])
if pushV[i]==popV[k]:
while stack!=[] and stack[-1] == popV[k]:
stack.pop()
k = k+1
if k==len(popV):
return True
return False
pushV = [1,2,3,4,5]
popV = [4,5,3,2,1]
a = Solution()
print(a.IsPopOrder(pushV,popV))
从上往下打印二叉树
BFS广度优先搜索算法,用queue队列,这题我以为要用递归的方法,想的都是递归怎么做,原来可以通过迭代实现,那么,要怎么找完root,找left和right呢?答案是通过一个list,list放的每个元素是treenode,每次读一个,就能依次遍历了。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回从上到下每个节点值列表,例:[1,2,3]
def PrintFromTopToBottom(self, root):
# write code here
if not root:
return []
queue = []
result = []
queue.append(root)
while queue:
node = queue.pop(0)
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
二叉搜索树的后序遍历序列
都要区分开左右子树,核心思想,重点1.怎么区分开。重点2.怎么判断true false
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if sequence==None or len(sequence)<=0:
return False
root = sequence[-1]
for i in sequence:
if i>root:
break
j = sequence.index(i) #左右子树区分点
for ii in sequence[j:]:
if ii < root:
return False
left,right = True, True
if j>0: #之前没写这个判断 不是全部都是右子树 也有左子树 才执行下面一步
left = self.VerifySquenceOfBST(sequence[:j])
if j<len(sequence)-1: #不是全部都是左子树 也有右子树 才执行下面一步 (如果全部都是左子树, j==len(sequence)-1
right = self.VerifySquenceOfBST(sequence[j:-1])
return left and right
二叉树中和为某一值的路径
这题还是没能自己做出来。是dfs搜索,用递归,但不知道怎么用。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
# write code here
res = []
if not root:
return res
path = [root] #保存根节点
sums = [root.val]
def dfs(root): #深度优先搜索的变形,不是用while,而是用递归!
if root.left:
path.append(root.left)
sums.append(root.left.val+sums[-1])
dfs(root.left)
if root.right:
path.append(root.right)
sums.append(root.right.val+sums[-1])
dfs(root.right)
if not root.left and not root.right:
if sums[-1] == expectNumber:
res.append([p.val for p in path])
path.pop()
sums.pop()
dfs(root)
return res
pNode1 = TreeNode(10)
pNode2 = TreeNode(5)
pNode3 = TreeNode(12)
pNode4 = TreeNode(4)
pNode5 = TreeNode(7)
pNode1.left = pNode2
pNode1.right = pNode3
pNode2.left = pNode4
pNode2.right = pNode5
S = Solution()
print(S.FindPath(pNode1, 22))
复杂链表的复制
这个很难想,一开始不知道要干什么,思路是如何复制一个链表,要新建结点,复制值、next指针、random指针。
分为三步完成:
一复制每个结点,并把新结点放在老结点后面,如1->2,复制为1->1->2->2
二为每个新结点设置other指针
三把复制后的结点链表拆开
class RandomListNode:
def __init__(self, x):
self.label = x
self.next = None
self.random = None
class Solution:
# 返回 RandomListNode
def Clone(self, pHead):
# write code here
if not pHead:
return None
def clonenext(pHead): #在def里又定义def,不能再加self了
node = pHead
while node:
clone = RandomListNode(0) #是一个结点 创建一个个结点
clone.label = node.label
clone.next = node.next
node.next = clone
node = clone.next
def clonerandom(pHead):
node = pHead
while node:
clone = node.next
if node.random:
clone.random = node.random.next
node = clone.next
def separate(pHead): #法一 自己写的
node = pHead
clone1 = node.next
while node:
clone = node.next
if not clone.next:
node.next = None
clone.next = None
return clone1
node.next = clone.next
node = node.next
clone.next = node.next
def ReconnectNodes(pHead): #法二 剑指offer上的
pNode = pHead
pClonedHead = pClonedNode = pNode.next
pNode.next = pClonedHead.next
pNode = pNode.next
while pNode:
pClonedNode.next = pNode.next
pClonedNode = pClonedNode.next
pNode.next = pClonedNode.next
pNode = pNode.next
return pClonedHead
clonenext(pHead)
clonerandom(pHead)
return separate(pHead)
node1 = RandomListNode(1)
node2 = RandomListNode(3)
node3 = RandomListNode(5)
node1.next = node2
node2.next = node3
node1.random = node3
S = Solution()
clonedNode = S.Clone(node1)
print(clonedNode.random.label)
二叉搜索树与双向链表
用list存每个结点
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def Convert(self, pRootOfTree): #中序遍历 right:前向链表 left:后向链表
# write code here
if not pRootOfTree: #一开始没写
return
a, b = [], []
def zhongxu(root):
if not root:
return
if pRootOfTree.left:
zhongxu(root.left)
a.append(root) #访问根结点
if root.right:
zhongxu(root.right)
zhongxu(pRootOfTree)
for i in range(len(a))[:-1]:
a[i].right = a[i+1]
for i in range(len(a))[1:]:
a[i].left = a[i-1]
return a[0] #返回是a[0],而不是返回a
#法二:l
for i,v in enumerate(self.arr[:-1]):
v.right = self.arr[i + 1]
self.arr[i + 1].left = v
return self.arr[0]
node1 = TreeNode(7)
node2 = TreeNode(5)
node3 = TreeNode(8)
node4 = TreeNode(4)
node5 = TreeNode(6)
node1.left = node2
node1.right = node3
node2.left = node4
node2.right = node5
S = Solution()
print(S.Convert(node1))
递归核心思想:可以写成诸如f(n) = f(n+*) ….的表达式
数组中出现次数超过一半的数字
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
for i in numbers:
if numbers.count(i)>len(numbers)/2:
return i
return 0
S = Solution()
print(S.MoreThanHalfNum_Solution([1,2,3,2,2,2,5,4,2]))
## 连续子数组的最大和
这题有两种解法,一种是我们熟知的动态规划算法,还有一种挺巧妙的,看的剑指 offer里的。
法一:
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
a = False
if not array:
a = True
return 0
a = False
cur = 0
Sum = -1000
for i in array:
if cur <= 0: #cur<=0 说明前面累加的白加了,可以从下一个重新加起
cur = i
else:
cur = cur + i
if cur > Sum:
Sum = cur
return Sum
S = Solution()
print(S.FindGreatestSumOfSubArray([-3,5,-2]))
法二:动态规划!!!!!!一定要会啊
f[i]表示以i结尾的子数组的最大和,只需求出max(f[i]),递归公式:
f[i] = array[i] ( f[i-1]<=0 ) #前面累加小于0,所以不要前面的了,只保留最后这个
f[i] = array[i] + f[i-1] ( f[i-1>0] )
解法:
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
f = [None]*len(array) #不能写f = np.zeros(len(array),在开头import numpy as np,牛客网不支持import numpy
f[0] = array[0]
for i in range(len(array))[1:]:
if f[i-1]<=0:
f[i] = array[i]
else:
f[i] = array[i] + f[i-1]
return max(f)
整数中1出现的次数(从1到n整数中1出现的次数)
参考http://www.cnblogs.com/qiaojushuang/p/7780445.html
对于1-9,10-99,100-999,每个n位数中包含1的个数公式为:
f(1) = 1
f(2) = 9 * f(1) + 10 ** 1
f(3) = 9 * f(2) + 10 ** 2
f(n) = 9 * f(n-1) + 10 ** (n-1)
n位数一共的1个数:
s(1) = f(1)
s(2) = 9*s(1)+ 10 ** 1 + s(1)
s(3) = 9*s(2)+ 10 ** 1 + s(2)
高位数:分两种:
1.最高位==1时,最高位为1时的次数(eg.12345)为:2346次(联想:10000-19999的次数为9999+1,因此12345的次数为2346)
2.最高位>1时,最高位为1 时的次数(eg.22345)为):10000次,因为包含了最高位为1时所有可能(当最高位为1时)。
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
if n < 10:
return 1 if n >= 1 else 0
#判断最高位为1时,1的个数
gaowei = int(str(n)[0])
weishu = len(str(n))
if gaowei == 1:
high = n - (10**(weishu-1))* gaowei + 1 #这个加1别忘了
#high1 = high
else:
high = 10**(len(str(n))-1)
def fn(n):
if n <= 0:
return 0
if n == 1:
return 1
current = 9 * fn(n-1) + 10 ** (n-1)
return fn(n-1) + current #这步很重要
"""
def sum1(n): #记录f(n)的和 #我自己写的,错误的fn
if n <= 0:
return 0
def fn(n): # n :位数
if n <= 0:
return 0
if n == 1:
return 1
if n > 1:
return fn(n-1)*9 + 10**(n-1)
summ=0
for i in range(n+1)[1:]:
summ = summ + fn(i)
"""
low = fn(weishu-1) * gaowei
return high+low+ self.NumberOf1Between1AndN_Solution(n - gaowei * 10 ** (weishu-1))
S = Solution()
print(S.NumberOf1Between1AndN_Solution(13))
把数组排成最小的数
这题和“字符串的排列”那题是一样的,都是全排列。
把数组变成一串数字:int(''.join([str(t) for t in arrSs]))
class Solution:
def PrintMinNumber(self, numbers):
if not numbers:
return ""
def Permutation(startIdx):
if startIdx >= len(arrSs):
clone = int(''.join([str(t) for t in arrSs]))
res.append(clone)
else:
changeIdx = startIdx
while changeIdx < len(arrSs):
arrSs[changeIdx], arrSs[startIdx] = arrSs[startIdx], arrSs[changeIdx]
Permutation(startIdx + 1)
arrSs[changeIdx], arrSs[startIdx] = arrSs[startIdx], arrSs[changeIdx]
changeIdx += 1
res = []
arrSs = numbers
Permutation(0)
res = list(set(res))
return min(sorted(res))
S = Solution()
print(S.PrintMinNumber([12,34,56]))
法二:拼接成的数组mn和nm比较,马上能得出大小(cmp的用法)。拼接用字符串拼接(数字转换成字符串)。
from functools import cmp_to_key
def cmp(a, b):
return int(str(a)+str(b)) - int(str(b)+str(a))
def print_mini(nums):
if not nums:
return
print (int(''.join([str(num) for num in sorted(nums, key=cmp_to_key(cmp))])))
if __name__ == '__main__':
test = [3,32,321]
print_mini(test)
丑数
这题很巧妙。下次要再做一次才行。下面是看别人的答案
class Solution:
def GetUglyNumber_Solution(self,n):
if n <= 0:
return 0
ugly = [1]
t2, t3, t5 = 0, 0, 0 # 分别标记乘以2,3,5的丑数索引
while n > 1:
while ugly[t2] * 2 <= ugly[-1]:
t2 += 1
while ugly[t3] * 3 <= ugly[-1]:
t3 += 1
while ugly[t5] * 5 <= ugly[-1]:
t5 += 1
ugly.append(min([ugly[t2]*2, ugly[t3]*3, ugly[t5]*5]))
n -= 1
return ugly[-1]
数组中的逆序对
归并排序的变形。注意count,设置全局变量,在class外,挺巧妙的。(在牛客网上不能在规定时间内执行完,归并+递归的复杂度还是比较高)
count = 0
class Solution:
def InversePairs(self, data):
global count
def merge_sort(lists):
if len(lists) <= 1:
return lists
global count
def merge(left, right):
global count
i, j = 0, 0
result = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
count += len(left)-i #right[j]比left[i]小,就比left剩余的都小,因为left是排好序的了
result += left[i:]
result += right[j:]
return result
# 归并排序
num = len(lists) >> 1
left = merge_sort(lists[:num])
right = merge_sort(lists[num:])
return merge(left, right)
merge_sort(data)
return count%1000000007
两个链表的第一个公共结点
链表问题,出发点1.长度;2.双指针
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
p1, p2 = pHead1, pHead2
n1, n2 = pHead1, pHead2
l1, l2 = 0, 0
while p1:
l1+=1
p1 = p1.next
while p2:
l2+=1
p2 = p2.next
if l1>l2:
s = l1-l2
while s:
s-=1
n1 = n1.next
else:
s = l2 - l1
while s:
s -=1
n2 = n2.next
while n2:
if n1 == n2:
return n1
n1 = n1.next
n2 = n2.next
Node1 = ListNode(0)
Node2 = ListNode(1)
Node3 = ListNode(2)
Node1.next = Node2
Node2.next = Node3
Node4 = ListNode(4)
Node5 = ListNode(1)
Node4.next = Node5
Node5.next = Node2
S = Solution()
print(S.FindFirstCommonNode(Node1,Node4).val)
二叉树的深度
这题看了剑指 offer的讲解,太巧妙了,哎,自己写不出来。
我一直在考虑的都是只有左子树或只有右子树时,深度加1。
没考虑到左右子树都有的时候,要考虑二者的深度大小对比了,二者都有的情况下,左深度大于右边深度,深度为左子树+1!反之亦然。
class Solution:
def TreeDepth(self, pRoot):
# write code here
if not pRoot:
return 0
nl = self.TreeDepth(pRoot.left)
nr = self.TreeDepth(pRoot.right)
if nl > nr:
return nl+1
else:
return nr+1
或者直接写成:
def maxDepth(p):
if not p:
return 0
return 1 + max(maxDepth(p.left),maxDepth(p.right))
平衡二叉树
看的牛客网其他人的回答。
方法一:自顶向下,对于每个节点,都计算一下左子树以及右子树的深度差的绝对值,即每个节点都判断一下。(借鉴了上一题)
算法复杂度为O(N*2)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def IsBalanced_Solution(self, p):
if p is None:
return True
left = self.depth(p.left)
right = self.depth(p.right)
return abs(left - right) <=1 and self.IsBalanced_Solution(p.left) and self.IsBalanced_Solution(p.right)
def depth(self, p):
if p is None:
return 0
return 1 + max(self.depth(p.left), self.depth(p.right))
方法二:自下往上
算法复杂度O(N)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def IsBalanced_Solution(self, p):
return self.dfs(p) != -1
def dfs(self, p):
if p is None:
return 0
left = self.dfs(p.left)
if left == -1:
return -1
right = self.dfs(p.right)
if right == -1:
return -1
if abs(left - right) > 1:
return -1
return max(left, right) + 1
递增数组,和为某个数字
复杂度O(n)
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array,target):
i,j=0,len(array)-1 #两指针 指向头和尾
res = []
while i<j:
if array[i]+array[j]==target:
res.append([array[i],array[j]])
i += 1
j -= 1
if array[i]+array[j] > target:
j -= 1
if array[i]+array[j] < target:
i +=1
return res
和为S的连续整数序列
这题看了剑指 offer的讲解,
class Solution:
def FindContinuousSequence(self, tsum):
# write code here
i, j = 1, 2
summ = [1,2]
res = []
while i < (1+tsum)>>1:
temp = sum(summ)
if temp == tsum:
b=[]
for ii in summ: #这里注意 不能直接res.extend([summ]),这样下面的summ改变了,res里头的元素也会跟着改变。
b.append(ii)
res.extend([b])
j+=1
if j>=tsum:
break
summ += [j]
continue
if temp < tsum:
j+=1
summ+=[j]
continue
if temp > tsum:
summ = summ[1:]
i+=1
return res
翻转的单词顺序列
class Solution:
def ReverseSentence(self, s):
# write code here
b = s.split(' ') #python中,''和""是等价的 #之前一直写的s.split()就不行,是按照""的空格区分的
b.reverse() #或者写成[::-1]
str1 = ''
str1 = ' '.join(b)
return str1
孩子们的游戏(圆圈中最后剩下的数)约瑟夫环??
这题好难,想用直接法,复杂度O(m*n)的方法,都没做出来。
看了剑指 offer的解析,映射的,很难想到。
# 牛客网显示maximum recursion depth exceeded 未完全AC
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n < 1:
return -1
if n==1:
return 0
else:
return (self.LastRemaining_Solution(n-1,m)+m)%n
#用迭代做
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n < 1 or m < 1:
return -1
if n==1:
return 0
last = 0 # n=1时,返回0
for i in range(n+1)[2:]:
last = (last + m)%i
return last
不用加减乘除做加法
python要进行越界检查 & 0xFFFFFFFF
正负数检查 num1 if num1<=0x7FFFFFFF else ~(num1^0xFFFFFFFF)
class Solution:
def Add(self, num1, num2):
# write code here
while num2:
summ = num1 ^ num2
carry = (num1 & num2)<<1
num1 = summ & 0xFFFFFFFF
num2 = carry & 0xFFFFFFFF
return num1 if num1<=0x7FFFFFFF else ~(num1^0xFFFFFFFF)
把字符串转换成整数
要点在于如何把str转换成int型。
设置一个number = ['0','1','2','3','4','5','6','7','8','9']
然后number.index(i)
,比如i是 ‘1’,返回对应的下标1,这个是int型,很巧妙。
class Solution:
def StrToInt(self, s):
# write code here
if not s:
return 0
if len(s)==1:
if s <= '0' or s >= '9':
return 0
lable = 1
start = 0
if s[0] == '+' :
lable = 1
start = 1
if s[0] == '-':
lable = -1
start = 1
summ = 0
number = ['0','1','2','3','4','5','6','7','8','9']
for i in s[start:]:
if i <= '0' or i >= '9':
return 0
summ = summ*10 + number.index(i)
return summ*lable
数组中重复的数字
这题一开始写成if a[i] in a
这是错的,因为一开始a[i]还没赋值,也就没有等不等于的概念。这里in a
就是在a.keys
中搜索。
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
# write code here
a={}
for i in numbers:
if i in a:
duplication[0] = i
return True
a[i] = 1
return False
构建乘积数组
这题脑回路好难,必须要看答案。
class Solution:
def multiply(self, A):
if A == None or len(A) <= 0:
return
length = len(A)
aList = [1] * length
for i in range(1, length):
aList[i] = aList[i-1] * A[i-1]
temp = 1
for i in range(length-2, -1, -1):
temp *= A[i+1] #一开始不懂为什么要设置temp
aList[i] *= temp
return aList
之所以要设置temp。分成两个矩阵,左边C[i]=C[i-1]*A[i-1]
,右边D[i]=D[i+1]*A[i+1]
解析(看的https://www.nowcoder.com/questionTerminal/94a4d381a68b47b7a8bed86f2975db46)
链接:https://www.nowcoder.com/questionTerminal/94a4d381a68b47b7a8bed86f2975db46
来源:牛客网
对于第一个for循环
第一步:b[0] = 1;
第二步:b[1] = b[0] * a[0] = a[0]
第三步:b[2] = b[1] * a[1] = a[0] * a[1];
第四步:b[3] = b[2] * a[2] = a[0] * a[1] * a[2];
第五步:b[4] = b[3] * a[3] = a[0] * a[1] * a[2] * a[3];
然后对于第二个for循环
第一步
temp *= a[4] = a[4];
b[3] = b[3] * temp = a[0] * a[1] * a[2] * a[4];
第二步
temp *= a[3] = a[4] * a[3];
b[2] = b[2] * temp = a[0] * a[1] * a[4] * a[3];
第三步
temp *= a[2] = a[4] * a[3] * a[2];
b[1] = b[1] * temp = a[0] * a[4] * a[3] * a[2];
第四步
temp *= a[1] = a[4] * a[3] * a[2] * a[1];
b[0] = b[0] * temp = a[4] * a[3] * a[2] * a[1];
由此可以看出从b[4]到b[0]均已经得到正确计算。
表示数值的字符串
这题看的别人的https://www.nowcoder.com/questionTerminal/6f8c901d091949a5837e24bb82a731f2
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
sign, decimal, hasE = False, False, False #正负号,小数,有没有E
for i in range(len(s)):
if s[i] == 'e' or s[i] == 'E' :
if hasE:
return False
if i == len(s)-1 :
return False
hasE = True
elif s[i] == '+' or s[i] =='-' :
if sign and s[i-1]!='e' and s[i-1]!='E' :
return False
if not sign and i>0 and s[i-1]!='e' and s[i-1]!='E' :
return False
sign = True
elif s[i] == '.' :
if decimal or hasE:
return False
decimal = True
elif s[i] > '9' or s[i] < '0' :
return False
return True
链表中环的入口结点
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
p1, p2, p3 = pHead, pHead, pHead
while p1:
if not p1 or not p2 or not p1.next or not p1.next.next:
return None
p1 = p1.next
p2 = p2.next.next
if p1 == p2:
break
while p1:
if p1 == p3: #一开始把这个判断写在下面了,应该写在开头。
return p1
p1 = p1.next
p3 = p3.next
pNode1 = ListNode(1)
pNode2 = ListNode(2)
pNode3 = ListNode(3)
pNode4 = ListNode(4)
pNode1.next = pNode2
pNode2.next = pNode3
pNode3.next = pNode4
pNode4.next = pNode1
S = Solution()
print(S.EntryNodeOfLoop(pNode1))
删除链表中重复的结点
这题想用之前写过的“在O(1)内删除链表结点”的思想,写了半天也没写出来。
看了牛客网上的:
链接:https://www.nowcoder.com/questionTerminal/fc533c45b73a41b0b44ccba763f866ef
用递归做,还是比较巧妙的。
public ListNode deleteDuplication(ListNode pHead) {
if (pHead == null || pHead.next == null) { // 只有0个或1个结点,则返回
return pHead;
}
if (pHead.val == pHead.next.val) { // 当前结点是重复结点
ListNode pNode = pHead.next;
while (pNode != null && pNode.val == pHead.val) {
// 跳过值与当前结点相同的全部结点,找到第一个与当前结点不同的结点
pNode = pNode.next;
}
return deleteDuplication(pNode); // 从第一个与当前结点不同的结点开始递归
} else { // 当前结点不是重复结点
pHead.next = deleteDuplication(pHead.next); // 保留当前结点,从下一个结点开始递归
return pHead;
}
}
对称的二叉树
这题做出来了,开心。重点在于新建的’#’结点,这个想得比较久。
class Solution:
def isSymmetrical(self, pRoot): #中序遍历 以根节点为中心,对称
# write code here
a = []
def zhongxu(pRoot):
if not pRoot:
#newNode = TreeNode('#')
#a.append(newNode.val)
return
if pRoot.left and not pRoot.right:
pRoot.right = TreeNode('#')
elif pRoot.right and not pRoot.left:
pRoot.left = TreeNode('#')
zhongxu(pRoot.left)
a.append(pRoot.val)
zhongxu(pRoot.right)
zhongxu(pRoot)
lens = len(a)
for i in range(lens>>1):
if a[i] != a[lens-1-i]:
return False
return True
按之字形顺序打印二叉树
是层次遍历的变形,我知道的,但还是没能写出来。每次打印一层,不要全部一起打印。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 存储点的时候按照奇数层和偶数层分别存储
def Print(self, pRoot):
if not pRoot:
return []
result, nodes = [], [pRoot]
right = True
while nodes:
curStack, nextStack = [], []
if right:
for node in nodes:
curStack.append(node.val)
if node.left:
nextStack.append(node.left)
if node.right:
nextStack.append(node.right)
else:
for node in nodes:
curStack.append(node.val)
if node.right:
nextStack.append(node.right)
if node.left:
nextStack.append(node.left)
nextStack.reverse()
right = not right
result.append(curStack)
nodes = nextStack
return result
# 转换思路,存储的时候一直从左向右存储,打印的时候根据不同的层一次打印
def zigzagLevelOrder(self, root):
if not root:
return []
level, result, lefttoright = [root], [], True
while level :
nextlevel ,curres = [], []
for node in level:
curres.append(node.val)
if node.left:
nextlevel.append(node.left)
if node.right:
nextlevel.append(node.right)
if not lefttoright:
curres.reverse()
lefttoright = not lefttoright
if curres:
result.append(curres)
level = nextlevel
return result
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()
aList = S.zigzagLevelOrder(pNode1)
print(aList)
矩阵的路径
这题做了大半天也没有完全AC,就差一点了,最后return的逻辑有问题。
最后看的牛客网讨论区的答案。
考虑的点:
1. 不能回到之前经历过的元素,所以要设置一个判断,比如访问过的设为1。并且之后还要复原,比如重新设为0.
2. 递归没有true,能返回到上一个点,又开启新一条路径,我就是在这里始终卡住的。总结就是要设置给false的判断,不能一味地if什么时候为true,还要判断什么时候为false。
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
flag = [None]*len(matrix)
def helper(matrix, rows, cols, i, j, path, k, flag):
index = i * cols + j
if i<0 or i>=rows or j<0 or j>=cols or matrix[index]!=path[k] or flag[index]==1:
return False
if k== len(path) -1:
return True
flag[index] = 1
if (helper(matrix,rows,cols, i-1, j, path, k+1, flag)
or helper(matrix, rows, cols, i + 1, j, path, k + 1, flag)
or helper(matrix, rows, cols, i, j - 1, path, k + 1, flag)
or helper(matrix, rows, cols, i, j + 1, path, k + 1, flag)):
return True
flag[index] = 0
return False
for i in range(rows):
for j in range(cols):
if helper(matrix,rows,cols,i,j,path,0,flag):
return True
return False
或直接写成:
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
flag = [None]*len(matrix)
def helper(matrix, rows, cols, i, j, path, flag):
index = i * cols + j
if i<0 or i>=rows or j<0 or j>=cols or matrix[index]!=path[0] or flag[index]==1:
return False
if len(path)==1:
return True
flag[index] = 1
if (helper(matrix,rows,cols, i-1, j, path[1:], flag)
or helper(matrix, rows, cols, i + 1, j, path[1:], flag)
or helper(matrix, rows, cols, i, j - 1, path[1:], flag)
or helper(matrix, rows, cols, i, j + 1, path[1:], flag)):
return True
flag[index] = 0
return False
for i in range(rows):
for j in range(cols):
if helper(matrix,rows,cols,i,j,path,flag):
return True
return False
a = Solution().hasPath('abcdbdef',2,4,'abb')
print(a)
机器人的运动范围
回溯法。有了上一题“矩阵的路径”的经验,在上一题的基础上更改代码就行了。return还是遇到了问题,这里flag=1之后不用再flag=0,依然是看牛客网讨论区的回答才AC.
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
flag = [0]*rows*cols
count = [0]*rows*cols
#或 flag = [[0 for col in range(cols)] for row in range(rows)] 下面用flag[i][j]
def helper(threshold, rows, cols, i, j, flag, count):
index = i * cols + j
if i < 0 or i >= rows or j < 0 or j >= cols or \
sum(list(map(int,str(i))))+sum(list(map(int,str(j)))) > threshold or \
flag[index] == 1:
return 0
flag[index] = 1
count[index] = 1
helper(threshold,rows,cols, i - 1, j, flag,count)
helper(threshold, rows, cols, i + 1, j, flag,count)
helper(threshold, rows, cols, i, j - 1, flag,count)
helper(threshold, rows, cols, i, j + 1, flag,count)
return count
summ = helper(threshold, rows, cols, 0, 0, flag,count)
if summ == 0:
return 0
else:
return sum(summ)
牛客网上:
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
flag = [0]*rows*cols
#flag = [[0 for col in range(cols)] for row in range(rows)]
def helper(threshold, rows, cols, i, j, flag):
index = i * cols + j
if i < 0 or i >= rows or j < 0 or j >= cols or \
sum(list(map(int,str(i))))+sum(list(map(int,str(j)))) > threshold or \
flag[index] == 1:
return 0
flag[index] = 1
return helper(threshold,rows,cols, i - 1, j, flag)+ \
helper(threshold, rows, cols, i + 1, j, flag)+ \
helper(threshold, rows, cols, i, j - 1, flag)+ \
helper(threshold, rows, cols, i, j + 1, flag) +1
return helper(threshold, rows, cols, 0, 0, flag)