力扣134. 加油站
题目来源(力扣):
https://leetcode.cn/problems/gas-station/solutions/488357/jia-you-zhan-by-leetcode-solution/
题目描述:
环形道路有n个点,第i个点可以获得能量a[i],并且可以消耗能量b[i]到达第i+1个点。
找到一个点作为起点,使得从起点出发可以便利环中的所有节点。如果不存在则返回-1。
基本思路:
贪心,思路类似于 https://www.cnblogs.com/hb-computer/articles/18535226
不存在答案的情况:如果sum(a)<sum(b),则无法找的合法的节点;
否则,至少可以找到一个合法的起点符合题意。
从起点0开始(start=0),每次经过一个节点,就将获取其能量a[i]并且消耗能量b[i],
即tmp+=a[i]-b[i];
如果tmp<0,则说明start开始的位置不能满足题意,更新start=i+1,继续往后更新tmp,直到数组末尾。
即贪心策略:如果i~j累计值sum<0,则起始位置至少为j+1。
对于贪心的证明可以见 https://leetcode.cn/problems/gas-station/solutions/488357/jia-you-zhan-by-leetcode-solution/
代码实现:
class Solution
{
public:
int canCompleteCircuit(vector<int> &gas, vector<int> &cost)
{
int sum = 0; //用于判断sum(a)与sum(b)的大小
int len = gas.size();
int start = 0;
int tmp = 0; //过程中的临时累计和
for (int i = 0; i < len; i++)
{
tmp += gas[i] - cost[i];
sum += gas[i] - cost[i];
if (tmp < 0) //tmp任意时刻小于0,说明之前的起点有误,需要进行新的起点尝试
{
tmp = 0;
start = i + 1;
}
}
if (sum < 0)
return -1;
return start;
}
};
时间复杂度
O(n)
补充-另一个思路
《代码随想录》中根据全局最优的思路得到另外一种贪心写法:
从0开始计算累加值sum,过程中的最小值为minn;
(1)如果sum<0,说明无解,返回-1;
(2)如果直到最后都minn>=0,则起点为0;
(3)否则,(minn不清0)从len-1位置向前累加,当minn>=0时,则对应的节点就是起点。
代码如下
class Solution
{
public:
int canCompleteCircuit(vector<int> &gas, vector<int> &cost)
{
int sum = 0;
int len = gas.size();
int start = 0;
int minn = 0;
// 从0走到末尾
for (int i = 0; i < len; i++)
{
sum += gas[i] - cost[i];
if (sum < minn)
{
minn = sum;
}
}
if (sum < 0)
return -1; //(1) 能量抵不上消耗
if (minn >= 0)
return 0; // (2)过程中无负值,说明节点0作为起点就为答案
// (3)过程中有负值,则从末尾开始往前,直到tmp>=0
for (int i = len - 1; i >= 0; i--)
{
minn += gas[i] - cost[i];
if (minn >= 0)
{
start = i;
break;
}
}
return start;
}
};
浙公网安备 33010602011771号