ACM复习(38)10675 ACMer不得不知道的事儿(二)

Description
作为一个入门的ACMer,在参加比赛之前,你势必要了解算法的一些基本概念,比如复杂度。
ACM的题目,只要不是a+b级别的,总会需要一定的算法来解决,即使是枚举,
也是叫做穷举算法。

一个算法的好坏,由它的复杂度来衡量,复杂度越高,算法越低效。
复杂度包括不限于时间复杂度、空间复杂度和编码复杂度,即其花费的时间、空间(即内存使用等)还有实现的难度。
第三个在做研究的时候不一定会考虑,但ACM赛制是5个小时内决胜负,编码复杂度也是至关重要的一个因素。

一、时间复杂度
通俗讲时间复杂度就是用来衡量算法执行的时间的,它和问题的规模(通常用n表示,如果问题规模和不止一个变量有关,
那用n,m,k等等表示)有关,规模越大,所花费的时间越长。越高效的算法,在n增长的时候,执行时间增加的越少。
例如求1..n的和,下面有三种写法:

普通写法是:
int sum=0,i;
for(i=1;i<=n;i++)
sum+=i;
我们说它的时间复杂度是O(n)。因为运行一次,必须执行一次n长度的循环,n越大时间越大。对于每次循环,它需要执行
一次i++,一次sum+=i,一次判断是否i<=n,可以说复杂度是O(3n),但是通常常数不被计入到复杂度的计算中,所以简化为O(n)。

文艺写法:
int sum=n*(n+1)/2;
复杂度O(1),很明显运行一次只需要执行一次运算操作。

2B写法:
int sum=0,i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
sum++;
}
嗯,很暴力很2B的O(n^2)复杂度,你懂的。

说到这里相信你已经对时间复杂度有了一定的了解了。

二、空间复杂度
所谓空间复杂度就是你用的内存的大小,简单说就是你用了多少变量开了多大的数组,malloc了多少内存,综合起来就是了,
这点比较简单,就不一一赘述。

三、编码复杂度
编码复杂度和你实现算法所需要的时间有关,而且有时候和时间复杂度也有一定关系,但不是越高级的算法越难实现,
像刚才的例子就是时间复杂度高了,编码复杂度也跟着高了。

当你对算法有了一定了解,在ACM上收获了不少知识之后,你甚至能在一些场合很轻松地解决掉一些问题,
并BS一些动手能力不强的人。

就好比某个牛津计算机系从本科读到博士还经常考第一的人,可以花15分钟的时间写出类似这样的代码,
来求一个数组里面,有多少数比它左边的数都要大:
cnt=0;
for(i=0;i < n;i++)
{
for(j=0;j < i;j++)
{
if(a[i] < a[j])
break;
}
if(j==i)
b[i]=1;
else
b[i]=0;
}
for(i=0;i < n;i++)
{
if(b[i]==1)
cnt++;
}
printf(“%d\n”,cnt);

这样写法的复杂度相信大家可以估算的出来,那么,我要你写出一个比这个的时间复杂度、代码复杂度都要低的代码来,
另外,我还要你求出有多少个数比它右边都要小,同时,从小到大输出他们的下标(从0开始)。

输入格式
第一行,是一个数T(T<=500),表示有多少组测试数据。

第二行乃至结束,是T组数据,对于每组数据:
第一行是一个数n(1<=n<=100000),表示这个数组的长度。
第二行是n个整数,有空格分隔。

输出格式
对于每组数据,输出四行:
第一行,一个数A,表示有多少个数比它左边都大
第二行,A个整数,表示比它左边都大的数的下标
第三行,一个数B,表示有多少个数比它右边都小
第四行,B个整数,表示比它右边都小的数的下标
请注意,那下标I,从左到右输出也就是从小到大

输入样例
2
4
1 3 1 4
5
1 2 3 2 1

输出样例
3
0 1 3
2
2 3
3
0 1 2
1
4

提示
数组太大要开成全局变量,即放在函数体外,因为定义在函数体内部是占用函数栈的空间的,而函数栈空间比较小,
放里面很容易造成爆栈然后得到“运行时错误”的结果。
另外,输入流和输出流是分开的,就是说,处理完一组数据,输出答案,再处理第二组数据,再输出第二组数据的答案,再处理第三组…,
这样和处理完所有数据,再一次性输出,是完全等价的。并且,系统评判的题目都是这样,不需要保存所有答案一并输出。
之所以这题是(二)滴原因是去年有道一的了喲,看看有助于解决题目哟亲~~~


解题思路

无论是求比左边大还是求比右边小都需要扫描一次,所以总共需要扫描两次,每次扫描的时候例如求比左边大时设置一个flag代表从左到右扫描遇到的最大的数,后面的数只需要和flag比即可,当遇到比flag大的则更新flag,求比右边小同理,只是flag此时代表是最小的数。扫描两遍时间复杂度为O(n)

#include<stdio.h>
int main()
{
    int t, n, count, flag, nums[100002], record[100002];
    scanf("%d", &t);
    while(t --)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i ++)
            scanf("%d", &nums[i]); 
        // 求比左边大的   
        count = 1;
        record[0] = 0;
        flag = nums[0];
        for(int i = 1; i < n; i ++)
            if(nums[i] > flag)
            {
                flag = nums[i];
                record[count] = i;
                count ++;
            }
        printf("%d\n", count);
        for(int i = 0; i < count; i ++)
            printf("%d ", record[i]);
        printf("\n");
        // 求比右边小的
        count = 1;
        record[0] = n - 1;
        flag = nums[n - 1];
        for(int i = n - 1; i >= 0; i --)
            if(nums[i] < flag)
            {
                flag = nums[i];
                record[count] = i;
                count ++;
            }
        printf("%d\n", count);
        for(int i = count - 1; i >= 0; i --)
            printf("%d ", record[i]);
        printf("\n"); 
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sinat_34200786/article/details/79561305
今日推荐