参考资料:《程序员面试代码指南》
方法1:贪心法
如果从x到y都无法完成的话,那么从z到y更无法完成,其中z是x去y的沿途结点。也就是,一旦x被确定不是良好出发点,那么x到y中间的点也必然不是良好出发点,不用试了。
public int canCompleteCircuit1(int[] gas, int[] cost)
{
int n = gas.length;
int i=0;
while(i<n)// check if node i is a good start
{
int sumGas = 0, sumCost=0;
int cnt=0;// 从i出发沿途成功经过的节点数
while(cnt<n)
{
int j = (i+cnt)%n;
sumGas+=gas[j];
sumCost+=cost[j];
if(sumCost>sumGas)
{
break;
}
cnt++;
}
if(cnt==n)
{
return i;
}else{// come here because 'break', sumCost>sumGas
i = i+cnt+1; // greedy policy
// because i,i+1,..,i+cnt were identified as not goot starts
}
}// end while
return -1;
}
方法2:左老师把题目推广成”判断每个点是否是良好出发点“,所以返回的是一个Boolean数组。具体见 《程序员代码面试指南》第二版
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost)
{
int n = gas.length;
boolean[] good = getGood(gas,cost);
for(int i=0;i<n;i++)
{
if(good[i])
{
return i;
}
}
return -1;
}
public static boolean[] getGood(int[] gas, int[] cost)
{
int n = gas.length;
int[] help = new int[n<<1];
for(int i=0;i<n;i++)
{
help[i] = gas[i]-cost[i];
help[i+n] = gas[i]-cost[i];
}
for(int i=1;i<help.length;i++)
{
help[i]+=help[i-1];
}
// window: [0...n-1]
LinkedList<Integer> que = new LinkedList<>();
for(int i=0;i<n;i++)
{
while(!que.isEmpty()&&help[que.peekLast()]>=help[i])
{
que.pollLast();
}
que.addLast(i);
}
boolean[] ans = new boolean[n];// false
for(int offset = 0,i=0,j=n;j<help.length;offset=help[i++],j++)
{
if(help[que.peekFirst()]-offset>=0)
{
ans[i] = true;
}
// remove i from this window
if(i==que.peekFirst())
{
que.pollFirst();
}
// push j into this window
while(!que.isEmpty()&&help[que.peekLast()]>=help[j])
{
que.pollLast();
}
que.addLast(j);
}
return ans;
}
}