给定一个无序数组arr,其中元素可正、可负、可0。给定一个整数k,求arr所有的子数组中累加和小于或等于k的最长子数组长度
例如:arr = [3, -2, -4, 0, 6], k = -2. 相加和小于等于-2的最长子数组为{3, -2, -4, 0},所以结果返回4
[要求]
时间复杂度为,空间复杂度为
第一行两个整数N, k。N表示数组长度,k的定义已在题目描述中给出
第二行N个整数表示数组内的数
输出一个整数表示答案
5 -2 3 -2 -4 0 6
4
#include <bits/stdc++.h> using namespace std; int F(int *a, int n, int x){ int l=0, r=n-1, m, p=-1; while(l<=r){ m = (l+r)>>1; if(a[m]>=x){ p = m; r = m-1; }else l = m+1; } return p; } int main(){ int n, k; cin>>n>>k; int a[n]; for(int i=0;i<n;i++) cin>>a[i]; int b[n+1]; memset(b, 0, sizeof(b)); int s=0, Max=0, t=0, l=0; b[0] = s; for(int i=0;i<n;i++){ s += a[i]; b[i+1] = max(b[i], s); } s = 0; for(int i=0;i<n;i++){ s += a[i]; t = F(b, n+1, s-k); l = (t==-1?0:i-t+1); Max = max(Max, l); } cout<<Max<<endl; return 0; }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] params = br.readLine().split(" "); int n = Integer.parseInt(params[0]), k = Integer.parseInt(params[1]); String[] strArr = br.readLine().split(" "); int[] arr = new int[n]; for(int i = 0; i < n; i++) arr[i] = Integer.parseInt(strArr[i]); // minSums[i]表示从i开始,往后数组的最小和;minSumEnds[i]表示这个最小和数组的边界 int[] minSums = new int[n], 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] + minSums[i + 1]; minSumEnds[i] = minSumEnds[i + 1]; }else{ minSums[i] = arr[i]; minSumEnds[i] = i; } } int end = 0, sum = 0, maxLen = 0; for(int i = 0; i < n; i++){ while(end < n && sum + minSums[end] <= k){ // 满足累加和小于等于k就累加上 sum += minSums[end]; end = minSumEnds[end] + 1; } maxLen = Math.max(maxLen, end - i); if(end > i){ sum -= arr[i]; // 窗口内还有救,把左边的元素弹出去试试 }else{ end = i + 1; // 窗口内没救了,另起一个起点 } } System.out.println(maxLen); } }
#include<iostream> (720)#include<map> #include<algorithm> using namespace std; int main(){ int n,k; cin>>n>>k; int inp[n]; for(int i = 0; i < n; i++){ scanf("%d",&inp[i]); } int d[n + 1]; d[0] = 0; int sum = 0; for(int i = 0; i < n; i++){ sum += inp[i]; d[i + 1] = max(sum, d[i]); } int count = 0, len = 0; sum = 0; for(int i = 0; i < n; i++){ sum += inp[i]; int tmp = sum - k; int* index = lower_bound(d,d+n+1,tmp); count = index - d; len = max(len, i - count + 1); } cout<<len<<endl; return 0; }
#include <bits/stdc++.h> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> arr(n); for(int i = 0; i < n; ++i) { cin >> arr[i]; } vector<int> help(n+1); int res = -1; int sum = 0; help[0] = 0; for(int i = 0; i < n; ++i) { sum += arr[i]; if(sum < help[i]) help[i+1] = help[i]; else help[i+1] = sum; // 二分法找sum-k int left = 0; int right = i; while(left <= right) { int mid = left + (right - left)/2; if(help[mid] >= sum - k) { res = max(res, i - mid + 1); //为什么+1,因为arr和help起始位置不同,换算 right = mid - 1; } else { left = mid + 1; } } } cout << res << endl; return 0; }
#include <bits/stdc++.h> using namespace std; struct A{ int minSum; //以 i 开始,往右扩展,的最小和 int minEnd; // 以 i 开始,往右扩展最小和的最右边界 }; int n, k; int main() { cin >> n >> k; A *h = new A[n]; int *a = new int[n]; for (int i=0; i<n; ++i){ cin >> i[a]; } h[n-1].minSum = a[n-1]; h[n-1].minEnd = n-1; for (int i=n-2; i>=0; --i) { if (h[i+1].minSum <= 0) { h[i].minSum = h[i+1].minSum + a[i]; h[i].minEnd = h[i+1].minEnd; } else { h[i].minSum = a[i]; h[i].minEnd = i; } } int ans = 0; for (int i=0; i<n; ++i) { if (h[i].minSum <= k) { int j = h[i].minEnd + 1; int sum = h[i].minSum; while (j < n) { sum += h[j].minSum; if (sum > k) { break; } else { j = h[j].minEnd + 1; } } ans = max(ans, j - i); if (j > n) { break; } } } cout << ans << endl; delete a; delete h; return 0; }
#include<bits/stdc++.h> using namespace std; int getid(vector<int> & res, int x){ int low = 0, hight = res.size() - 1, mid = 0, ans = -1; while (hight >= low){ mid = (low + hight) / 2; if (res[mid] >= x){ ans = mid; hight = mid - 1; } else low = mid + 1; } return ans; } int getlen(vector<int> & res, int x){ vector<int>h(res.size() + 1, 0); int sum = 0; h[0] = sum; for (int i = 0; i < res.size(); i++){ sum += res[i]; h[i + 1] = max(h[i], sum); } sum = 0; int ans = 0, pre = 0, len = 0; for (int i = 0; i < res.size(); i++){ sum += res[i]; pre = getid(h, sum - x); len = pre == -1 ? 0 : i - pre + 1; ans = max(ans, len); } return ans; } int main() { int n,x; cin>>n>>x; vector<int>res(n); for(int i=0;i<n;i++) cin>>res[i]; cout<<getlen(res,x)<<endl; return 0; }
#include <bits/stdc++.h> using namespace std; int main(){ int n, k; cin >> n >> k; // special case if (n < 1) return 0; int arr[n]; for (int i=0; i<n; i++){ cin >> arr[i]; } int h[n], ends[n]; h[n-1] = arr[n-1]; ends[n-1] = n-1; // 找到从i出发的最长的最小值子队列 for(int i=n-2; i>-1; i--){ if(h[i+1]<=0){ h[i] = arr[i] + h[i+1]; ends[i] = ends[i+1]; } else{ h[i] = arr[i]; ends[i] = i; } } // 从前往后,依次寻找和比较从位置i出发,满足要求小于等于k的子数组并比较长度 int len=0, end=0, sum=0; for(int i=0; i<n; i++){ while(end<n && (sum+h[end]<=k)){ sum += h[end]; end = ends[end]+1; } len = max(len, end-i); // 注意上面的循环退出条件,这里end实际上已经在符合条件的区间外了,所以无需再+1 sum -= end > i ? arr[i]: 0; // 同样注意上面的循环条件,如果end压根没动,sum值则未更新,不需要进行再次清零操作 end = max(i+1, end); // 同理,此时end恰好在边界外,无需+1 } cout << len; return 0; } P.s 虽然在第二次循环中嵌套了while循环,但无需担心,因为在一次for循环的过程中,end总会前进while的步数,并且end不大于n,那么n即为上界; P.s.s 务必注意end和sum的值更新,详细理由已在注释中写明;
#include<bits/stdc++.h> using namespace std; int sum[202020],a[202020]; int main(){ int n,i,j,k,s=0,res=0,x; cin>>n>>k; for(i=1;i<=n;i++)cin>>a[i],sum[i]=s+=a[i]; for(i=n-1;i>=1;i--)sum[i]=min(sum[i],sum[i+1]); int temp=0; for(i=0;i<=n;i++){ temp+=a[i]; res=max(res,int(upper_bound(sum+1,sum+n+1,temp+k)-sum-i-1)); } cout<<res; }
#include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N = 100010; int n, k; int a[N], s[N]; int main() { cin >> n >> k; for(int i=1; i<=n; i++) cin >> a[i]; int ans = 0; for(int i=1, sum=0; i<=n; i++) { sum += a[i]; int t = sum - k; // 找大于 t 的 最小index int it = lower_bound(s, s + i, t) - s; ans = max(ans, i - it); s[i] = max(sum, s[i-1]); } cout << ans << endl; return 0; }
#include "bits/stdc++.h" using namespace std; int find(vector<int>&sums,int tmp) { int n=sums.size(); //if(tmp>sums[n-1]) return n; int l=0;int r=n; int mid; while(l<r) { mid=(l+r)>>1; if(sums[mid]==tmp) {while(mid>0&&sums[mid]==sums[mid-1])mid--; return mid;} else if(sums[mid]<tmp){l=mid+1;} else if(sums[mid]>tmp){r=mid;} } return l; } int main() { int len;cin>>len; int target;cin>>target; vector<int> sums(len+1,0); vector<int> helper(len+1,0); int sum=0; int tmp; int max_tmp=INT_MIN; for(int i=0;i<=len;i++) { cin>>tmp; sum+=tmp; sums[i]=sum; max_tmp=max(max_tmp,sums[i]); helper[i]=max_tmp; } int ret=0; for(int i=0;i<=len;i++) { tmp=sums[i]-target; int j=find(helper,tmp); if(j<=i) ret=max(ret,i-j); } cout<<ret; return 0; }
#include <iostream> #include <vector> #include <algorithm> using namespace std; int getLessIndex(vector<int>& arr, int num) { int low = 0; int high = arr.size() - 1; int mid = 0; int res = -1; while (low <= high) { mid = (low + high) / 2; if (arr[mid] >= num) { res = mid; high = mid - 1; } else { low = mid + 1; } } return res; } int maxLength(vector<int>& arr, int k ) { // 记录累加和 vector<int> sumArr(arr.size(), 0); // 记录sumArr数组每个位置上的左侧最大值, 是有序的, 因此可以二分查找 vector<int> helperArr(arr.size() + 1, 0); int sum = 0; helperArr[0] = sum; for (int i =0; i != arr.size(); i++) { sum += arr[i]; sumArr[i] = sum; helperArr[i+1] = max(sum, helperArr[i]); } sum = 0; int res = 0; int pre = 0; int len = 0; for(int i = 0; i != sumArr.size(); i++) { sum = sumArr[i]; // helperArr[x] >= sumArr[i] - k, x为满足此条件的最小下标 // 即: sumArr[i] - helperArr[x] <= k // 然后 x ~ i 即为满足条件的最长子数组 pre = getLessIndex(helperArr, sum - k); len = pre == -1 ? 0 : (i - pre + 1); res = max(res, len); } return res; } int main() { int n = 0, k = 0; cin >> n >> k; vector<int> arr(n, 0); for (int i = 0; i < n; i++) { cin >> arr[i]; } cout << maxLength(arr, k) << endl; }
import java.util.*; public class Main{ public static void main(String [] args){ Scanner input = new Scanner(System.in); int N,k; N = input.nextInt(); k = input.nextInt(); int [] arr = new int[N]; int [] prefix = new int[N+1]; int maxlen = 0; for(int i = 0;i < N;++i){ arr[i] = input.nextInt(); prefix[i+1] = prefix[i]+arr[i]; } for(int i = 0;i < N;++i){ int target = prefix[i+1]-k; /*在prefix的[0,i]区间中找到第一个大于等于target的数的索引位置,没有则返回-1*/ int tmp = find(prefix,target,0,i); if(tmp != -1){ maxlen = Math.max(maxlen,i-tmp+1); } /*对前缀和进行特殊处理从而通过二分查找确定可能存在的最左边的边界*/ prefix[i+1] = Math.max(prefix[i],prefix[i+1]); } System.out.printf("%d\n",maxlen); } static int find(int[] prefix,int target,int left,int right){ while(left < right){ int mid = (right-left)/2+left; if(prefix[mid] >= target) right = mid; else{ left = mid+1; } } return prefix[right] >= target ? right : -1; } }
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); int[] arr = new int[n]; for(int i = 0; i < n; i++) { arr[i] = sc.nextInt(); } //答案在 0 - n 之间 int left = 0; int right = n; int ans = 0; while(left <= right) { int mid = (left + right) / 2; if(check(mid, arr, k)) { ans = mid; left = mid + 1; } else { right = mid - 1; } } System.out.print(ans); } /** 用连续 n个 能不能加起来小于 k */ public static boolean check(int n, int[] arr, int k) { int sum = 0; for(int i = 0; i < n; i++) { sum += arr[i]; } int left = 0; int right = n; while(sum > k && right < arr.length) { sum += arr[right++]; sum -= arr[left++]; } return sum <= k; } }
#include <bits/stdc++.h> using namespace std; int main(){ int N, k; cin>>N>>k; vector<int> nums(N); for(int i=0;i<N;++i) cin>>nums[i]; vector<int> minSums(N), minSumEnds(N); minSums[N-1] = nums[N-1]; minSumEnds[N-1] = N-1; for(int i=N-2;i>=0;--i){ // 生成minSums和minSumEnds if(minSums[i+1] <= 0){ minSums[i] = nums[i] + minSums[i+1]; minSumEnds[i] = minSumEnds[i+1]; } else{ minSums[i] = nums[i]; minSumEnds[i] = i; } } int sum = 0, res = 0, right=0; for(int i=0;i<N && right<N;++i){ // 对每个初始位置寻找满足条件的最长子数组 while(right<N && sum+minSums[right]<=k){ sum += minSums[right]; right = minSumEnds[right] + 1; } res = max(res, right-i); if(right > i) sum -= nums[i]; else right = i+1; } cout<<res; return 0; }
#include <bits/stdc++.h> using namespace std; int main(){ int n, k; scanf("%d%d", &n,&k); vector<int> arr(n); for(int i=0; i<n; i++) scanf("%d", &arr[i]); vector<int> minSum(n,0); vector<int> minIndex(n,0); minSum[n-1] = arr[n-1]; minIndex[n-1] = n-1; for(int i=n-2; i>=0; i--){ if(minSum[i+1] <= 0){ minSum[i] = arr[i] + minSum[i+1]; minIndex[i] = minIndex[i+1]; }else{ minSum[i] = arr[i]; minIndex[i] = i; } } int cur = 0, start = 0;; int sum = 0, len = 0; while(cur < n){ sum += minSum[cur]; if(sum <= k){ len = max(len, minIndex[cur]-start+1); if(len >= (n-start)) break; cur = minIndex[cur] + 1; }else{ while(sum > k){ sum -= arr[start]; start++; } len = max(len, minIndex[cur]-start+1); cur = minIndex[cur] + 1; } } cout << len; return 0; }
#include<bits/stdc++.h> using namespace std; int main() { int n,k; cin>>n>>k; vector<int>v(n); for(int i=0;i<n;++i) cin>>v[i]; vector<int>minSums(n); vector<int>minSumEnds(n); minSums[n-1] = v[n-1]; minSumEnds[n-1] = n-1; for(int i=n-2;i!=-1;--i) { if(minSums[i+1]<0) { minSums[i] = v[i] + minSums[i+1]; minSumEnds[i] = minSumEnds[i+1]; } else { minSums[i] = v[i]; minSumEnds[i] = i; } } int end = 0; int sum = 0; int res = 0; for(int i=0;i<n;++i) { while(end<v.size() && sum+minSums[end]<=k) { sum += minSums[end]; end = minSumEnds[end] + 1; } res = max(res,end-i); if(end>i) sum-=v[i]; else end = i+1; } cout<<res<<endl; }
import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int N = in.nextInt(); long k = in.nextLong(); int[] arr = new int[N]; for (int i = 0; i < N; i++) { arr[i] = in.nextInt(); } int[] sums = new int[N]; Map<Integer, Integer> map = new HashMap<>(); sums[N-1] = arr[N-1]; map.put(N-1, N-1); for (int i = N-2; i >= 0; i--) { if (sums[i+1] < 0) { sums[i] = arr[i] + sums[i+1]; map.put(i, map.get(i+1)); } else { sums[i] = arr[i]; map.put(i, i); } } int res = 0, sum = 0, end = 0; for (int i = 0; i < N; i++) { while (end < N && sum + sums[end] <= k) { sum += sums[end]; end = map.get(end) + 1; } res = Math.max(res, end - i); sum -= end > i ? arr[i] : 0; end = Math.max(end, i+1); } System.out.println(res); } }