class ListNode:
def __init__(self, x):
self.val = x
self.next = None
'''
他让我判断是否有环:
我的想法是:记录,记录,记录,用字典记录(这样查找方便些)
--记录每个变量的内存地址,这样每次遍历的时候查找一遍不挺好?
'''
def fun1(head):
dic={}
while head:
if head in dic:
return True
else:
dic[head]=0#进入字典
head=head.next
return False
'''
他让我用o(1)的空间复杂度,我应激反应出来了,双指针
因为,只能一个方向所以一定是快慢指针? 嗯应该是这样
那么如果没有环,直到head==None slow和quick都不可能指向同一个节点
如果有环,那么quick和slow是可以指向同一节点的
--因为quick跑的太快又回来了
'''
'''
重点:
如何设计可以使有环的时候,quick一定可以追上slow
这里可以看一下:floyd判环(圈)算法,我没详细看,反正就是一定能追上只要quick比slow快,且有圈
就先理解成套圈吧
'''
p1=ListNode(1)
def fun2(head):
if head == None or head.next == None:
return False
s = head
q = head.next
while q and q.next: # 这里写个q是为了防止当前q是倒数第二个,然后q=q.next.next得到了None这样的话q.next会报错
if q == s:
return True
q = q.next.next # 跑两步
s = s.next # 跑一步
return False
print(fun2(p1))
====================================================================================================================================================================================================================================
104. 二叉树的最大深度
'''
'''
哈哈,这个题目我有印象,当时死搞搞了两个多小时,非要尼玛用栈模仿递归
'''
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
'''
广度优先遍历
这种遍历就是,一层一层的遍历树,可以用队列来
'''
def fun1(root):#这个函数的运行结果和这个题目没什么关系,只是从上到下,从左到右进行输出而已
duilie=[]
while duilie or root:#当前节点不为空,或者
if root.left:
duilie.append(root.left)
if root.right:
duilie.append(root.right)
print(root.val)
root=duilie.pop(0)
def fun2(root):#这个的层次更加鲜明,循环里面嵌套循环,嵌套循环用来表示一层,然后顺带着可以算出最大深度
if root==None:
return 0
duilie=[root]
dade=[]
while duilie:#队列不为空进来
size=len(duilie)#获得当前队列长度,相当于一层的个数
ls=[0]*size
for i in range(size):
node=duilie.pop(0)
if node.left:
duilie.append(node.left)
if node.right:
duilie.append(node.right)
ls[i]=node.val
#循环结束
dade.append(ls)
return len(dade)
'''
既然是二叉树,递归就是不可或缺的一部分
那我们来看看递归怎么做?
--1+max(fun3(root.left),fun3(root.right))
你不觉得很好吗?
当前位置是一层+左子树或右子树的最大值,这样不就是最大深度
'''
def fun3(root):
if root==None:
return 0
return 1+max(fun3(root.left),fun3(root.right))
====================================================================================================================================================================================================================================
98. 验证二叉搜索树
'''
二叉搜索树的定义:
--当前节点的左子树只含有小于当前节点的数
--当前节点的右子树只含有大于当前节点的数
--所有的左右子树也为二叉搜索树
二叉搜索树有一个性质:
中序遍历一定是有序的
那么中序遍历有序,可不可以得到该二叉树是二叉搜索树
可以
'''
'''
方法一:
先中序遍历,再判断是否为有序
这个的时间复杂度怎么说呢
中序遍历o(n) 排序o(n*logn)当然这里需要动的并不多,可以达到o(n)不过我不知道python排序的快速排序怎么写的
比较o(n)
时间复杂度:
开了两个列表
'''
'''
这里其实写,非递归的中序遍历更好,因为可以直接在这个过程中比较
'''
class Solution:
def isValidBST(self, root) -> bool:
ls=[]
self.digui(root,ls)
#这样ls里面的就是中序遍历的结果
li=ls.copy()
li.sort()
for i in range(len(li)):
if i+1<len(li) and li[i]==li[i+1]:
return False#这里是因为它这个定义的二叉排序树不允许出现重复元素
if li[i]!=ls[i]:
return False
return True
def digui(self,root,ls):
if root==None:
return
self.digui(root.left,ls)
ls.append(root.val)
self.digui(root.right,ls)
'''
我觉得有一种相对上面这样写更好的方法,再遍历的过程中找到左子树的最大值,右子树的最小值,然后与当前节点比较
哈哈哈,这是看答案写的不是很理解
过程有点理不清了
'''
class Solution:
def isValidBST(self, root) -> bool:
return self.bianli(root,float('-inf'),float('inf'))
def bianli(self,root,lower,upper):#这里是当前节点,左子树的最大值,右子树的最小值
if root==None:
return True
val=root.val
if not lower<val<upper:
return False#我可以直接return掉
if not self.bianli(root.left,lower,val):
return False#该当前节点的左子树了
if not self.bianli(root.right,val,upper):
return False
return True
====================================================================================================================================================================================================================================
48. 旋转图像
#妈蛋,看错提了,操蛋
'''
这个题目让我原地:
就是说不开辟额外空间来完成这个题目
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
3,0 3,1 3,2 3,3
这样的话就是:
0,0-->0,3 1,0-->0,2
0,1-->1,3 1,1-->1,2
0,2-->2,3 1,2-->2,2
0,3-->3,3 1,3-->3,2
可以观察到,前面的行和后面的列的和是一个定值n
然后前面的列变为了后面的行
但是:
我有一个问题没有注意到:
我在这个过程中更改了列表,如果我没有更改列表,那么确实可以这样
就是说我再拿一个列表,进行一下copy()以他作为参考
所以我现在应该怎么办?
我想明白了
0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
为了让原地的更改影响不到其他人,我就一圈一圈的转
0,0-->0,2 0,2-->2,2 2,2-->2,0 2,0-->0,0
0,1---------------------------------------都是这样
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
3,0 3,1 3,2 3,3
0,0-->0,3 0,3-->3,3
'''
def fun1(matrix):
n=len(matrix)-1
i=0
z=0
while i<n+1-z:
j=z
while j<n-i:
t1=matrix[i][j]
t2=matrix[j][n-i]
t3=matrix[n-i][n-j]
t4=matrix[n-j][i]
matrix[j][n-i]=t1
matrix[n-i][n-j]=t2
matrix[n-j][i]=t3
matrix[i][j]=t4
j+=1
z+=1
i+=1
print(matrix)
fun1([[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]])
#fun1是直接旋转
#还可以这样,先水平旋转,再对角线反转
def fun2(matrix):
#先水平反转
n=len(matrix)-1
mid=(0+n)//2
i=0
while i<=mid:
matrix[i],matrix[n-i]=matrix[n-i],matrix[i]
i+=1
for i in range(n+1):
for j in range(i,n+1):
t=matrix[i][j]
matrix[i][j]=matrix[j][i]
matrix[j][i]=t
print(matrix)
fun2([[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]])
====================================================================================================================================================================================================================================
101. 对称二叉树
'''
这个就是给定一个二叉树,判断他是否是对称的(这种对称是关于y轴对称)
我觉得这个需要你去了解,关于树的遍历,无论是递归还是非递归
因为你必须去遍历树
我认为遍历是两种方式
左右根
以及右左根
'''
'''
递归代码:关于树的遍历的递归代码是非常简单的
'''
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
'''
非递归代码的层序遍历
'''
def fun1(root):
if not root:
return []
duilie=[root]
ll=[]
while duilie:
ls = []
size = len(duilie)
for i in range(size):
item = duilie.pop(0)
ls.append(item.val)
if item.left:
duilie.append(item.left)
if item.right:
duilie.append(item.right)
ll.append(ls)
return ll
'''
那么我们可以更改一下层序遍历让他变得可用
'''
'''
这个代码有问题,越写越麻烦
'''
def fun2(root):
if not root:
return []
duilie=[root]
duitou=0
jishu=0
z=[1]
while duilie:
size = len(duilie)
duiwei=size-1
duitou+=jishu
dui=duitou
#第一次循环,先只看一下
while dui<=duiwei:
left=duilie[dui]
right=duilie[duiwei]
if left.val!=right.val:
return False
dui+=1
duiwei-=1
jishu=0
for i in range(duitou,size):
item = duilie[i]
if item.left:
duilie.append(item.left)
z.append(item.left.val)
jishu+=1
if item.right:
duilie.append(item.right)
z.append(item.right.val)
jishu+=1
return True
root=TreeNode(1)
root.left=TreeNode(2)
root.right=TreeNode(2)
root.left.left=TreeNode(3)
root.left.right=TreeNode(4)
root.right.left=TreeNode(4)
root.right.right=TreeNode(3)
print(fun2(root))
====================================================================================================================================================================================================================================
88. 合并两个有序数组
'''
合并两个有序数组,感觉和合并两个有序链表差不多
很简单就有思路了:
假设有两个列表:
[1,2,7,0,0,0](后面的0是为了java等,数组无法自动扩容而多开辟的用来容纳另一个数组)
[2,5,6]
第一次:
1,2比 不动
2,2比 对于等于的 不动
7,2比 对于大于的 换位置 变为[1,2,2] 注意每一次都会查看会不会超出范围
[7,5,6],排个序
超出了,结束
把而放在后面
'''
def fun1(nums1,m,nums2,n):
s=0
l=0
while s<m and l<n:
if nums1[s]>nums2[l]:
nums1[s],nums2[l]=nums2[l],nums1[s]
nums2.sort()
s+=1
for i in range(m,m+n):
nums1[i]=nums2[l]
l+=1
print(fun1([1,2,3,0,0,0],3,[2,5,6],3))
'''
直接放一起一起排序
'''
'''
重新开一个数组,进行储存,都是可以的
'''
====================================================================================================================================================================================================================================
278. 第一个错误的版本
#哈哈哈
'''
这个题目一看就是二分查找的变形
因为在没错之前全是对的,在错了之后全是错的
'''
def isBadVersion(version):
pass
def fun1(n):
if n == 1:
return 1
left = 1
right = n
while left<=right:
mid = (left + right) // 2
if not isBadVersion(mid): # 如果是False证明没问题
left = mid + 1
else:
right = mid - 1
return left#因为最后一次的时候,mid对应的一定是坏的,所以会进入,right=mid-1,这样返回left就好了
def fun2(n):#感觉直接这样空写,好难,就先转列表了
ls=[]
for i in range(1,n+1):
ls.append(i)
left=0
right=n-1
#哈哈哈,写到这里,我突然发现前面哪里写错了
====================================================================================================================================================================================================================================
70. 爬楼梯
'''
这个题目做过了,是个斐波那契数列
1 2 3 4 5 6
1 2 3 5 8
'''
'''
既然知道他是斐波那契数列,那么很明显直接公式走起就可以
'''
'''
动态规划拿两个变量 t和h 通过不断变换得到
'''
'''
递归也可以
'''
def fun1(n):
if n==1 or n==0:
return 1
return fun1(n-1)+fun1(n-2)
====================================================================================================================================================================================================================================
121. 买卖股票的最佳时机
'''
最开始以为这题我做过,后面突然发现,其实没有,我当时做的是买卖股票的最佳时机2
'''
'''
这个题目首先的想法是什么?
顺序查找,就是在当前位置,往后面找的最小的
但很明显,很麻烦时间复杂度很高
'''
'''
所以我们需要转换思路:
我只买一次和卖一次
那一定是买的时候越少,卖的时候越大就好了
那么我就遍历一次查找到最大的和最小的,如果小的在大的左边就可以了,不满足就再来一次
这样的话,如果小的都在大的左边,是很难受的
'''
'''
还是把我以前的方法拿出来吧,从右往左看
这里会放一张截图
'''
def fun1(prices):#哈哈哈最开始想复杂了
max=0
max_hou=0
for i in reversed(range(len(prices))):
if i<len(prices):
t=-prices[i]+max_hou
if prices[i]>max_hou:
max_hou=prices[i]
if max<t:
max=t
else:
max_hou=prices
return max
print(fun1([7,6,4,3,1]))