1.加油站:
在一条环路上有 n个加油站,其中第 i个加油站有汽油 gas[i]升。
你有一辆油箱容量无限的的汽车,从第 1个加油站开往第 i+1个加油站需要消耗汽油 cost[i]升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回-1 。如果存在解,则 保证 它是 唯一 的。
gas = input().split()
cost = input().split()
sum1 = 0
for i in range(len(gas)):
gas[i] = int(gas[i])
cost[i] = int(cost[i])
def jyz(gas,cost):
for i in range(len(gas)):
gas[i] = gas[i] - cost[i]
gas = list(gas)
for i in range(len(gas)):#遍历所有可能的起点
sum = 0
if gas[i] < 0:#起点为负数,直接跳过
continue
else:
for j in range(i,len(gas)):#对可能的起点进行遍历
sum += gas[j]
if sum < 0:
break
for j in range(0,i):#对可能的起点进行遍历
sum += gas[j]
if sum < 0:
i = i + 1 +j#如果i不可以作为起点,那么后面的数一定也不可以作为起点,所以直接跳过
break
if sum >= 0:
return i
return -1
print(jyz(gas,cost))
上述代码可以优化的点在于,下一次的循环可以从i+j+1的地方开始,由于若从i无法走到j,则从i+1位置作为起点也无法走到,由于从i开始到i+1的地方时,i+1的初始油数一定非负,那意味着从i+1处启动为0,必然也不用参与循环,有效减缓程序时间。
2.接雨水
这道题以下给出三种解决方法:
1).双指针
通过左右指针指向两侧的遇到的最值,找到最大值较小的一侧后,由于水高最高和当前遇到最高的墙高(指针的值)一样,意味着用墙高减去每一个位置的墙数,可以得到每一个位置的可能的储水量。
height = list(map(int, input().split()))
left, right = 0, len(height) - 1
left_max, right_max = 0, 0
ans = 0
while left < right:
if height[left] < height[right]:
# 左边较低,处理左边
if height[left] >= left_max:
left_max = height[left]
else:
ans += left_max - height[left]
left += 1
else:
# 右边较低,处理右边
if height[right] >= right_max:
right_max = height[right]
else:
ans += right_max - height[right]
right -= 1
print(ans)
2).动态规划
本题对于动态规划的方法,需要先从左往右遍历一边数组,得到左侧的最大值组,右侧同理,之后对两个数组同时遍历,取得当前位置上两个数组值的最小值作为当前位置的最大水位,再减去位置上的墙数,最后累加则得到了储水量。
height = list(map(int, input().split()))
n = len(height)
# 构建左侧最大高度数组
left_max = [0] * n
left_max[0] = height[0]
for i in range(1, n):
left_max[i] = max(left_max[i - 1], height[i])
# 构建右侧最大高度数组
right_max = [0] * n
right_max[n - 1] = height[n - 1]
for i in range(n - 2, -1, -1):
right_max[i] = max(right_max[i + 1], height[i])
# 计算结果
ans = 0
for i in range(n):
ans += min(left_max[i], right_max[i]) - height[i]
print(ans)
3).单调栈
单调栈(存元素下标)需要保持栈内元素单调,若下一个读入栈的元素不满足单调增,则对大于该数的所有元素逐个弹出,弹出元素时计算当前元素*(当前位置i - 栈顶元素下标 -1)首尾的话可以添加一个元素-1避免首位有减1的问题,或者可以单独对首尾添加判断。单调递减则相反,本题使用单调递减的栈,逐个计算两个高墙间的所有位置,并且减去每一个位置的墙数,累加得到结果。
height = list(map(int, input().split()))
stack = []
ans = 0
for current in range(len(height)):
while stack and height[current] > height[stack[-1]]:
top = stack.pop()
if not stack:
break
distance = current - stack[-1] - 1
bounded_height = min(height[current], height[stack[-1]]) - height[top]
ans += distance * bounded_height
stack.append(current)
print(ans)
3.单调栈例题:面试题: 求最大矩形面积,
恰定一个非负数组arr,每个坐标i横坐标x的位置。arr[i]表示当前位置宽为1的矩形高度,求arr中可以画出的最大矩形的面职。
这里的栈需要单调增,以找到最大的面积
def largestRectangleArea(heights):
stack = [] # 初始化一个空栈
max_area = 0 # 初始化最大面积
for i, h in enumerate(heights):#enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列
# 开始位置的柱形高度已经不是递增的了
# 确定右边界为 i,左边界为栈顶元素之后的那个元素
while stack and heights[stack[-1]] > h:#如果栈不为空且栈顶元素大于当前元素,栈顶是左边界
top = stack.pop()#弹出栈顶元素
width = i if not stack else (i - stack[-1] - 1)#如果栈为空,宽度为i,否则为i-栈顶元素-1
max_area = max(max_area, heights[top] * width)
stack.append(i)
# 遍历结束后清空栈,确定右边界为数组长度
while stack:
top = stack.pop()
width = len(heights) if not stack else (len(heights) - stack[-1] - 1)
max_area = max(max_area, heights[top] * width)
return max_area
# 测试代码
heights = list(map(int, input().split(','))) # 使用逗号', '分隔的输入
print(largestRectangleArea(heights))