数组变换问题

1、数组切分问题

题目: 输入一个正序排列的整型数组,如果它可以被切分为1个或多个子序列,输出True,反之False。子序列需为连续的整型数组,并且长度至少为3。
示例:
例1:
输入: [1,2,3,3,4,5]
输出:True
解释:可以切分为2个各自连续的子序列:
1, 2, 3
3, 4, 5
例2:
输入: [1,2,3,3,4,4,5,5]
输出:True
解释:可以切分为2个各自连续的子序列:
1, 2, 3, 4, 5
3, 4, 5
例3:
输入: [1,2,3,4,4,5]
输出:False
解释:无法切分出长度至少为3的子序列。

分析: 此题用贪心算法。创建两个哈希map,freq用来建立数和其出现次数的映射,need记录这个数字可以跟在已有序列后面的次数。首先使用两个哈希map。
freq[i]:存储原数组中数字i出现的次数
need[i]:存储以数字i结尾的且符合题意的连续子序列个数

  • 先去寻找一个长度为3的连续子序列i, i+1, i+2,找到后就将freq[i], freq[i+1], freq[i+2]中对应数字消耗1个(即-1),并将need[i+2]加1,即以i+2结尾的子序列个数+1。
  • 如果后续发现有能够接在这个连续子序列的数字i+3,则延长以i+2为结尾的连续子序列到i+3,此时消耗freq[i+3]一个,由于子序列已延长,因此need[i+2]减1,need[i+3]加1。
    在不满足上面的情况下:
  • 如果freq[i]为0,说明这个数字已经消耗完,可以不管了
  • 如果freq[i]不为0,说明这个数字多出来了,且无法组成连续子序列,所以可以直接返回false了。因此,只有检查到某个数时,这个数未被消耗完,且既不能和前面组成连续子序列,也不能和后面组成连续子序列时,无法分割。
bool solution(vector<int> input){
    
    
    if (input.size()<3) return false;
    unordered_map<int, int> freq;
    for (int i:input){
    
    
        freq[i]++;
    }
    unordered_map<int, int> seq;
    for(int i:input){
    
    
        if(freq[i]==0) continue;
        if(seq[i-1]!=0){
    
    
            seq[i-1]--;
            seq[i]++;
            freq[i]--;
        }else if(freq[i+1]>0&&freq[i+2]>0){
    
    
            freq[i]--;
            freq[i+1]--;
            freq[i+2]--;
            seq[i+2]++;
        }else{
    
    
            return false;
        }
    }
    return true;
}

2、数组极差问题

小Q的好朋友牛牛在纸上写了长度为n的正整数数列。牛牛要求小Q每次从数列中选取两个数a,b,把这两个数从数列中移除出去,然后在数列中加入a * b + 1,直到只剩一个数为止。小Q发现根据操作顺序的不同,最后得到的数的大小也不一样。小Q现在想让你帮他计算,在所有情况中能获得的最大值减去能获得的最小值等于多少? 极差问题证明

输入:
3
1
2
3
输出:
2

解题方法:

第一步:先要对你输入的一个数组进行排序

第二步:擦掉最小的两个数,然后插入a*b+1 继续擦掉最小的数,最终得到最大值。

第三步:擦掉最大的两个数,然后插入a*b+1继续擦掉最大的数,最终得到最小值。

int solution2(vector<int> input){
    
    
    int len=input.size();
    if (len<3) return 0;
    sort(input.begin(),input.end());
    int max=input[0]*input[1]+1;
    int min=input[len-1]*input[len-2]+1;
    for (int i=2;i<len;i++){
    
    
        max=max*input[i]+1;
    }
    for (int i=len-3;i>=0;i--){
    
    
        min=min*input[i]+1;
    }
    return max-min;
}

3、自增数组问题

题目: 小Q发现了一种特殊的数组,叫做自增数组。这个数组支持一种操作:每次操作可以把数组中的一个数自增1.
现在有一个长度为n的自增数组,小Q现在想利用这个操作把数组中的每个数变得不一样,英文最少需要多少次操作?

输入描述:
第一行,一个整数n(n<=10000)
第二行,n个空格间隔的整数,即数组中的元素ai(-10000<=ai<10000)

input
5
1 2 3 2 5
output
2

扫描二维码关注公众号,回复: 12329392 查看本文章
int solution3(vector<int> input){
    
    
    int len=input.size();
    if (len<=1) return 0;
    sort(input.begin(),input.end());
    int maxLen=max(len+1,input[len-1]+1);
    vector<int> dup;
    for (int i=1;i<len;i++){
    
    
        if(input[i]==input[i-1])
            dup.push_back(input[i]);
    }
    vector<int>newArray(maxLen+dup.size(),0);
    for (int i=0;i<len;i++){
    
    
        newArray[input[i]]=input[i];
    }
    int index=0;
    int cnt=0;
    for (int i=0;i<len;i++){
    
    
       if (index==dup.size()) break;
       if(newArray[i]!=i){
    
    
            if(dup[index]<i){
    
    
              cnt+=(i-dup[index++]);
            } 
        }
        
    }
    return cnt;
}

猜你喜欢

转载自blog.csdn.net/u014618114/article/details/108131967