码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-10-19 00:25:00      阅读:323      评论:0      收藏:0      [点我收藏+]

标签:

昨天做爱奇艺笔试题,最后一道编程题是求整型数组最长递增子序列,由于时间关系,没有完全写出来,今天重新来做做这一系列题。
《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("\n");
23         return max;
24     }
25 
26     int main(){
27         int input[] = {5,1,-2,4,9,1};
28         printf("maxmult : %d \n", 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 }

后续更新

 
 
 
 

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

标签:

原文地址:http://www.cnblogs.com/lerongwei/p/4890633.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!