import java.util.*; /** * NC202 长度最小的连续子数组 * @author d3y1 */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param nums int整型一维数组 * @param target int整型 * @return int整型 */ public int minSubarray (int[] nums, int target) { // return solution1(nums, target); // return solution2(nums, target); return solution3(nums, target); // return solution4(nums, target); } /** * 前缀和 + 双指针(滑动窗口) * @param nums * @param target * @return */ private int solution1(int[] nums, int target){ int n = nums.length; // 前缀和: pre[i]表示前i项的和 int[] pre = new int[n+1]; int val; for(int i=1; i<=n; i++){ val = nums[i-1]; if(val >= target){ return 1; } pre[i] = pre[i-1]+val; } if(pre[n] < target){ return 0; } int sum; int result = Integer.MAX_VALUE; // 双指针(滑动窗口) for(int i=0,j=1; i<=j&&j<=n;){ sum = pre[j]-pre[i]; if(sum >= target){ result = Math.min(result, j-i); i++; }else{ j++; } } return result; } /** * 前缀和 + 双指针(滑动窗口) + 二分 * @param nums * @param target * @return */ private int solution2(int[] nums, int target){ int n = nums.length; // 前缀和: pre[i]表示前i项的和 int[] pre = new int[n+1]; int val; for(int i=1; i<=n; i++){ val = nums[i-1]; if(val >= target){ return 1; } pre[i] = pre[i-1]+val; } if(pre[n] < target){ return 0; } // 二分 <- 前缀数组pre 单调增 // 快速找到第一个满足条件的位置 int left = 1; int right = n; int mid; while(left <= right){ mid = (left+right)/2; if(pre[mid] < target){ left = mid + 1; }else{ right = mid - 1; } } int sum; int result = Integer.MAX_VALUE; // 双指针(滑动窗口) for(int i=0,j=left; i<=j&&j<=n;){ sum = pre[j]-pre[i]; if(sum >= target){ result = Math.min(result, j-i); i++; }else{ j++; } } return result; } /** * 前缀和 + 二分 * @param nums * @param target * @return */ private int solution3(int[] nums, int target){ int n = nums.length; // 前缀和: pre[i]表示前i项的和 int[] pre = new int[n+1]; int val; for(int i=1; i<=n; i++){ val = nums[i-1]; if(val >= target){ return 1; } pre[i] = pre[i-1]+val; } if(pre[n] < target){ return 0; } // 二分 <- 前缀数组pre 单调增 int result = Integer.MAX_VALUE; for(int i=0; i<n; i++){ int left = i; int right = n; int mid; while(left <= right){ mid = (left+right)/2; // 关键 if(pre[mid] < pre[i]+target){ left = mid + 1; }else{ right = mid - 1; } } if(left <= n){ result = Math.min(result, left-i); } } return result; } /** * 前缀和 + 二分 * @param nums * @param target * @return */ private int solution4(int[] nums, int target){ int n = nums.length; // 前缀和: pre[i]表示前i项的和 int[] pre = new int[n+1]; int val; for(int i=1; i<=n; i++){ val = nums[i-1]; if(val >= target){ return 1; } pre[i] = pre[i-1]+val; } if(pre[n] < target){ return 0; } // 二分 <- 子数组长度 int left = 1; int right = n; int mid; while(left <= right){ mid = (left+right)/2; boolean found = false; for(int i=0,j=i+mid; j<=n; i++,j++){ if(pre[j]-pre[i] >= target){ found = true; break; } } if(!found){ left = mid + 1; }else{ right = mid - 1; } } // left>n => 不存在满足条件的子数组 int result = left>n?0:left; return result; } }