package class_2022_01_3_week; // 来自字节跳动 // 给定一个数组arr,其中的值有可能正、负、0 // 给定一个正数k // 返回累加和>=k的所有子数组中,最短的子数组长度 // 本题测试链接 : https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/ public class Code03_ShortestSubarrayWithSumAtLeastK { public static int shortestSubarray1(int[] arr, int k) { if (arr == null || arr.length < 1) { return -1; } int n = arr.length + 1; long[] sum = new long[n]; for (int i = 1; i < n; i++) { sum[i] = sum[i - 1] + arr[i - 1]; } int[] stack = new int[n]; int size = 1; int ans = Integer.MAX_VALUE; for (int i = 1; i < n; i++) { int mostRight = mostRight(sum, stack, size, sum[i] - k); ans = Math.min(ans, mostRight == -1 ? Integer.MAX_VALUE : (i - mostRight)); while (size > 0 && sum[stack[size - 1]] >= sum[i]) { size--; } stack[size++] = i; } return ans == Integer.MAX_VALUE ? -1 : ans; } public static int mostRight(long[] sum, int[] stack, int size, long aim) { int l = 0; int r = size - 1; int m = 0; int ans = -1; while (l <= r) { m = (l + r) / 2; if (sum[stack[m]] <= aim) { ans = stack[m]; l = m + 1; } else { r = m - 1; } } return ans; } public static int shortestSubarray2(int[] arr, int K) { int N = arr.length; long[] sum = new long[N + 1]; for (int i = 0; i < N; i++) { sum[i + 1] = sum[i] + arr[i]; } int ans = Integer.MAX_VALUE; int[] dq = new int[N + 1]; int l = 0; int r = 0; for (int i = 0; i < N + 1; i++) { // 头部开始,符合条件的,从头部弹出! while (l != r && sum[i] - sum[dq[l]] >= K) { ans = Math.min(ans, i - dq[l++]); } // 尾部开始,前缀和比当前的前缀和大于等于的,从尾部弹出! while (l != r && sum[dq[r - 1]] >= sum[i]) { r--; } dq[r++] = i; } return ans != Integer.MAX_VALUE ? ans : -1; } }