• 最大子数组之和、最大子数组之积、最长递增子序列求法


    昨天做爱奇艺笔试题,最后一道编程题是求整型数组最长递增子序列,由于时间关系,没有完全写出来,今天重新来做做这一系列题。
    《1》 最大子数组之和
    首先从最简单的最大子数组之和求取。数组里有正数、负数、零。设包含第  i  个元素的子数组的和为 Sum,则Sum的值为
    Sum(i) = Sum(i-1) + arrey[i]; 显然如果arrey[i]<=0,则Sum(i)<=Sum(i-1);则必须把Sum(i)=arrey[i];同时maxSum用来保存Sum最大值。时间复杂度为o(n);

    #include<iostream>
    #include<math.h>
    using namespace std;
    int  max(int a,int b){
    	return a>b?a:b;
    }
    int FindGreatestSumOfSubArrey(int input[],int length){
    	int TempSum=input[0];
    	int MaxSum=TempSum;
    	for (int i = 1;i < length; i++){
    		TempSum = max(TempSum + input[i],input[i]);
    		MaxSum = max(TempSum,MaxSum);
    	}
    	return MaxSum;
    }
    
    int main(){
    	int input[] = {1,-2,-5,3,5};
    	cout<<FindGreatestSumOfSubArrey(input,5)<<endl;// 结果为8
    	return 0;
    }
    

     上面题目中,如果要求返回和最大子数组,则可以设置两个指针begin,end来指向maxSum的第一个元素和最后一个元素。 设置指针first,last来指向当前Sum的第一个元素和最后一个元素。当Sum>=maxSum时,如果begin=first时,通过last来更新end,如果begin!=first,则设置begin=first,end=last. 当Sum<maxSum时,保持begin 和first值不变。

     1 #include<iostream>
     2 #include<math.h>
     3 using namespace std;
     4 int  max(int a,int b){
     5     return a>b?a:b;
     6 }
     7 void FindGreatestSumOfSubArrey(int input[],int length){
     8     int TempSum=input[0];
     9     int MaxSum=TempSum;
    10     int first,last;
    11     int begin,end;
    12     first = last = begin = end = 0;
    13     for (int i = 1;i < length; i++){
    14         TempSum += input[i];
    15         if (TempSum <= input[i]){
    16             first = last = i;
    17             TempSum = input[i];
    18         }
    19         else
    20             last = i;
    21         if (MaxSum <= TempSum){
    22             MaxSum = TempSum;
    23             begin = first;
    24             end = last;
    25         }
    26             
    27     }
    28     cout<<"MaxSum = "<<MaxSum<<endl;
    29     for (i = begin; i <= end; i++)
    30         cout<<input[i]<<" "; // 输出子数组
    31 }
     1 int main(){
     2     int test1[] = {1,-2,-5,3,5};
     3     int test2[]={1,1,1,1,1};
     4     int test3[]={-1,-1,-1,-1,-1};
     5     int test4[]={-1,2,-3,1,1};
     6     FindGreatestSumOfSubArrey(test1,5);
     7     cout<<endl;
     8     FindGreatestSumOfSubArrey(test2,5);
     9     cout<<endl;
    10     FindGreatestSumOfSubArrey(test3,5);
    11     cout<<endl;
    12     FindGreatestSumOfSubArrey(test4,5);
    13     cout<<endl;
    14     return 0;
    15 }
    对于第四组测试数据,其中有最大子数组之和有两个。一个{2},另一个是{1,1};上述代码得到的是后一种答案,有兴趣的可以把最大和相同的子数组全部输出。
    《2》最大子数组之积 分别求取以第i个元素开始的数组的积,然后在求取所有积中最大值即可。时间复杂度为o(n^2)
     1  #include <stdio.h>
     2     int getmaxsub(int *input, int size){
     3         if(input == NULL || size == 0) return 0xFFFF;
     4         if(size == 1) return input[0];
     5         int current_product;
     6         int max = input[0];
     7         int first,last;
     8         first = last = 0;
     9         for(int len = 0;len<size;len++){
    10             current_product =input[len];
    11             for(int end = len + 1; end < size; end++){
    12                 current_product *= input[end];
    13                 if(current_product > max){
    14                     first = len ;
    15                     last = end;
    16                     max = current_product;    
    17                 }
    18             }
    19         }
    20         for (int k = first; k <= last ;k++)
    21             printf("%d ",input[k]);
    22         printf("
    ");
    23         return max;
    24     }
    25 
    26     int main(){
    27         int input[] = {5,1,-2,4,9,1};
    28         printf("maxmult : %d 
    ", getmaxsub(input,6));
    29         return 0;
    30     }
    动态规划做法,假设数组为a[N],max[N] 表示以下标为 i 结尾的子数组乘积最大值,min[N] 表示以下标为 i 结尾的子数组乘积最小值。为了处理数组元素为负的问题,必须将最小乘积也保存起来。很容易想到,若当前元素a[i]为负数,那么a[i]*max[i-1]得到的值并不一定比a[i]*min[i-1]大,因为min[i-1]可能为负,如果min[i-1]的绝对值大于max[i-1],那么a[i]*min[i-1]负负相乘的值是更大的,因此有转移方程:
    max[i] = MaxinThree(a[i],  a[i]*max[i-1],  a[i]*min[i-1]);    //求三者最大
    min[ i] = MininThree(a[i],  a[i]*max[i-1],  a[i]*min[i-1]);     //求三者最小
     1 #include<stdio.h>
     2 #include<iostream>
     3 using namespace std;
     4 int MaxinThree(int a, int b, int c)  
     5     {  
     6         return (((a>b)?a:b)>c) ? (a>b?a:b) : c;  
     7     }  
     8 int MininThree(int a, int b, int c)  
     9     {  
    10         return (((a<b)?a:b)<c) ? (a<b?a:b) : c;  
    11     }  
    12 void FindGreatestMultiOfSubArrey(int *input,int size){
    13     int *max = new int[size];
    14     int *min = new int[size];
    15     int product;
    16     max[0] = min [0] = input[0];
    17     product = max[0];
    18     for (int i = 1; i < size; i++){
    19         max[i] = MaxinThree(input[i],input[i]*max[i-1],input[i]*min[i-1]);
    20         min[i] = MininThree(input[i],input[i]*min[i-1],input[i]*max[i-1]);
    21         if(max[i] > product)
    22             product = max[i];
    23     }
    24     cout<<product<<endl;
    25 }
    26 int main(){
    27     int input[] = {5,-1,-2,4,9,1};
    28     void FindGreatestMultiOfSubArrey(int *input,int size);
    29     FindGreatestMultiOfSubArrey(input,6);
    30     return 0;
    31 
    32 }
    《3》最长递增子序列
    最长递增序列不要求数组元素连续问题,返回递增序列长度和递增序列。o(n^2)做法,顺序比较以第i个元素开头的递增序列即可。

     1 #include<stdio.h>
     2 #include<iostream>
     3 using namespace std;
     4 void FindGreatestAddOfSubArrey(int *input,int size){
     5     int *result = new int[size];
     6     int *pre = new int[size];
     7     int k,MaxLen = 0;
     8     for (int len = 0; len < size; len++){
     9          int temp = input[len];
    10          int cnt = 0;
    11          pre[0] = input[len];
    12          for(int end = len + 1; end < size; end++){
    13             if (input[end] > temp){
    14                 temp = input[end];
    15                 pre[++cnt] = temp;
    16             }
    17         }
    18         if (cnt >= MaxLen){
    19             k = 0;
    20             MaxLen = cnt;
    21             while(k <= cnt){
    22                 result[k] = pre[k];
    23                 k++;
    24             }
    25         }
    26     }
    27     cout<<MaxLen+1<<endl;
    28     for(int i = 0;i < k; i++)
    29         cout<<result[i]<<" ";
    30     cout<<endl;
    31 }
    32 
    33 int main(){
    34     int test1[] = {5,-1,-2,4,9,1};
    35     int test2[] = {1,2,3,4,5,6};
    36     int test3[] = {6,5,4,3,2,1};
    37     FindGreatestAddOfSubArrey(test1,6);
    38     FindGreatestAddOfSubArrey(test2,6);
    39     FindGreatestAddOfSubArrey(test3,6);
    40     return 0;
    41 }
    利用动态规划来做,假设数组为1, -1, 2, -3, 4, -5, 6, -7。我们定义LIS[N]数组,其中LIS[i]用来表示以array[i]为最后一个元素的最长递增子序列。
    使用i来表示当前遍历的位置:
    当i = 0 时,显然,最长的递增序列为(1),则序列长度为1。则LIS[0] = 1
    当i = 1 时,由于-1 < 1,因此,必须丢弃第一个值,然后重新建立序列。当前的递增子序列为(-1),长度为1。则LIS[1] = 1
    当i = 2 时,由于2 > 1,2 > -1。因此,最长的递增子序列为(1, 2),(-1, 2),长度为2。则LIS[2] = 2。
    当i = 3 时,由于-3 < 1, -1, 2。因此,必须丢掉前面的元素,重建建立序列。当前的递增子序列为(-3),长度为1。则LIS[3] = 1。
    依次类推之后,可以得出如下结论。
    LIS[i] = max{1, LIS[k] + 1}, array[i] >array[k], for any k < i
    最后,我们取max{Lis[i]}。
     1 #include<stdio.h>
     2 #include<iostream>
     3 using namespace std;
     4 void FindLongestAscSequence(int *input,int size){
     5     int *list = new int[size];// 用来存储以第i个元素结尾的最长递增子序列
     6     int MaxLen = 1;
     7     int k = 0;
     8     for (int i = 0; i < size; i++){
     9         list[i] = 1 ;
    10         for ( int j = 0; j < i; j++){
    11             if ((input[i] > input[j]) && (list[j] +1 > list[i]) )
    12                    list[i] = list[j] + 1;
    13         }
    14         if (MaxLen < list[i]){
    15             MaxLen = list[i];
    16         }
    17     }
    18     cout<<MaxLen<<endl;
    19 }
    20 
    21 int main(){
    22     int test1[] = {5,-1,-2,4,9,1};
    23     int test2[] = {1,2,3,4,5,6};
    24     int test3[] = {6,5,4,3,2,1};
    25     FindLongestAscSequence(test1,6);
    26     FindLongestAscSequence(test2,6);
    27     FindLongestAscSequence(test3,6);
    28     return 0;
    29 }

    后续更新

     
     
     
     
  • 相关阅读:
    BZOJ 1069 最大土地面积
    BZOJ 1059 矩阵游戏
    BZOJ 3570 动物园
    Luogu 3934 Nephren Ruq Insania
    Luogu 3233 [HNOI2014]世界树
    CF613D Kingdom and its Cities
    Luogu 4001 [BJOI2006]狼抓兔子
    Luogu 2824 [HEOI2016/TJOI2016]排序
    POJ 3463 Sightseeing
    Luogu 2495 [SDOI2011]消耗战
  • 原文地址:https://www.cnblogs.com/lerongwei/p/4890633.html
Copyright © 2020-2023  润新知