You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
3.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class25;
// 本题测试链接 : https://leetcode.com/problems/gas-station/
// 注意本题的实现比leetcode上的问法更加通用
// leetcode只让返回其中一个良好出发点的位置
// 本题是返回结果数组,每一个出发点是否是良好出发点都求出来了
// 得到结果数组的过程时间复杂度O(N)额外空间复杂度O(1)
public class Code04_GasStation {
public static int canCompleteCircuit(int[] gas, int[] cost) {
if (gas == null || gas.length == 0) {
return -1;
}
if (gas.length == 1) {
return gas[0] < cost[0] ? -1 : 0;
}
boolean[] good = stations(cost, gas);
for (int i = 0; i < gas.length; i++) {
if (good[i]) {
return i;
}
}
return -1;
}
public static boolean[] stations(int[] cost, int[] gas) {
if (cost == null || gas == null || cost.length < 2 || cost.length != gas.length) {
return null;
}
int init = changeDisArrayGetInit(cost, gas);
return init == -1 ? new boolean[cost.length] : enlargeArea(cost, init);
}
public static int changeDisArrayGetInit(int[] dis, int[] oil) {
int init = -1;
for (int i = 0; i < dis.length; i++) {
dis[i] = oil[i] - dis[i];
if (dis[i] >= 0) {
init = i;
}
}
return init;
}
public static boolean[] enlargeArea(int[] dis, int init) {
boolean[] res = new boolean[dis.length];
int start = init;
int end = nextIndex(init, dis.length);
int need = 0;
int rest = 0;
do {
// 当前来到的start已经在连通区域中可以确定后续的开始点一定无法转完一圈
if (start != init && start == lastIndex(end, dis.length)) {
break;
}
// 当前来到的start不在连通区域中就扩充连通区域
// start(5) -> 联通区的头部(7) -> 2
// start(-2) -> 联通区的头部(7) -> 9
if (dis[start] < need) { // 当前start无法接到连通区的头部
need -= dis[start];
} else { // 当前start可以接到连通区的头部开始扩充连通区域的尾巴
// start(7) -> 联通区的头部(5)
rest += dis[start] - need;
need = 0;
while (rest >= 0 && end != start) {
rest += dis[end];
end = nextIndex(end, dis.length);
}
// 如果连通区域已经覆盖整个环当前的start是良好出发点进入2阶段
if (rest >= 0) {
res[start] = true;
connectGood(dis, lastIndex(start, dis.length), init, res);
break;
}
}
start = lastIndex(start, dis.length);
} while (start != init);
return res;
}
// 已知start的next方向上有一个良好出发点
// start如果可以达到这个良好出发点那么从start出发一定可以转一圈
public static void connectGood(int[] dis, int start, int init, boolean[] res) {
int need = 0;
while (start != init) {
if (dis[start] < need) {
need -= dis[start];
} else {
res[start] = true;
need = 0;
}
start = lastIndex(start, dis.length);
}
}
public static int lastIndex(int index, int size) {
return index == 0 ? (size - 1) : index - 1;
}
public static int nextIndex(int index, int size) {
return index == size - 1 ? 0 : (index + 1);
}
}