python leetcode3

141. 环形链表

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]))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值