算法练习——和最接近于零的子数组

问题描述:

求对于长度为N的数组A,求子数组的和接近0的子数组,要求时间复杂度O(NlogN)

(1) 求出所有的sum[i]  sum[i]表示A的前 i 项和
(2) 对sum[-1,0,...,N-1]排序,然后计算sum相邻元素的差的绝对值,最小记为 min1   
(3) min1 : 在A中任意取两个相邻子数组的和,求两者差的最小值。(相当于 i——j和的最小值)
(4) min2 : A的前k个元素的和的绝对值的最小值(为sum[0,1....n-1]中的最小值)
(5) min1和min2更小者,即为所求。

 1 public class SumIsZero {
 2     public static int SumMinIsZero(int[] a, int length){
 3         int[] sum = new int[length];
 4         //同时定义sum[-1] = 0;
 5         //sum[-1] = 0;
 6         //求前n项的和并且存在sum数组中,在从里面求出绝对值最小的数
 7         sum[0] = a[0];
 8         int i;
 9         //求出所以的sum[i]
10         for (i = 1; i < length; i++) {
11             sum[i] = sum[i-1]+a[i];
12         }
13         int min2 = Math.abs(sum[0]);
14         for (i = 0; i < sum.length; i++) {
15             if (Math.abs(sum[i]) < min2)
16                 min2 = Math.abs(sum[i]);
17         }
18
19         //同时对数组sum做排序
20         quickSort(sum, 0, length-1);
21
22         //求sum排序之后的相邻元素的最小值min1
23         int min1 = Math.abs(sum[0]-sum[1]);
24         for (int j = 2; j < sum.length; j++) {
25             if (Math.abs(sum[j] - sum[j-1]) <min1)
26                 min1 = Math.abs(sum[j] - sum[j-1]);
27         }
28         return (min1 > min2 ? min2:min1);
29     }

快速查找(保证满足题目的时间复杂度)

 1 public static void quickSort(int[] a, int low,int high){
 2         int i,j;
 3         int temp;
 4
 5         i=low;
 6         j=high;
 7         temp=a[low];                //取第一个元素为标准数据元素
 8         //下面的对左边和右边的扫描定位反复进行,直到左边的下标i大于或者等于右边元素的下标为止
 9         while(i<j){
10             //在数组的右边扫描,如果数大于哨兵,则不改变位置,否则将j上的元素马上移动到i位置,
11             //并且马上扫描左边
12             while( i < j&& a[j]>=temp) j--;
13             if (i<j) {
14                 a[i]=a[j];
15                 i++;
16             }
17
18             //在数组的左边扫描,如果数小于哨兵,则不改变位置,否则将左边i处的位置交换到
19             //右边j处的位置,并且转回扫描右边
20             while( i < j&& a[i] < temp) i++;
21             if (i<j) {
22                 a[j]=a[i];
23                 j--;
24             }
25         }
26
27         a[i]=temp;
28
29         //对左边的子集合做递归查询
30         if (low<i) {
31             quickSort(a, low, i-1);
32         }
33         //对右边的子集合做递归查询
34         if (i<high) {
35             quickSort(a, j+1, high);
36         }
37     }

但是以上算法只是简单的得到了最接近零的子数组的和,并没有得到所有的子数组。

时间: 2024-08-02 03:06:00

算法练习——和最接近于零的子数组的相关文章

LintCode-最接近零的子数组和

给定一个整数数组,找到一个和最接近于零的子数组.返回第一个和最有一个指数.你的代码应该返回满足要求的子数组的起始位置和结束位置 样例 给出[-3, 1, 1, -3, 5],返回[0, 2],[1, 3], [1, 1], [2, 2] 或者[0, 4] 挑战 O(nlogn)的时间复杂度 分析:首先O(n^2)的算法很好想,直接枚举起点就行,看到挑战的复杂度,想肯定要排序或者二分什么的,这里没找出能二分的性质来,所以想只能想排序了,我们知道连续数组的和其实就是前缀和之间的差,而要求和最接近于零

(算法)和为0的最大连续子数组

题目: 和为零的最大连续子数组 思路: 我首先想到的是前缀数组和,遍历一遍数组,计算出sum[i](表示从0-i的子数组之和). 有了前缀数组和,只要sum[i]=sum[j](i<j),那么区间[i+1,j]就是和为零的子数组,只要在遍历前缀数组和时记录最长的区间即可. 需要注意的是:当sum[i]等于0时,其区间为[0,i]. 在判断sum[i]=sum[j](i<j)时,有个查找的过程,要么直接遍历j左边的所有数(增加时间复杂度),要么通过map来存储对应和的下标位置(空间换时间).(详

算法学习笔记:最大连续子数组

寻找最大连续子数组 这两天看了看数据结构与算法,对其中一个问题颇感兴趣,所以在这里写一下.问题:寻找最大连续子数组. 问题:在一个有正有负的数组中,寻找一个连续的.和最大的子数组.这个数组类似于下面的数组,否则这个问题没有意义(如果全是正数的话,所有数组元素的和一定是最大的,同样全为负数也没有意义.). int a={1,-2,3,45,-78,34,-2,6}; 解法一:暴力求解. 那么如何来解决这个问题呢?这个思路要起来并不难,绝大多数人会想到这样的办法:遍历该数组的所有子数组,找到和最大的

笔试算法题(22):二分法求旋转数组最小值 &amp; 骰子值概率

出题:将一个数组最开始的k个(K小于数组大小N)元素照搬到数组末尾,我们称之为数组的旋转:现在有一个已经排序的数组的一个旋转,要求输出旋转数组中的最小元素,且时间复杂度小于O(N): 分析: 时间复杂度小于O(N)也就是不能用常规的遍历思路:可以将数组看成两个都是递增序列(假设为升序)的子数组,并且前半段的元素均大于等于后半段的元素,分界点的位于后半段数组的第一个元素就是最小元素: 具体算法:两个指针left和right指向数组第一个和最后一个元素,使用Binary Search确定中间元素mi

Effective Java 之-----返回零长度的数组或集合而不是null

如下代码,通常用户列表为空时,会习惯性返回null,因为这时会认为:null返回值比零长度数组更好,因为它避免了分配数组所需要的开销. private final List<UserBean> UserList = null; public List<UserBean> getUserBean(){ if(UserList.size() == 0){ return null; }else{ return UserList; } } 但这种观点是站不住脚的,原因如下: 1) 在这个级

返回零长度的数组或者集合,而不是null——Effective Java 读书笔记

/** * 返回零长度的数组或者集合,而不是null * * @author 刘向峰 * */ public class Shop { private List<Object> objectList; // 零长度数组常量被传递给toArray方法,以指明所期望的返回类型 private final static Object[] EMPTY_OBJECT_ARRAY = new Object[0]; public Shop(List<Object> objectList) { s

算法 | 最大连续子数组

最大连续子数组 给定一个数组A[0,1,-,n-1],求A的连续子数组,使得该子数组的和最大. 例如: 数组:1,-2,3,10,-4,7,2,-5 最大字数组:3,10,-4,7,2 此问题有以下四种方法 1.  暴力法 2.  分治法 3.  分析法 4.  动态规划法 暴力法 直接求解A[I,-j]的值,其中,0<=i<n,i<=j<n,因为i,i+1,-j的最大长度为n,所以时间复杂度O(n3). //暴力法 int MaxSubArray(int *a, int n) {

经典算法题每日演练——第十题 树状数组

原文:经典算法题每日演练--第十题 树状数组 有一种数据结构是神奇的,神秘的,它展现了位运算与数组结合的神奇魅力,太牛逼的,它就是树状数组,这种数据结构不是神人是发现不了的. 一:概序 假如我现在有个需求,就是要频繁的求数组的前n项和,并且存在着数组中某些数字的频繁修改,那么我们该如何实现这样的需求?当然大家可以往 真实项目上靠一靠. ① 传统方法:根据索引修改为O(1),但是求前n项和为O(n). ②空间换时间方法:我开一个数组sum[],sum[i]=a[1]+....+a[i],那么有点意

返回零长度的数组或者集合,而不是null

<<Effective Java>> 第四十三条:返回零长度的数组或者集合,而不是null 如果一个方法的返回值类型是集合或者数组 ,如果在方法内部需要返回的集合或者数组是零长度的,也就是没有实际对象在里面, 我们也应该放回一个零长度的数组或者集合,而不是返回null.如果返回了null,客户端程序员就要检测返回的是不是null,然后才能 进行下一步操作,否则就会引发NullPointException.但是如果是返回的的是空数组或者集合,就不会再后续的使用这个对象上,引发 空指针