程序员代码面试指南第二版 126.未排序数组中累加和小于或等于给定值的最长子数组长度
题目描述
给定一个无序数组arr,其中元素可正、可负、可0。给定一个整数k,求arr所有的子数组中累加和小于或等于k的最长子数组长度
例如:arr = [3, -2, -4, 0, 6], k = -2. 相加和小于等于-2的最长子数组为{3, -2, -4, 0},所以结果返回4
[要求]
时间复杂度为O(n)O(n),空间复杂度为O(n)O(n)
输入描述:
第一行两个整数N, k。N表示数组长度,k的定义已在题目描述中给出
第二行N个整数表示数组内的数
输出描述:
输出一个整数表示答案
示例1
输入
5 -2
3 -2 -4 0 6
输出
4
第一次做; 核心维护两个数组,具体见注释; 时间复杂度O(N); 这个方法很难, 优先掌握O(NlogN)的算法
import java.util.Scanner;
import java.util.HashMap;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String[] str = sc.nextLine().split(" ");
int n = Integer.parseInt(str[0]);
int k = Integer.parseInt(str[1]);
str = sc.nextLine().split(" ");
int[] arr = new int[n];
for(int i=0; i<n; i++){
arr[i] = Integer.parseInt(str[i]);
}
int[] minSums = new int[n];
int[] minSumEnds = new int [n];
minSums[n-1] = arr[n-1];
minSumEnds[n-1] = n-1;
for(int i=n-2; i>=0; i--){
if(minSums[i+1]>=0){
minSums[i] = arr[i];
minSumEnds[i] = i;
}
else{
minSums[i] = arr[i] + minSums[i+1];
minSumEnds[i] = minSumEnds[i+1];
}
}
int end=0, sum=0, len=0;
for(int i=0; i<n; i++){
while(end<n && sum + minSums[end] <= k){
sum = sum + minSums[end];
end = minSumEnds[end]+1;
}
len = Math.max(len, end-i);
if(end>i)
sum = sum - arr[i];
else
end = i + 1;
}
System.out.print(len);
}
}
第一次做; 哈希表前缀和+二分查找法; 时间复杂度O(NlogN)
import java.util.Scanner;
import java.util.HashMap;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String[] str = sc.nextLine().split(" ");
int n = Integer.parseInt(str[0]);
int k = Integer.parseInt(str[1]);
str = sc.nextLine().split(" ");
int[] arr = new int[n];
for(int i=0; i<n; i++){
arr[i] = Integer.parseInt(str[i]);
}
int[] max = new int[n+1];
int tmp=0;
for(int i=1; i<=n; i++){
tmp = tmp + arr[i-1];
max[i] = Math.max(tmp, max[i-1]);
}
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0,-1);
int sum=0,len=0;
for(int i=0; i<n; i++){
sum = sum + arr[i];
tmp = getEqualOrGreaterThan(max,sum-k);
if(tmp>=sum-k && map.containsKey(tmp)){
len = Math.max(len, i-map.get(tmp));
}
if(!map.containsKey(sum)){
map.put(sum, i);
}
}
System.out.print(len);
}
public static int getEqualOrGreaterThan(int[] max, int a){
int res = a-1;
int left=0, right=max.length-1, mid;
while(left<right){
mid = left + ((right-left)>>1);
if(max[mid]>=a){
right = mid;
}
else{
left = mid+1;
}
}
return max[left] >= a ? max[left] : a-1;
}
}