下面是小编帮大家整理的最大子数组问题(共含7篇),欢迎阅读,希望大家能够喜欢。同时,但愿您也能像本文投稿人“与之二三事”一样,积极向本站投稿分享好文章。
解法一:暴力求解
最简单最直接的想法就是我求出所有非空连续子数组的和,再通过比较找到最大的一个子数组不就行了吗。确实可以,通过for循环遍历我们可以得到这样的伪代码:
暴力求解伪代码:
FindMaxSubarray(A,low,high)
1. maxSum = 负无穷大
2. sum = 0
3. for i = 1 to n
4. for j = i to n
5. sum=sum+A[j]
6. if sum > maxSum
7.maxSum = sum
8.maxLeft = i
9.maxRight = j
10. sum = 0
11. return (maxLeft,maxRight,maxSum)
伪代码讲解:
第一二行,maxSum用来表示当前扫描过的最大子数组的和,sum用来表示当前子数组的和
第三到十行,主体扫描所有子数组并求和,记录最大子数组的起始位置i、结束位置j以及和sum
第十一行返回扫描结果
C语言完整代码:
/*Author: Terry Zhang*/
#include
#include
struct info{
int maxLeft;
int maxRight;
int Sum;
};
int main
{
size_t n;
scanf_s(“%d”, &n);
int *p = (int *)calloc(n, sizeof(int));
for (size_t i = 0; i < n; i++)
{
scanf_s(“%d”, p + i);
}
info Find_Max_Subarray(int A[], int low, int high);
info inf;
inf = Find_Max_Subarray(p, 0, n - 1);
//输出结果
printf(“MaxLeft:%dn”, inf.maxLeft+1); //默认起始位置为1
printf(“MaxRight:%dn”, inf.maxRight+1);
printf(“MaxSum:%dn”, inf.Sum);
if (p != NULL)
free(p);
return 0;
}
info Find_Max_Subarray(int A[], int low, int high)
{
int maxSum = INT_MIN;
int maxLeft = 0;
int maxRight = 0;
int sum = 0;
for (size_t i = low; i <= high; i++)
{
for (size_t j = i; j < high; j++)
{
sum += A[j];
if (sum >= maxSum)
{
maxSum = sum;
maxLeft = i;
maxRight = j;
}
}
sum = 0;
}
info inf;
inf.maxLeft = maxLeft;
inf.maxRight = maxRight;
inf.Sum = sum;
return inf;
}
复制代码
解法二:使用分治策略求解
使用分治策略意味着我们要把数组划分成两个规模尽量相等的子数组。以mid为划分点,则数组A[low,high]的任何连续子数组A[i,j]的位置必然有一下三种情况。
1. 完全位于子数组A[low,mid]中,此时low<=i<=j<=mid
2. 完全位于子数组A[mid,high]中,此时mid<=i<=j<=high
3. 跨越中点mid,此时low<=i<=mid
我们可以递归求解第一二种情况,因为它们仍然是最大子数组问题,只是规模更小。现在解决问题的重点落在了解决第三种情况,那就是子数组跨越中点情况。而仔细思考后我们发现第三种情况可以这样去处理,我们可以找到形如A[i,mid]和A[mid+1,j]的最大子数组,然后我们将两个子数组合并来得到A[low,high]跨越中点的“最大子数组”,当然这个子数组只是跨越中点的最大子数组,我们还需要将其和其它两种情况得到的最大子数组比较从而确定整个数组的最大子数组。
找到跨越中点的“最大子数组”的伪代码:
FindMaxCrossingSubarray(A,low,mid,high)
1. leftSum = 负无穷大
2. sum = 0
3. for i=mid downto low
4. sum = sum + A[i];
5. if sum > leftSum
6. leftSum = sum
7. maxLeft = i
8. sum = 0
9. rightSum = 负无穷大
10. for j=mid+1 to high
11. sum = sum + A[j]
12. if sum > rightSum
13. rightSum = sum
14. maxRight = j
15. return (maxLeft,maxRight,leftSum+rightSum)
伪代码讲解:
第一到七行找出A[low,mid]的最大子数组,并记录子数组最左侧的边界位置及子数组和
第八到十四行找出A[mid+1,high]的最大子数组,并记录子数组最右侧的边界位置及子数组的和
第十五行返回执行结果
FindMaxCrossingSubarray(A,low,mid,high)完整C代码如下:
info Find_Max_Crossing_Subarray(int A[], int low, int mid, int high)
{
int leftSum = INT_MIN;
info p;
int sum = 0;
for (int i = mid; i >= low; i--)
{
sum = sum + A[i];
if (sum > leftSum)
{
leftSum = sum;
p.maxLeft = i;
}
}
sum = 0;
int rightSum = INT_MIN;
for (int j = mid + 1; j <= high; j++)
{
sum = sum + A[j];
if (sum > rightSum)
{
rightSum = sum;
p.maxRight = j;
}
}
p.Sum = leftSum + rightSum;
return p;
}
复制代码
解决了问题的重头戏,我们也就很容易得到FindMaxSubarray的伪代码了,
求解最大子数组伪代码:
FindMaxSubarray(A,low,high)
1. if low == high
2. return (low,high,A[low])
3. else mid = (low+high)/2 向下取整
4. (leftLow,leftHigh,leftSum) = FindMaxSubarray(A,low,mid)
5. (rightLow,rightHigh,rightSum) = FindMaxSubarray(A,mid+1,high)
6. (crossLow,crossHigh,crossSum) = FindMaxCrossingSubarray(A,low,mid,high)
7. if leftSum >= rightSum and leftSum >= crossSum
8. return (leftLow,leftHigh,leftSum)
9. else if rightSum >= leftSum and rightSum >= crossSum
10. return (rightLow,rightHigh,rightSum)
11. else return (crossLow,crossHigh,crossSum)
这样求解最大子数组问题我们只需要初始调用A[A,1,A.Length]即可。
完整C代码如下:
info Find_Max_Subarray(int A[], int low, int high)
{
info pLeft, pRight, pCross;
if (low == high)
{
pLeft.maxLeft = low;
pLeft.maxRight = high;
pLeft.Sum = A[low];
return pLeft;
}
else
{
int mid = (low + high) / 2;
pLeft = Find_Max_Subarray(A, low, mid);
pRight = Find_Max_Subarray(A, mid + 1, high);
pCross = Find_Max_Crossing_Subarray(A, low, mid, high);
if (pLeft.Sum >= pRight.Sum && pLeft.Sum >= pCross.Sum)
{
return pLeft;
}
else if (pRight.Sum >= pLeft.Sum && pRight.Sum >= pCross.Sum)
{
return pRight;
}
else
return pCross;
}
}
复制代码
解法三:非递归、线性时间解法
有没有更好的算法呢。我们可以这样思考,从数组的左边界开始,由左到右处理,记录到目前为止已经处理过的最大子数组。而如果我们知道了A[1,j]的最大子数组,我们考虑A[1,j+1]的最大子数组的可能情况:
1. A[1,j+1]的最大子数组就是A[1,j]的最大子数组
2. A[1,j+1]的最大子数组为形如A[i..j+1]的最大子数组
而在我们在已知A[1..j]的最大子数组的情况下,我们可以很容易地在线性时间内找到A[1..j+1]的最大子数组。
伪代码:
FindMaxSubarray(A,low,high)
1. sum = 0
2. maxLeft = low
3. maxRight = low
4. maxSum = A[low]
5. for i = low to high
6. if sum >= 0
7. sum = sum + A[i]
8. else sum = A[i]
9. maxLeft = i
10. if sum > maxSum
11. maxSum = sum
12. maxRight = i
13. return (maxLeft,maxRight,maxSum)
伪代码讲解:
第一到四行进行初始化,其中sum代表以当前扫描位置的前一个位置为结束位置,起始为正数且和为正数的最长子数组,即形如A[x..i]且A[x]为正数,数组所有元素和为正数的最长子数组
第五到十二行为循环主体,当sum<= maxSum时即为第一种情况,当sum>maxSum时,即为第二种情况
第十三行返回执行结果
C语言完整代码:
info Find_Max_Subarray(int A[], int low, int high)
{
int sum = 0;
info inf;
inf.maxLeft = low;
inf.maxRight = low;
inf.Sum = 0;
for (size_t i = low; i < high; i++)
{
if (sum >= 0)
{
sum += A[i];
}
else
{
sum = A[i];
inf.maxLeft = i;
}
if (sum > inf.Sum)
{
inf.Sum = sum;
inf.maxRight = i;
}
}
return inf;
}
链接:click here
给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵,最大子矩阵求和 NYOJ 104 && 372 && HDU 1081。 例子: 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 其最大子矩阵为: 9 2 -4 1 -1 8 其元素总和为15。输入第一行输入一个整数n(0每组测试数据:
第一行有两个的整数r,c(0
随后有r行,每行有c个整数;
输出输出矩阵的最大子矩阵的元素之和。样例输入
14 40 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
样例输出
15
代码:
#include
先上代码吧:
?
#include
#include
using namespace std ;
int replacefun(char* str, char c1, char c2);
int main(void)
{
char * p = “I love you China, do you love me?”; // 用指针的形式定义一个字符数组
int m = 0;
m = replacefun(p, 'o', 'c');
cout << m << endl;
return 0;
}
int replacefun(char* str, char c1, char c2)
{
int num = 0;
while (*str != ' ')
{
if (*str == c1)
{
*str = c2; // 这句话调试的时候内存报错
num++;
}
str++;
}
return num;
}
这个程序实现的目的的是替换指定的字符,在编译的时候没有任何错误,但是在运行的时候,程序意外终止,
小小的C语言问题指针数组赋值关于指针和数组,
。
于是,启动利器,单步调试。。。跳进函数后,发现在*str到达'o'之前一切正常,不过。。到了'o'之后,结果说内存错误,无法赋值。
经过多方查找资料和询问,得知:
char *p=“abcde”;的时候,字符串是不可以修改的!
而char p[]=“abcde”;的时候,字符串是可以修改的!
同一个字符串,用指针定义的时候在常量区,而用数组定义的时候在栈中。
就是刚刚上面的那个
I love you China, do you love me?
是一个常量。
据大婶说:
“I love you China, do you love me?”
在存放在.rodata段,该段是只读的,当你强行做修改的时候,当然要报错喽。
而定义为数组的形式之后:就把这个字符串拷贝进数组了,对于数组中的内容,可以随便修改呀. 原来的字符串还是不变的。。。
以上总结,涨姿势了。
继续C++。
给定一个长度为N的整数数组,只允许用乘法,计算任意(N-1)个数的组合乘积中最大的一组,并写出算法的时间复杂度,
最容易想到的就是通过一次遍历把所有(N-1)个数的组合找出来,分别计算他们的乘积,并比较大小。由于总共有N个(N-1)个数的组合,总的时间复杂度为O(N的2次方),显然这不是最好的解决办法。
且看下面的实现方法,当然也是比较简单的,毕竟没太多时间思考,他的时间复杂度只有O(N)。
当然肯定有其他的方式解决这个问题,blog友如果有好的方式可以贴出来分享。谢谢!
1packageorg.blogjava.arithmetic;
2
3importjava.util.ArrayList;
4
5/** *//**
6*@authorJack.Wang
7*@seejack.blogjava.net/
8*/
9publicclassArray
10privatestaticfinallongserialVersionUID=7799621696481440826L;
11
12privatestaticlongmaxOfSubArray(Array arr){
13//最大值
14longmax=0;
15intsize=arr.size;
16//s[i]表示前i个元素的乘积,可知s[i]=s[i-1]*arr.get(i-1) 其中(1<=i<=N)
17long[] s=newlong[size+1];
18s[0]=1;
19//t[i]表示i后面元素的乘积,可知t[i]=t[i+1]*arr.get(i) 其中(1<=i<=N)
20long[] t=newlong[size+1];
21t[size]=1;
22//设p[i]为除第i个元素之外的其他元素之积,即:p[i]=s[i-1]*t[i+1];
23long[] p=newlong[size+1];
24
25//求出 s数组
26for(inti=1; i<=size; i++){
27s[i]=s[i-1]*((Integer) arr.get(i-1));
28}
29//求出t数组
30for(inti=size-1; i>=0; i--){
31t[i]=t[i+1]*((Integer) arr.get(i));
32}
33//计算 p数组
34for(inti=1; i<=size; i++){
35p[i]=s[i-1]*t[i];
36if(p[i]>max){
37max=p[i];
38}
39}
40returnmax;
41}
42
43publicstaticvoidmain(String[] args){
44Array
45array.add(1);
46array.add(4);
47array.add(6);
48array.add(10);
49array.add(12);
50array.add(40);
51//上面的数字很简单,口算也知道N-1个最大乘积为115200
52//算法结果:
53System.out.println(“算法结果:”+maxOfSubArray(array));
54}
55
56}
57
本文来自:www.blogjava.net/Jack2007/archive//10/17/234870.html
约瑟夫环问题――初步了解+数组实现
一开始接触约瑟夫环问题,还是在C语言的书中,具体的题目如下:n个人围坐成一圈,选某个人开始(比如第1个),从1开始报数,沿着顺时针方向数到m的人被淘汰,然后后面一个人继续再从1开始报数,数到m时再淘汰一人,重复上面的过程,输出剩下的最后一个人。
解题思路:
Step 1:建立一个长度为n的数组;
Step 2:删除的位置编号为i = (i + m -1) % n;为什么呢?因为第一个人事i = 0,然后 i 增加m-1即可删除另外一个人,把数组想象成一个“环”即可。
Step 3:删除 i 之后,后面的数组元素往前移动;
Step 4:当 i 正好是数组中最后一个数,删除之后,由于后面的新的 i 无法移动(后面没有数了),所以令 i =0;
代码实现如下,这个是用数组实现的:
#include 结果如下: 此外,还可以用链表、队列、堆栈等实现,后面再写, 最“不是问题”的问题 在面试的时候,如果是外企,经常会碰到蓝眼睛、黄头发的老外考官,这种情况下,往往要求英文的听说和理解水平到达一定的`层次。如果自己的英文还不够过关,那么面试时更多的麻烦,就不是来自问题回答本身,因为很多时候你会连题目都听不懂,这可就麻烦大了, 我就有这样的经历,考官一个劲地给我解释问题,我呢,却因为尴尬而不好意思多问,结果忙乎了好久,还是跳过了这个题目,想想真是惭愧,早知如此真应该多花些时间好好学习英文。总之,面试了这么久,虽然失败多于成功,我还是学到了不少,也见识了不少。但愿自己在新的一年里能有所长进,找到适合自己的位置。 新的一年开始了,又要为找工作而四处东奔西跑,心中既充满了希望又有着一丝的担忧, 面试问题十大最篇6:最“不是问题”的问题
篇7:面试问题十大最
出现频率最高的问题
每次去公司面试,无论是什么形式的企业,考官发问的第一句话几乎都是让应聘者做一个简短的自我介绍。在我经历的面试中,这似乎成为了一道主餐前必备的“开胃菜”,出现率高达95%。可不要小看这短短的自我介绍,由于如今的面试大多采用全英文的交流方式,因此,很多考官把这段介绍作为衡量求职者英文和口语水平的重要的指标。标准的发音,沉稳的节奏再加上适当的措辞,很可能一开始接就考官留下一个很好和印象分。所以,我觉得越是看似普通的问题,就越应该认真对待。
最令人尴尬的问题
成绩向来是公司择人的重要标准之一,因此面试时考官通常会问一些有关学习的问题。如果你的学习成绩出类拔萃那自然很好应付,不然,这样的问题往往会令你非常尴尬。诸如“为什么你的大学成绩中等或偏下,为什么会有不及格或重修的课程”等等,如果事先没有准备的托词,就只有憋在那儿哑口无言的份儿了。
最幽默的问题
记得有一次在一家跨国公司面试,落座之后,我正欲“背诵”个人简介,考官却突然奔出一句话:“你先用英文给我一个笑话吧”,顿时,我惊呆了。面试了这么久,还没听说过要讲笑话的,而且还是用英文。情急之下,我只好努力的回想起一条前几天朋友发给我短信笑话,用疙疙瘩瘩地英文复述了一边。上帝保佑,讲完之后,那考官居然哈哈大笑起来,我这才松了一口气。真没想到如今的招聘还要考察我们的“洋幽默”水平,真让人啼笑皆非。
最莫名其妙的问题
一次,我去了一家著名的化妆品公司面试。据说那家公司非常看中员工的形象,而且选拔的要求也比较怪,所以我格外的小心。大部分的过程还算顺利,尽管考官的脸色一直冷冰冰的,可是到了最后,她忽然仔细的打量我起来,然后莫名其妙的问了一句:“你有没有染过头发?”这一问,还真把我问呆了,搞不懂她到底是什么意思。回答“是”还是“否”呢?我犹豫了好一会儿才作了肯定的回答,接着考官却什么也没说就结束了面试。结果,我顺利的进入了下一轮,但是对那个问题我始终想弄明白个究竟。
最“不是问题”的问题
在面试的时候,如果是外企,经常会碰到蓝眼睛、黄头发的老外考官。这种情况下,往往要求英文的听说和理解水平到达一定的层次。如果自己的英文还不够过关,那么面试时更多的麻烦,就不是来自问题回答本身,因为很多时候你会连题目都听不懂,这可就麻烦大了。我就有这样的经历,考官一个劲地给我解释问题,我呢,却因为尴尬而不好意思多问,结果忙乎了好久,还是跳过了这个题目,想想真是惭愧,早知如此真应该多花些时间好好学习英文。总之,面试了这么久,虽然失败多于成功,我还是学到了不少,也见识了不少。但愿自己在新的一年里能有所长进,找到适合自己的位置。