题意:
朴素想法直接使用暴力求解:
func canCompleteCircuit(gas []int, cost []int) int {
/*
使用一个变量计算剩余的油量
初始化为空
首先枚举每一个点是否有可能成为答案
时间复杂度O(n^2)
空间复杂度O(1)
*/
n := len(gas)
for i := range gas {
j := i
remain := gas[i]
for remain-cost[j] >= 0 {
remain = remain - cost[j] + gas[(j+1)%n]
j = (j + 1) % n
//假设能走完一圈返回答案。
if i == j {
return i
}
}
}
return -1
}
如果在力扣上提交会超时,因为时间复杂度是O(n^2)。
基于上面的代码能否有更好的方式。答案肯定是有的。
假设从i出发最远能走到j,那么i-j之间所有点,不能走一圈。此时j在i的前面 j < i因为我们已经考虑过了。所有直接返回-1。
假设从j出发最远达到i,可以尝试从i+1开始考虑。
为什么不是从i开始考虑而是从i+1开始考虑。可以想一下i到i+1油量一定是大于等于0不可能是负数。
| 1 2 3 4 5 |
j i
显而易见基于上面的代码进行一次改进
func canCompleteCircuit(gas []int, cost []int) int {
n := len(gas)
for i := 0;i<n;i++ {
j := i
remain := gas[i]
for remain-cost[j] >= 0 {
remain = remain - cost[j] + gas[(j+1)%n]
j = (j + 1) % n
//假设能走完一圈返回答案。
if i == j {
return i
}
}
if j < i{
return -1
}
i = j
}
return -1
}
空间复杂度O(1)
时间复杂度O(n)
那么还有没有其他的方式呢?答案有,你可以设想sum(gas[i]) > sum(cost[i])一定能绕一圈,只是你要计算一下下标在哪个位置。
能都用一个变量来存储当前剩余油量,一个变量存储所有油量,一个变量存储下标呢?
func canCompleteCircuit(gas []int, cost []int)int{
//存储剩余油量
curr := 0
//存储所有的油量
total := 0
//剩余油量对应的下标
idx := 0
for i := range gas{
curr += gas[i] - cost[i]
total += gas[i] - cost[i]
if curr < 0 {
idx = i + 1
curr = 0
}
}
if total < 0{
idx = -1
}
return idx
}