Maximum Subsequence Sum
#include<iostream>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int list[n];
for(int i=0;i<n;i++)
cin>>list[i];
int flag=0,first=0,end=0;
int max=-1,sum=0;//max=-1判别全负和部分负数部分0 两种情况
for(int i=0;i<n;i++)
{
sum+=list[i];
if(sum<0)
{
sum=0;
flag=i+1;
}
else if(sum>max)
{
max=sum;
end=i;
first=flag;
}
}
if(max<0)
cout<<0<<" "<<list[0]<<" "<<list[n-1]<<endl;
else if(max>=0)
cout<<max<<" "<<list[first]<<" "<<list[end]<<endl;
}
}
比起前一篇的算法四,此题还要求输出对应子列和的第一个数和最后一个数,如果有多种相同答案,取第一种。同时若数组全为负,则输出0,第一个元素,最后一个元素。
首先在于max值的设定,此题中应让max=-1,若数组全为负数则进入max<0时的if判断语句;若数组为部分负数部分为0,那么显然正确答案应该为0,0,0,此时max=0,进入对应的if语句。
另外一点的区别在于,当sum=0时,先将下一个下标即i+1赋给flag,再下一次循环中若sum>max,才将flag赋给first完成第一个元素的初始化。而end的查找则比较简单,只要当此循环中sum>max,就更新end为当前的i。
还有一点在于first,end是取对应的下标还是对应的值,刚开始时我取的对应的值,对应的代码如下:
#include<iostream>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int list[n];
for(int i=0;i<n;i++)
cin>>list[i];
int flag=0,first=0,end=0;
int max=-1,sum=0;//max=-1判别全负和部分负数部分0 两种情况
for(int i=0;i<n;i++)
{
sum+=list[i];
if(sum<0)
{
sum=0;
flag=list[i+1];
}
else if(sum>max)
{
max=sum;
end=list[i];
first=flag;
}
}
if(max<0)
cout<<0<<" "<<list[0]<<" "<<list[n-1]<<endl;
else if(max>=0)
cout<<max<<" "<<first<<" "<<end<<endl;
}
}
那么在只有一个正数的情况下,如
5
1 -2 -3 -4 -5
输出的结果为1 0 1,显然是不对的。因为在这种情况下first的值并未更新,输出的只是初始化的值0。
而使用对应的下标输出的则是list[0],则为正确的结果。
PS:细节真的真的很重要啊!!!
复杂度3 二分查找
题目部分提供的代码
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
List ReadInput(); /* 裁判实现,细节不表。元素从下标1开始存储 */
Position BinarySearch( List L, ElementType X );
int main()
{
List L;
ElementType X;
Position P;
L = ReadInput();
scanf("%d", &X);
P = BinarySearch( L, X );
printf("%d\n", P);
return 0;
}
/* 你的代码将被嵌在这里 */
函数代码
Position BinarySearch( List L, ElementType X )
{
int p=0;
int l=L->Last;
int i=(1+l)/2;
for(int j=0;j<(1+l)/2;j++)
{
if(X==L->Data[i])
{
p=i;
return p;
}
else if(X==L->Data[l])
{
p=l;
return p;
}
else if(X>L->Data[i])
{
i=(l+i)/2;
}
else if(X<L->Data[i])
{
i=(i+1)/2;
}
}
return NotFound;
}
首先要注意的是元素从下标1开始存储,这就意味着最开始中间的元素是(1+l)/2,l为线性表中最后一个元素的位置(别问我为什么要用跟1这么像的l…)
显然二分查找的最大次数为(1+l)/2,作为循环的限制条件,接着判断X在线性表中的位置。第一个if语句很简单,判断X与当前的中间值是否相等,第二个if语句(我当时没有想到,看了大佬的代码才发现这一点,佩服佩服。)是判断如果X是否在末尾,即L->Data[l]这个位置上。那么为什么要单独判断末尾呢?
可以举一个简单的例子,比如有5个数,分别为
7 11 15 21 23 ,对应的下标为
1 2 3 4 5
如果我们要查找X=23,那么第一步判断X与L->Date[3]是否相等,发现X>15,下一步判断X与L->Date[(3+5)/2]即L->Date[4]的大小,发现X>21,下一步就是关键所在了,L->Data[(4+5)/2]即L->Data[4],会发现X还是和21比较,因为int的除法(4+5)/2是等于4的,然后循坏结束,返回NotFound,因此末尾需要单独判断。而开头则不会出现这种情况,因为(1+2)/2等于1。
后面的判断就很简单了,如果X>L->Date[i],那么 i=(l+i)/2,即判断右半部分;如果XData[i],那么i=(i+1)/2,即判断左半部分。按此循环直到找到X的下标并返回,或者没有找到返回NotFound。
虽然今天后面还看了对数组,链表的查找,插入,删除的操作,可是今天已经不想再看代码了!!!剩余的部分等明天补上吧。
上午稍微学习了一点Python,还停留在基本的概念阶段,路漫漫其修远兮啊。