python leetcoe5

152. 乘积最大子数组

'''
    这个和最大子序和是一样的,只是一个是乘积形式,一个是和的形式
    如果想到达i位置,要不经过i-1位置,要不只取i位置
    那么就出现了[i]+f(i-1)与i比大小的情况
    这里有一个特殊情况:
        如果出现了如果f(i-1)=0
        那么f(i)=[i]
        这里不管[i]是正数还是负数
        因为已经有0的记录了,如果后面全是负数,最大值还是可以归到0身上
        但是如果为了变成最大而改换成0,那么就会导致后面结果出现误差:
        如:  [2,3,0,-2,-4]
            [2,6,0,0,0]  最大值应该是8,但如果计算了0那么就不是这样了


    上面的思路有个问题:
        [-2,3,-4]
        -4位置的最大值为-2*3*-4=24,那么可以知道
        当前位置的最优解未必是由前一个位置的最优解转移得到的。

    所以我想了一下,因为负数和正数以及0的存在,导致了可能负负得正
    以及正上加正
    所以每一次需要记录最小值和最大值
    这样就是 最小值*[cur] 最大值*[cur] [cur]
    本身里面选择
'''

def fun1(nums):#错误写法,只有正上加正得情况,没有负负得正得情况
    max_=nums[0]
    pre=nums[0]
    for i in range(1,len(nums)):
        if pre!=0:
            cur=max(pre*nums[i],nums[i])
        else:
            cur=nums[i]
        if max_<cur:
            max_=cur
        pre=cur
    print(max_)
fun1([2,3,0,-2,-4])

def fun2(nums):#代码通过,所谓动态规划就是大量使用已经计算过的结果
    max_=nums[0]
    pre_max=nums[0]
    pre_min=nums[0]
    for i in range(1,len(nums)):
        cur_max=max(pre_max*nums[i],pre_min*nums[i],nums[i])
        cur_min=min(pre_max*nums[i],pre_min*nums[i],nums[i])
        if max_<cur_max:
            max_=cur_max
        pre_max=cur_max
        pre_min=cur_min
    return max_
print(fun2([]))

===========================================================================================================================================================================
628. 三个数的最大乘积

'''
    首先找出三个数,计算他们的乘积
    然后找出所有的三个数乘积,这是一种全排列,是可以的方法,但当然不是好的方法

    方法一:
        排序+max(最后三个数相乘,最后一个数*第一个数*第二个数)
        因为存在负数情况,那么负数会导致越小乘积越大
        但是不可能是3个负数相乘,所以就取最小的两个负数+最后一个数
'''
def fun1(nums):
    nums.sort()
    max1=nums[-1]*nums[-2]*nums[-3]
    max2=nums[0]*nums[1]*nums[-1]
    if max1<max2:
        return max1
    else:
        return max2


'''
    方法二:
        暴力枚举
    暴力思路:
        假设有一数组  [1,2,3,4,5]
                    [0,1,2,3,4]
    当前数为1,固定2 然后遍历3,4,5
        固定3,然后遍历4,5
        固定4,然后遍历5
    当前数为2,固定3 然后遍历4,5
        固定4 然后遍历5
    当前数为3,固定4 然后遍历5
    
    
'''
def fun2(nums):#92通过了71个,不能通过很正常
    max_=float('-inf')
    for i in range(len(nums)):
        for j in range(i+1,len(nums)):
            cur=j+1
            while cur<len(nums):
                dangqianshu=nums[i]*nums[j]*nums[cur]
                if max_<dangqianshu:
                    max_=dangqianshu
                cur+=1
    return max_

'''
    方法三:
        去他妈的,我以为是动态规划,就是没有动态规划操
    线性扫描:
        排序的目的是什么?找出最小两个数,和最大三个数
        那么很明显,我只需要遍历,然后找到这五个数就好了
'''


===========================================================================================================================================================================
221. 最大正方形

'''
    相邻节点:下标与上一层节点下标相同或者上一层节点下标+1
    如果在当前行的下标为i,那么下一步可以移动到<<下一行>>的下标i,下标i+1

    暴力当然是可以做的,用栈来模拟,记录回来的位置

'''

def fun1(triangle):#答案提交通过
    #经典动态规划,本来是没思路的哈哈哈
    #结果一准备去看答案,就发现了思路
    #动态规划,利用已经出现的计算
    dp=[[0]*i for i in range(1,len(triangle)+1)]
    min_=float('inf')
    dp[0][0]=triangle[0][0]
    for i in range(1,len(triangle)):#行遍历
        dangqianhang=triangle[i]
        for j in range(len(dangqianhang)):#每一次必须走了,不存在跳动的情况
            if j>len(dp[i-1])-1:
                dp[i][j] = dangqianhang[j] + dp[i - 1][j-1]
            elif 0<=j-1:
                dp[i][j]=dangqianhang[j]+min(dp[i-1][j],dp[i-1][j-1])
            else:
                dp[i][j]=dangqianhang[j]+dp[i-1][j]
    min_=min(dp[len(triangle)-1])
    return min_

def fun2(triangle):
    # 上面的代码和答案的思路是一致的,但是答案把代码又优化了一下
    len_ = len(triangle)

    dp = [[0] * i for i in range(1, len_ + 1)]
    dp[0][0] = triangle[0][0]

    for i in range(1, len_):  # 行遍历
        dangqianhang = triangle[i]
        # 如果第一次是最左边的元素,那么j==0,也只有这个会导致j-1溢出
        dp[i][0] = dangqianhang[0] + dp[i - 1][0]
        cd = len(dangqianhang)
        for j in range(1, cd - 1):  # 每一次必须走了,不存在跳动的情况

            dp[i][j] = dangqianhang[j] + min(dp[i - 1][j], dp[i - 1][j - 1])
        # 只有最右边的元素,才会导致j>len(dp[i-1])-1
        dp[i][cd - 1] = dangqianhang[cd - 1] + dp[i - 1][cd - 2]
        min_ = min(dp[len(triangle) - 1])
    return min_

'''
    空间复杂度可以化简,不过对我来说没必要了
    最近都是笔试,面试离我还有一定的距离,就先学会写代码就好
'''
def fun3():
    pass

===========================================================================================================================================================================
221. 最大正方形

'''
    暴力的方法
    怎么暴力?
        先行遍历,将所有的将所有的1筛选出来
        如果出现了连续的1,可以开始列遍历,看是否可以变成一个正方形
'''

def fun1(matrix):
    max_=0#这样的话,在全是0的时候,应该就不需要更替了
    for i in range(len(matrix)):#行遍历
        hang=matrix[i]
        ls=[]
        for j in range(len(hang)):
            if hang[j]=='1':
                ls.append(j)#添加下标
        #开始判断是否有下标相邻
        qishi=ls[0]
        changdu=1
        lingshi=[]
        for xiabiao in range(1,len(ls)):
            if ls[i]-ls[i-1]!=1:
                lingshi.append((qishi,changdu))
                qishi=i
                changdu=1
            changdu+=1
        lingshi.append((qishi,changdu))
        print(lingshi)




def fun2():
    #写着写着我突然想到了一个事情
    #我为什么不直接按行遍历二维表
    #记录所有找到的1的下标
    #然后开始循环遍历?
    #傻逼,给你的不就是这玩意吗?
    pass
def fun3(matrix):#错误代码,主要是在内循环的时候有问题
    #不是我开了那么多空间,里面就需要这么多方块


    #我觉得上面的暴力方法,实现起来不方便
    #那么该怎么办呢?
    #遍历行和列,然后cur(当前位置)如果是1那么就开始  相当于开一个表格 开始循环判断是不是都是1
    hang=len(matrix)
    lie=len(matrix[0])

    max_=0
    for i in range(hang):
        for j in range(lie):
            if matrix[i][j]=='1':
                max_=max(max_,1)#这是因为起始设置的为0,防止全是0
                #开表格
                changdu = min(hang-i, lie-j)

                tingzhi=False

                x=0
                y=0
                while x<changdu:
                    while y<changdu:
                        if matrix[i+x][j+y]!='1':
                            changdu=max(i+x,i+y)
                            break
                        y+=1
                    x+=1
                else:
                    #不是break结束就可以进来
                    if max_<changdu:
                        max_=changdu
    print(max_*max_)





def fun4(matrix):
    hang = len(matrix)
    lie = len(matrix[0])

    max_ = 0
    for i in range(hang):
        for j in range(lie):
            if matrix[i][j] == '1':
                max_ = max(max_, 1)  # 这是因为起始设置的为0,防止全是0
                # 开表格
                changdu = min(hang - i, lie - j)

                for k in range(1, changdu):  # 循环长度次数,每一次都是最外围
                    tingzhi = False
                    for m in range(k + 1):#也可以分两个循环,每次遍历行和列
                        if matrix[i + k][j + m] == '0' or matrix[i + m][j + k] == '0':
                            tingzhi = True
                            break
                    if tingzhi:
                        break
                    else:
                        max_ = max(max_, k + 1)
    print(max_ * max_)


'''
     0 1 1 1 0          0 1 1 1 0
     1 1 1 1 0          1 1 2 2 0
     0 1 1 1 1          0 1 2 3 1
     0 1 1 1 1          0 1 2 3 2
     0 0 1 1 1          0 0 1 2 3
    
    
   
    

    dp[i][j]为一个正方形的右下角(这是为了方便dp,如果是左下角,就从右往左,从上往下遍历)
    
    检查矩阵中当前位置matrix[i][j]
    如果为0 那么不可能为正方形的右下角,也不可能构成数全为1的矩阵
    如果为1 那么那么一定是一个正方形的右下角(最次也是他自己)
        问题是这个正方形会有多大呢?
        min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1
        因为是正方形的原因,所以需要取min
    还有问题
        对于i==0或者j==0的该这么办?
        原封不动,因为不可能组成
'''
def fun5(matrix):#动态规划
    lie=len(matrix[0])
    hang=len(matrix)

    max_=0
    dp=[[0]*lie for i in range(hang)]
    for j in range(lie):
        dp[0][j]=eval(matrix[0][j])
        max_=max(max_,dp[0][j])
    for j in range(hang):
        dp[j][0] = eval(matrix[j][0])
        max_=max(max_,dp[j][0])
    for i in range(1,hang):
        for j in range(1,lie):
            if matrix[i][j]=='0':
                dp[i][j]==0
            else:
                dp[i][j]=min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1
                max_=max(max_,dp[i][j])
    return max_*max_

print(fun5([["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]))

===========================================================================================================================================================================
1277. 统计全为 1 的正方形子矩阵

'''
    这个题目本质上和221. 最大正方形是同一类
'''

'''
     0 1 1 1 0          0 1 1 1 0
     1 1 1 1 0          1 1 2 2 0
     0 1 1 1 1          0 1 2 3 1
     0 1 1 1 1          0 1 2 3 2
     0 0 1 1 1          0 0 1 2 3
    动态规划思路:
        dp[i][j]是正方形的右下角,这是因为遍历是从左往右,从上往下的
        如果当前为matrix[i][j]
        
        如果为0,那么他一定不会是正方形的右下角,也不能参与构建全为1的正方形,所以就记为0
        如果为1,那么就这个样子
            min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+1
        注意:
            像第一行,第一列,一定与原来相同,可以直接先遍历
    
'''
def fun1(matrix):
    hang = len(matrix)
    lie = len(matrix[0])
    dp = [[0] * lie for i in range(hang)]
    count = 0

    for i in range(hang):
        dp[i][0] = matrix[i][0]
        if dp[i][0] == 1:
            count += 1
    for j in range(1, lie):
        dp[0][j] = matrix[0][j]
        if dp[0][j] == 1:
            count += 1
    for i in range(1, hang):
        for j in range(1, lie):
            if matrix[i][j] == 0:
                dp[i][j] == 0
            else:
                dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1
                count += dp[i][j]
    return count

print(fun1([[1,0,1],[1,1,0],[1,1,0]]))

===========================================================================================================================================================================
62. 不同路径

'''
    机器人每次都只能向下和向右走
    所以第一行,一定都只有一种方法到达
    第一列,一定都只有一种方法到达


       0 1 2 3 4 5 6
    0 [0 0 0 0 0 0 0]   像(1,1)这个位置只能是(1,0)和(0,1)移动到,所以
    1 [0 0 0 0 0 0 0]
    2 [0 0 0 0 0 0 0]

    dp[i][j]=dp[i-1][j]+dp[i][j-1]


'''

def fun1(m,n):
    dp = [[1] * n for i in range(m)]
    for i in range(1, m):
        for j in range(1, n):
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
    return dp[m - 1][n - 1]

===========================================================================================================================================================================
63. 不同路径 II

'''
    这个题目比不同路径相比多了一个障碍物的设定
    这个设定会使得你不是每一次位置,都可以走,但其实也没有难多少(只少我现在感觉)
    每次加一个判定,原矩阵[i][j]是否为障碍物



'''
def fun1(obstacleGrid):
    hang=len(obstacleGrid)
    lie=len(obstacleGrid[0])

    dp=[[0]*lie for i in range(hang)]

    #这里有一点需要注意,第一行和第一列都是如果堵了一个后面的全被堵完


    for j in range(lie):
        if obstacleGrid[0][j]==1:
            dp[0][j]=0
            for i in range(j+1,lie):
                dp[0][i]=0
            break
        else:
            dp[0][j]=1
    for i in range(hang):
        if obstacleGrid[i][0]==1:
            dp[i][0]=0
            for j in range(i+1,lie):
                dp[j][0]=0
            break
        else:
            dp[i][0]=1

    for i in range(1,hang):
        for j in range(1,lie):
            if obstacleGrid[i][j]==1:
                dp[i][j]=0
            else:
                dp[i][j]=dp[i-1][j]+dp[i][j-1]
    print(dp)
fun1([[0,0],[1,1],[0,0]])


===========================================================================================================================================================================
64. 最小路径和

'''
    只要看到二维数组+最优解问题,一定就是动态规划
    动态规划干了什么事,通过开辟空间,记录曾经的结果
    并在后续计算中使用
    减少了重复计算次数


    仔细看了一下题目,....
    好吧,好像我这一天做的三个题,都是一个类型的,这样好树立自信心哈哈哈
'''

def fun1(grid):
    start=grid[0][0]
    hang=len(grid)
    lie=len(grid[0])
    dp=[[start]*lie for i in range(hang)]

    for j in range(1,lie):
        dp[0][j]=dp[0][j-1]+grid[0][j]
    for i in range(1,hang):
        dp[i][0]=dp[i-1][0]+grid[i][0]

    for i in range(1,hang):
        for j in range(1,lie):
            dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]
    return dp[hang-1][lie-1]
fun1([[1,3,1],[1,5,1],[4,2,1]])

===========================================================================================================================================================================
119. 杨辉三角 II

'''
    这个杨辉三角
    每一次的结果,都是左上方和右上方的和(存在只有左上方,只有右上方的情况)
    所以很自然的可以想到,动态规划,使用已经得到的结果

'''

def fun1(rowIndex):
    dp=[[1]*i for i in range(1,rowIndex+2)]
    hang=len(dp)
    for i in range(2,hang):#如果行数等于0,1,2不会进来,一会看一下输出结果
        lie=len(dp[i])
        for j in range(1,lie-1):#不对列的两边进行计算,因为不需要
            dp[i][j]=dp[i-1][j]+dp[i-1][j-1]
    return dp[rowIndex]


def fun2(rowIndex):
    #可以看到,上面在当前行,只会使用到其上一行的结果
    #所以可以只保留上一行数组

    #但是这样的话,后面就需要加些判断
    #奥不对,经过我的思考,发现不需要
    pre=[1]
    for i in range(rowIndex):
        cur=[1]*(len(pre)+1)
        for j in range(1,len(cur)-1):#注意第二行是进不来这个循环的
            cur[j]=pre[j]+pre[j-1]
        pre=cur
    return cur


def fun3(rowIndex):
    #这个题目还有一个很好的解法
    #可以达到,常数级的时间复杂度
    #这个放在,CSDN里面了
    n=rowIndex
    ls=[1]
    for m in range(1,n+1):
        ls.append(ls[m-1]*(n-m+1)//m)
    print(ls)
fun3(3)





请添加图片描述

===========================================================================================================================================================================
392. 判断子序列

'''
    好难受,不想想问题


'''

'''
    方法一:
        暴力方法,每次进行查找,返回下标
        
        问题:
            可能存在多个相同字符,不能只返回第一个下标
'''

def fun1(s,t):
    pre=[[] for i in range(len(s))]
    if len(s)==1 and len(t)==1:
        if s==t:
            return True
        return False
    for i in range(len(s)):
        for j in range(len(t)):
            if s[i]==t[j]:
                pre[i].append(j)
    for i in reversed(range(1,len(pre))):
        if pre[i]==[] or pre[i-1]==[] or max(pre[i])<=min(pre[i-1]):
            return False
    return True
print(fun1("aaaaaa","bbaaaa"))

===========================================================================================================================================================================
55. 跳跃游戏

'''
    跳跃游戏:
        --到达该位置,可能不跳吗?
            不可能,因为不跳永远无法到达

'''

'''
    暴力肯定是一种方法,所有可能情况,全部列出来就好了
'''
def fun1(nums):
    #用栈记录走过的路,不断的进行尝试
    stack_xiabiao=[0]#初始下标
    stack_item=[0]#初始下标对应元素

    while stack_xiabiao!=[]:
        if stack_item[-1]<nums[stack_xiabiao[-1]]:
            pass
            #说明可以继续往后面走
    #...
    #大致写一下,肯定需要有细节注意


'''
    我觉得这种思路更好:
        --首先循环遍历,将所有下标可以到达的位置通过二维表进行记录
        --如果没有可以到达最后面位置的下标,就直接返回False
        --如果有,就再次进行判断,当前下标是否有人可以达到
        不断的进行划分,如果可以到达下标0位置则返回True
        否则返回False
'''
def fun2(nums):
    pass


'''
    动态规划
    dp[i][j]
    i代表当前位置,j代表想要到达位置
    dp[i][j]可取值为True或False
    每次到达i位置查找dp[i][j]位置是否为True
'''
def fun3(nums):#超出了时间限制
    if len(nums) == 1:
        return True
    dp = [[False] * len(nums) for i in range(len(nums))]
    j = 1
    while j < len(nums) and j < nums[0] + 1:
        dp[0][j] = True
        j += 1
    for i in range(1, len(nums)):
        for chazhao in range(i):  # 查看0~i-1位置是否有元素可以达到i位置
            if dp[chazhao][i] == True:
                # 可以达到i位置进行替换
                j = 1
                while i + j < len(nums) and j < nums[i] + 1:
                    dp[i][i + j] = True
                    j += 1
                if dp[i][len(nums) - 1] == True:
                    return True

    if dp[0][len(nums) - 1] == True:
        return True
    return False



def fun4(nums):
    #贪心算法,猜测结果哈哈哈
    #维护最大可到达长度
    #循环nums列表,直到遍历最后一个item时最大可到达长度<当前元素下标
    '''
        [2,3,1,1,4]
        第一次:下标为0长度为2,最大可到达下标为2
        第二次:下标为1长度为3,最大可到达下标为4
        第三次:下标为2长度为1,最大可到达下标为3,不进行更改
        第四次:下标为3长度为1,最大可到达下标为4,不进行更改

        不用看了
        第五次:下标为4长度为4,最大可到达下标为4
    '''

    max_ = 0
    for i in range(len(nums)):
        if i <= max_:  # 这里是需要加个判断的,为什么,因为max_是0~i-1位置的最大可以到达长度,那么说不定i位置是前面到不了的
            if i + nums[i] >= max_:
                max_ = i + nums[i]
                if max_ >= len(nums) - 1:
                    return True
    return False
print(fun4([0,2,3]))

===========================================================================================================================================================================
213. 打家劫舍 II

'''
    理解题目:
        --围成一圈,即第一个房子和最后一个房子是紧挨着的
        --两间相邻房间同一晚上被小偷偷,则会报警
        --不触动报警装置,偷取最大金额
    这个题目的变化地方在于0和len(nums)-1位置变成了相邻

    在打家劫舍中,因为没有围成圈,不需要考虑0和len(nums)-1的问题
    所以如果只有一个元素就取他一个就行了
    如果有两个元素,[0]的时候取自己,[1]的时候取[0],[1]中的最大值

    假设待偷数组为nums
    当元素个数>2时
        分为两种情况:
            当前位置偷:nums[i]+dp[i-2]
            当前位置不偷:dp[i-i]
        这样可以得到公式
            dp[i]=max(dp[i-1],dp[i-2]+nums[i])
            每次到达一个位置,都是可以偷的最大值,后面的元素也不会影响前面的结果
            所以如果想要[i]位置最大,一定是在这两种情况里面选


'''

#这个写的是打家劫舍的代码
def fun1(nums):#执行通过
    if len(nums)<=2:
        return max(nums)


    dp = [0] * len(nums)
    dp[0]=nums[0]
    dp[1]=max(nums[0],nums[1])

    for i in range(2,len(nums)):
        dp[i]=max(dp[i-1],dp[i-2]+nums[i])

    return dp[len(nums)-1]

def fun2(nums):#把时间复杂度化简一下
    #我实际用到的就两个变量[i-2]和[i-1]
    if len(nums)<=2:
        return max(nums)


    pre1=nums[0]#[i-2]
    pre2=max(nums[0],nums[1])#[i-1]

    for i in range(2,len(nums)):
        t=pre2
        pre2=max(pre2,pre1+nums[i])
        pre1=t
    return pre2


#打家劫舍2的代码
'''
    基本思路:
        --与打家劫舍相比,0和len(nums)-1相邻
        --进行拆分变成从0到len(nums)-2和len(nums)-1到1
        --为什么?
            因为有我没他
        
'''
def fun3(nums):
    if len(nums)<=3:
        return max(nums)
    pre1=nums[0]
    pre2=max(nums[0],nums[1])
    for i in range(2,len(nums)-1):
        t=pre2#更换
        pre2=max(pre2,pre1+nums[i])#获得当前位置可以达到的最大值
        pre1=t
    max1=pre2



    pre1 = nums[len(nums)-1]
    pre2 = max(nums[len(nums)-1], nums[len(nums)-2])
    for i in reversed(range(1,len(nums)-2)):
        t = pre2  # 更换
        pre2 = max(pre2, pre1 + nums[i])  # 获得当前位置可以达到的最大值
        pre1 = t

    return max(max1,pre2)
fun3([2,3,3,3,3,3,9])

===========================================================================================================================================================================

在这里插入代码片

===========================================================================================================================================================================

在这里插入代码片

猜你喜欢

转载自blog.csdn.net/qq_53183608/article/details/120971051
今日推荐