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); } }