算法编程题-区间最小数乘区间和的最大值,基于数组中的数字拼接可得的小于目标值的最大数


这里分享两道字节面试常考但是不是leetcode原题的两道题目。

区间最小数乘区间和的最大值

原题描述

给定一个数组,定义一个子数组的值为:该子数组中的最小值乘以该子数组的和,现在需要找到值最大的子数组。比如,对于数组[6, 2, 1],应当输出36。

思路简述

该题虽然不是leetcode原题,但是和经典题接雨水的思路是一样的。先从暴力思路入手,最暴力最直观的思路就是遍历每一个子数组,然后在遍历这个子数组得出子数组的最小值和和,这种做法的时间复杂度达到了 O ( n 3 ) O(n^3) O(n3)。先尝试在这一个基础上进行优化,减少遍历次数。可以优化遍历方式,在遍历的同时计算当前子数组的最小值和和,这样时间复杂度就减少到了 O ( n 2 ) O(n^2) O(n2)。但是这样的时间复杂度是肯定不够的,还需要优化。
考虑枚举,换一个角度想,能不能枚举没有的最小值,也就是我们遍历数组,以当前位置作为最小值,那么当前位置的数能够作为什么样的子数组的最小值呢,显然是子数组中不会存在小于该数的数,那么就可以从当前位置往左看,第一个小于当前数的位置,以及往右看,第一个小于当前数的位置,以上两个位置夹的子数组就是以当前数为最小数的情况下,对应的最优的子数组,因为在最小数确定的情况下,子数组自然是越长越好。可是怎么去找到以上的两个位置呢?可以基于单调栈以 O ( n ) O(n) O(n)的时间复杂度预处理得到所有位置的左边第一个小于的数,右边第一个小于的数,这样整体的时间复杂度就减少到了 O ( n ) O(n) O(n)
以寻找左边最近的较小的数字的过程为例来说明单调栈的过程,首先是从左往右遍历数组,维护一个单调递增栈,为什么是递增,如下图,假设此时维护的栈不满足严格的递增,遍历到一个新的数11,其左边的第一个较小的数字是8,而10永远没有机会,因为一个数字如果比10大,也一定会大于8,而我们要找的左边最近的,相当与10会被8覆盖掉,所以我们要维护成一个单调递增栈。具体的思路就是在遍历的过程中,先把栈顶大于等于当前数字的数pop出去,然后根据栈中的情况决定左边最近的较小的数字的位置是什么,然后将当前数字也加入到栈中,这样维护的栈就是一个单调递增栈。
在这里插入图片描述

代码实现

func MaxVInterval(arr []int) int {
   
   
	n := len(arr)
	// 1. 从前往后用单调栈找出左边最近的比当前元素要小的元素的位置+1
	leftSmaller := make([]int, n)
	stack := gulc.NewStack[int]()
	for i := 0; i < n; i++ {
   
   
		for !stack.IsEmpty() && arr[stack.Top()] >= arr[i] {
   
   
			stack.Pop()
		}
		if stack.IsEmpty() {
   
   
		
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值