文章目录
代码随想录之贪心系列困难算法
1.最大子序和(最大子数组和)
2.加油站
2.1暴力
func canCompleteCircuit(gas []int, cost []int) int {
for i := 0; i < len(gas); i++ {
//记录剩余汽油量
rest := gas[i] - cost[i]
//这里要rest += gas[index] - cost[index]的原因是在循环里面要继续进行相减了
index := (i + 1) % len(gas)
for rest > 0 && index != i {
rest += gas[index] - cost[index]
index = (index + 1) % len(gas) //循环自动连接首部
}
//如果以i为起点跑一圈,剩余油量>=0,则说明可以
if rest >= 0 && index == i {
return i
}
}
return -1
}
//一各一个起点尝试,如果跑了一圈,中途没有断油,而且最后油量大于等于0,说明这个起点是ok的。
//O(N^2)
空间复杂度:$O(n)$
2.2贪心
func canCompleteCircuit(gas []int, cost []int) int {
curSum := 0
totalSum := 0
start := 0
//每一个加油点都要进行尝试
for i := 0; i < len(gas); i++ {
curSum += gas[i] - cost[i]
totalSum += gas[i] - cost[i]
if curSum < 0 {
start = i+1
curSum = 0
}
}
// 因为耗油总和是大于零的,如果小于0说明怎么走都不可能跑一圈了
if totalSum < 0 {
return -1
}
return start//即大于等于0的情况,totalSum < 0
}
//思路:我们可以通过减小被检查的加油站数目,来降低总的时间复杂度。
那么局部最优:当前累加rest[j]的和curSum一旦小于0,起始位置至少要是j+1,因为从j开始一定不行。
全局最优:找到可以跑一圈的起始位置。
那么为什么一旦[i,j] 区间和为负数,起始位置就可以是j+1呢,j+1后面就不会出现更大的负数?
看如下图:
为什么最后还要进行一下if totalSum < 0 判断?
为什么本题解法没有体现到环形数组呢?
i不一定要
//canCompleteCircuit 时间复杂度O(N),空间复杂度O(1)