【每日一题】1793.好子数组的最大分数--Python

文章描述了一个编程问题,给定一个整数数组和一个整数k,目标是找到一个区间,其内的最小值乘以区间长度最大。文章介绍了从暴力解法到双指针优化,最终提供了一种更高效的解决方案,利用最大值作为新最小值,直到i减小到0。
摘要由CSDN通过智能技术生成

给你一个整数数组 nums (下标从 0 开始)和一个整数 k 。

一个子数组 (i, j) 的 分数 定义为 min(nums[i], nums[i+1], …, nums[j]) * (j - i + 1) 。一个 好 子数组的两个端点下标需要满足 i <= k <= j 。

请你返回 好 子数组的最大可能 分数 。

示例 1:
输入:nums = [1,4,3,7,4,5], k = 3
输出:15
解释:最优子数组的左右端点下标是 (1, 5) ,分数为 min(4,3,7,4,5) * (5-1+1) = 3 * 5 = 15 。

示例 2:
输入:nums = [5,5,4,5,4,1,1,1], k = 0
输出:20
解释:最优子数组的左右端点下标是 (0, 4) ,分数为 min(5,5,4,5,4) * (4-0+1) = 4 * 5 = 20 。

提示:
1 <= nums.length <= 105
1 <= nums[i] <= 2 * 104
0 <= k < nums.length

思路:
(1)首先我第一个想到的又是暴力解法,直接三个循环嵌套,不出意外的超时了
代码如下:

class Solution(object):
    def maximumScore(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        n = len(nums) 
        Result = 0
        for i in range(0,k+1):
            for j in range(k,n):
                m = nums[i]
                for x in range(i,j+1):
                    if m > nums[x]:
                        m = nums[x]
                s = m * (j-i+1)
                if s > Result:
                    Result = s
        return Result
        

(2)现在想想咋降低时间复杂度呢?
因为好子数组要求i<=k<=j,可以发现,不管怎么选择好子数组的范围,nums[k]永远在好子数组内。
那么我们可以使用双指针,一个指向k的前一位,一个指向k的后一位。
枚举法,首先令i=nums[k]作为当前好子数组的最小值,在left和right不超出边界的情况下:若k左边的数>=nums[k],则left-1,若k右边的数>=nums[k],则right+1。最后得出的i*(right-left-1)就是nums[k]作为最小值的好子数组的最大分数。然后用i*(right-left-1)与result比大小,如果更大,则替换result。
然后令i-1,继续计算最大值,与result比较,更新即可。
这样时间复杂度减少了

Python代码:

class Solution(object):
    def maximumScore(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        n = len(nums)
        left = k - 1
        right = k + 1
        result = 0
        for i in range(nums[k],0,-1):  #因为nums[k]一定包含在好子数组中,用双指针从中间开始遍历,
            while left >= 0 and nums[left] >=i:  #第一轮i=nums[k]计算出nums[k]为最小值时,好字子数组的最大分数
                left -= 1                         
            while right < n and nums[right] >= i:
                right +=1
            result = max(result,i*(right - left - 1))#然后最小值逐渐递减到1,求出每个最小值对应的最大分数
        return result   #不断更新最大分数,返回最大的
        

(3)刚刚的解法中,每一次更新i,left和right有可能不会移动,这样浪费了时间。如果我们每一次更新i的时候不让i-1了,而是让他等于nums[left]和nums[right]中的最大值,这样就可以 保证每一次更新i,left和right都有移动,再一次减少的运行时间。
Python代码:

class Solution(object):
    def maximumScore(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        n = len(nums)
        left = k - 1
        right = k + 1
        result = 0
        i = nums[k]
        while True:  #因为nums[k]一定包含在好子数组中,用双指针从中间开始遍历,
            while left >= 0 and nums[left] >=i:  #第一轮i=nums[k]计算出nums[k]为最小值时,好字子数组的最大分数
                left -= 1                         
            while right < n and nums[right] >= i:
                right +=1
            result = max(result,i*(right - left - 1))#然后最小值逐渐递减到1,求出每个最小值对应的最大分数
            i = max(-1 if left == -1 else nums[left],-1 if right == n else nums[right])
            if i<=0:
                break
        return result   #不断更新最大分数,返回最大的

------改进算法参考LeetCode--------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值