首页 > 试题广场 >

求最长可整合子数组的长度

[编程题]求最长可整合子数组的长度
  • 热度指数:428 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
先给出可整合数组的定义: 如果一个数组arr在排序之后,从最小值到最大值的顺序中,每相邻两个数之间差的绝对值都为1,则arr为可整合数组。 例如: arr = {5,3,4,6,2},再排序之后为:{2,3,4,5,6},排序后符合每相邻两个数之间差的绝对值都为1,所以arr是可整合数组。 给定一个整形数组arr,请返回其中长度最大的可整合子数组的长度。
[5,0,1,2,4,3,9],最长可整合子数组为[5,0,1,2,4,3],所以返回6
[6,7,3,0,1,2,4,7],最长可整合子数组为[3,0,1,2,4],所以返回5
 要求:如果数组长度为N,时间复杂度请达到O(N^2)
class Solution {
    const int INF=999999999;
public:
    int getMaxLength(vector<int> arr, int len) {
        int i,j,maxLen=0;
        for(i=0;i<len;i++){
            map<int,int> book;
            int Max=-INF,Min=INF;
            for(j=i;j<len;j++){
                if(book.count(arr[j]))
                    break;
                book[arr[j]]=1;
                Max=max(Max,arr[j]);
                Min=min(Min,arr[j]);
                if(Max-Min==j-i) 
                    maxLen=max(maxLen,j-i+1);
            }
        }
        return maxLen;
    }
};

发表于 2017-10-16 23:42:45 回复(0)
判断长度、和、乘积。。。。乘积有点hash的意味。。欢迎来hack这个代码。。。
int getMaxLength(vector<int> arr, int len) {
        int ans = 0;
        for(int i = 0; i < len && len - i > ans; ++i){
            int mi, mx;
            long long sum = 0, hash = 1, he;
            for(int j = i; j < len; ++j){
                if(j == i) mi = mx = arr[j], he = arr[j] | 1;
                else{
                    if(arr[j] < mi){
                        if(mx - arr[j] + 1 > len - i) break;
                        else while(mi > arr[j]) he *= (--mi) | 1;
                    }
                    else if(arr[j] > mx){
                        if(arr[j] - mi + 1 > len - i) break;
                        else while(mx < arr[j]) he *= (++mx) | 1;
                    }
                }
                sum += arr[j];
                hash *= (arr[j] | 1);
                if(mx - mi + 1 == j - i + 1 && 1LL * (mi + mx) * (j - i + 1) / 2  == sum && hash == he) if(ans < j - i + 1) ans = j - i + 1;
            }
        }
        return ans;
    }

=======update 2015-04-08 15:40=====================================

鉴于有一些人不满意之前的比较简便的hash的做法。。那就另写一个吧。。
还是暴力枚举起点和终点,如果最大值-最小值+1等于长度,而且这中间没有相同的,就是合法的子数组。
这个相同的数的判断,对数据离散处理即可(我猜这里的数据这么弱不用离散也是可以的。。).
O(n)的额外内存,最坏时间是O(n^2)
typedef pair<int, int> pii;
bool cmpid(pii a, pii b){ return a.second < b.second; }
class Solution {
public:
 /**
 *	在数组中求长度最大的可整合子数组长度
 *	arr:输入数组
 *	返回:最大的可整合子数组的长度
 */
 int getMaxLength(vector<int> arr, int len) {
        if(len <= 0) return 0;
        vector<pii> tmp(len);
        for(int i = 0; i < len; ++i) tmp[i] = pii(arr[i], i);
        sort(tmp.begin(), tmp.end());
        int pre = tmp[0].first;
        tmp[0].first = 0;
        for(int i = 1; i < len; ++i) {
            if(tmp[i].first == pre) tmp[i].first = tmp[i - 1].first;
            else pre = tmp[i].first, tmp[i].first = tmp[i - 1].first + 1;
        }
        sort(tmp.begin(), tmp.end(), cmpid);
        for(int i = 0; i < len; ++i) tmp[i].second = arr[i];
        int ans = 0;
        for(int i = 0; i < len; ++i){
            vector<bool> has(tmp[len - 1].first + 1, false);
            int mi = 0x7fffffff, mx = 0x80000000;
            for(int j = i; j < len; ++j){
                if(has[tmp[j].first]) break;
                has[tmp[j].first] = true;
                if(tmp[j].second < mi) mi = tmp[j].second;
                if(tmp[j].second > mx) mx = tmp[j].second;
                if(mx - mi == j - i && j - i + 1 > ans) ans = j - i + 1;
            }
        }
        return ans;
    }
};

编辑于 2015-04-08 15:43:35 回复(7)
整合数组另一种表达方式是子数组最大值-最小值和长度的关系,,,利用这个条件就可解出
同时注意有重复的数字不符合条件,用的是hash来解决的
class Solution {
public:
	int getMaxLength(vector<int> arr, int len) {
        if(len <= 0) return 0;
		int minNum = 0;
        int maxNum = 0;
        int ret = 0;
        set<int> s;
        for(int i = 0; i < len; i++){
            minNum = arr[i];
            maxNum = arr[i];
            for(int j = i; j < len; j++){
                if(s.find(arr[j]) != s.end()){
                    break;
                }
                s.insert(arr[j]);
                minNum = min(arr[j], minNum);
                maxNum = max(arr[j], maxNum);
                if(maxNum - minNum == j - i){
                    ret = max(ret, maxNum-minNum+1);
                }
            }
            s.clear();
        }
        return ret;
    }
};

编辑于 2016-08-08 17:21:44 回复(0)
求解答,为什么不让用hash_map,我感觉我写的是对的啊!!!!!!

int getMaxLength(vector<int> arr, int len) 
{
    if (arr.empty() || len <= 0)
    {
        return 0;
    }
    int res = 1;
    for (int i = 0; i < len; i++)
    {
        hash_map<int, int> pool;
        int max = arr.at(i);
        int min = arr.at(i);
        for (int j = i; j < len; j++)
        {
            if (pool.find(arr.at(j)) != pool.end())
            {
                break;
            }
            pool[arr.at(j)] = 0;
            max = arr.at(j)>max ? arr.at(j) : max;
            min = arr.at(j) < min ? arr.at(j) : min;
            if (j - i == max - min)
            {
                res = j - i>res ? j - i : res;
            }
        }
    }
    return res + 1;
}
发表于 2018-07-30 10:05:18 回复(0)
class Solution {
public:
	/**
	 *	在数组中求长度最大的可整合子数组长度
	 *	arr:输入数组
	 *	返回:最大的可整合子数组的长度
	 */
	int getMaxLength(vector<int> arr, int len) {
        //可整合子数组没有重复(一旦出现就没有必要往右继续找了)
        //最大值-最小值+1 =  长度
        int res = 0;
        map<int,int>help;
        for(int i=0;i<len;i++)
        {
            int max=0x80000000;  
            int min=0x7fffffff;
            for(int j=i;j<len;j++)
            {
               if(help[arr[j]]!=0)
                {
                    break;
                }
                help[arr[j]]++;
                max = max>arr[j]?max:arr[j];
                min = min<arr[j]?min:arr[j];
                if(max-min == (j-i))
                {
                   res = res>(max-min+1)?res:(max-min+1);
                }
            }
            help.clear();
        }
       return res;
    }
};

发表于 2016-05-28 18:55:30 回复(0)
class Solution {
public:
 /**
 *	在数组中求长度最大的可整合子数组长度
 *	arr:输入数组
 *	返回:最大的可整合子数组的长度
 *      思路:若数组长度为8,首先判断0-7;然后长度-1,判断0-6和1-7;
 *            .....直到长度为2,如果期间均没有,则结果为1
 *      判断方法:1.元素个数,假设最小值为3最大值为6,则应该有4个元素
 *             2.元素和,同上,取得3-6的和,以及数组中元素的和,比较
 *             3.元素积,注意去除0;
 *       因为要找到最长的,所以只要有符合的,就可一输出并结束程序
 */
 int getMaxLength(vector<int> arr, int len) {
        if(len==0)
            return 0;
        if(len==1)
            return 1;
        for(int i=0;i<len-1;i++)
        {
            int start=0,end=len-1-i;
            while(end<len)
            {
                int min=arr[start];
                int max=arr[start];
                long long sum=arr[start];
                long long res;
                if(arr[start]==0)
                    res=1;
                else
                    res=arr[start];
                for(int j=start+1;j<=end;j++)
                {
                    if(arr[j]<min) min=arr[j];
                    if(arr[j]>max) max=arr[j];
                    sum+=arr[j];
                    if(arr[j]!=0)
                    	res*=arr[j];
                }
                //判断1
                if((max-min)!=(end-start))
                {
                    start++;
                    end++;
                    continue;
                }
                //判断2
                long long sumR=(max+min)*(end-start+1)/2;
                if(sum!=sumR)
                {
                    start++;
                    end++;
                    continue;
                }
                //判断3
                long long resR=1;
                for(int k=min;k<min+end-start+1;k++)
                {
                    if(k!=0)
                        resR*=k;
                }
                if(res!=resR)
                {
                    start++;
                    end++;
                    continue;
                }
                return end-start+1;
            }
        }
        return 1;
    }
};
编辑于 2015-04-02 00:52:00 回复(0)

1.答案错误 [0,5,1,3,0,1,2,1] 输出应该为 :4

排序后为[0,0,1,1,1,2,3,5]

2.答案错误[6,8,7,1,5,3,8,5,8,6,5]输出应该为 :3
排序后为[1,3,5,5,5,6,6,7,8,8,8]

1和2两种输入不是类似的吗?计算结果却不一样。。。

发表于 2015-03-29 13:55:01 回复(7)
static void getMaxMakeArray(int[] arr){
        int[] temp = arr;
        for(int i=0;i<temp.length;i++){
            for(int j=i+1;j<temp.length;j++){
                int a = temp[i];
                int b = temp[j];
                if(a > b){
                    temp[i] = b;
                    temp[j] = a;
                }
            }
        }
        int count = 0;
        for(int i=0;i<temp.length-1;i++){
            if(temp[i+1]-temp[i] == 1){
                count++;
            }else{
                break;
            }
        }
        System.out.println("count:"+(count==0?0:count+1));
    }
发表于 2015-03-11 11:02:51 回复(0)
首先将数组进行排序,根据时间复杂度的要求得用冒泡排序,在循环排序后的新数组,累计连续的值的个数得到最多的连续个数,完成返回

发表于 2015-03-09 16:13:05 回复(2)