第s名的小红

  前几天的大一新生赛自己也跟着做了做,顺便测测后台数据有没有bug,这是一道排序题,题目如下:

Problem Description

小红总是排第二,有点不服气,现在她想知道一个序列中第二小的数字是多少,你能告诉她么。

Input

输入包含多组测试样例,每组测试样例分为两行,第一行一个n(0 < n <= 10000),代表序列有n个数字,第二行输入n个正整数ai(0 <= ai <= 10^6)。

Output

每组输出到一行上,如果找到了第二小的数 x,输出它,如果没找到,输出"No find",没有引号。

Sample Input

5
1 2 3 4 5

Sample Output

2
 题目如上,看到题的第一反应,毫无疑问的桶排。事实上准备出来的标程也是如此,思路如下: 由于n的范围为0~1e6,所以开一个长度为一百万的一维数组(初始化为0),数组下标与出现过的数字相对应,数字每出现过一次,对应的数组元素值重置为1,循环输入完成后,另开一圈循环,从0开始,直到找到第二个数组元素对应值为1的元素,输出其下标,即为所求。

   代码如下:

#include<stdio.h>
int main()
{
  int n;
  while (~scanf("%d",&n))
  {
    int a[1000000]={0};
    for(int i=0;i<n;i++)
    {
      int k;
      scanf("%d",&k);
      a[k]=1;
    }
    int flag=0;
    for(int i=0;i<1000000;i++)
    {
      if(a[i]!=0)
      flag++;
      if(flag==2)
      {
      printf("%d\n",i);
      break;
      }
    }
    if(flag!=2)
    printf("No find\n");
  }
}

  结果自然是ac了,然而缺点是内存开的太大了。so。。。小开了一波脑洞,思路如下:

  既然是只输出第二位元素,那么只进行简单的排序,输出第二位不就好了,那么利用冒泡排序的思想,只让两个元素沉底之后输出第二个不就好了,然而这个算法有一个非常明显的bug,就是对于相同元素的情况处理,假设有两个或者两个以上的最小元素沉底的话,如:5 1 1 2 3 4 ,那么最小的数有两个即两个1,那么循环会执行两次外层循环,结果为 2 3 4 1 1,那么结果很明显是错误的。那么只要在判断与上一个已经沉底的元素相同的话,改变i值,执行i--,使得外层循环强行增加一次。后来这种想法被舍弃了,原因有两个,第一,数组下标实在是太难计算了,而且下标计算出错改错也很困难。第二,如果是特殊数据的话,例如 5 1 1 1 1 2,那么时间复杂度就会变成O(n2),所以并不可取(实际上是因为数组下标算烦了)。。。

    不过在算数组下标的时间里,又诞生了一种想法,既然是找到第二小的元素,那么只要找到最小的元素,除去最小的元素以外的元素里剩下的部分,其中最小的元素不就是第二小的了么,而且这样实现的话,对于元素除重的问题也很好解决。不过还是要从同到尾遍历两次数组,那么是否可以将其塞到一层循环里呢(输入完数据后不再经历循环),答案当然是可以的(如果我没实现出来就不在文里提了。。。)思路如下:

  在输入一个数组元素后用两个变量记录下当前扫过的最小值和仅次于最小值的值,遍历数组后直接输出就好。代码如下:

#include<stdio.h>
int main()
{
  int a[10005];
  int n;
  while (~scanf("%d",&n))
  {
    int flag=0;
    int flag2=0;
    int min1=10001;
    int min2=10001;
    for(int i=0; i<n; i++)
    {
      scanf("%d",&a[i]);
      if(a[i]<min1)
      {
        min2=min1;
        min1=a[i];
      }
      else if(a[i]!=min1&&a[i]<min2)
        min2=a[i];
    }
    if(min2==10001)
      printf("No find\n");
    else
      printf("%d\n",min2);
  }
}

  这样的话内存就小了很多,相比桶排的实现,内存上还是存在一定程度上的优化的,而且如果是桶排,局限性也得到了解决(题目限制数据输入不超过1e6如果是1e15这样的数据范围,一维数组的内存申请就会出错)

  但是这是求第二小的元素,如果是第n小呢,即便我可以写到第n个min,也不可能写出那么多的else if()啊。。。所以我开始继续改良我的“冒泡版”算法。

  鉴于之前的遇到重复元素的处理既费时又费力。。。所以新的处理办法思路如下:

  对于存在重复元素的数据,如果重复的元素本身并不是第二小,或者第一小,不用考虑,如果是,那么设置条件,当前的元素必须不等于已经沉底的元素,而且小于下一个元素的时候才执行元素互换。代码如下:

#include<stdio.h>
int main()
{
  int n;
  while (~scanf("%d",&n))
  {
    int a[10000];
    int flag=-1;
    int j;
    int flag2=0;
    for(int i=0; i<n; i++)
    {
      scanf("%d",&a[i]);
      if(flag2||a[i]!=a[0])
      flag2=1;
    }
    for(int i=0; i<2; i++)
    {
      for(j=0; j<n-1-i; j++)
        if((a[j]<a[j+1]||a[j+1]<=flag)&&a[j]>flag)
        {
          int t=a[j];
          a[j]=a[j+1];
          a[j+1]=t;
        }
    flag=a[j];
    }
    if(flag2)
      printf("%d\n",a[n-2]);
    else
      printf("No find\n");
  }
}

  ac...算是把一开始脑洞搬到电脑上了。。。然而。。。刚填完一个脑洞,又开了一个:能不能实现它的推广呢,即题目那样,可以任意改变第几小。继续想需要改动的地方,想了一圈。唯一的难点是No find,因为不能在输入的时候直接判定有几个不同元素了,这个问题困扰了好一阵,大致思路还是想塞到输入的那层for里,但是直到现在也没用这种方法实现。所以转了一种思路,把这个判定放到别的地方去,思路如下:

  每次外层循环结束,即有元素沉底后,判断这个刚刚沉底的元素和倒数第二个沉底的元素的关系,正常情况下,应该是刚刚沉底的元素大于倒数第二个沉底的元素,而非正常情况下,也就是No find时,这个刚刚沉底的元素一定会小于等于倒数第二个沉底的元素。代码如下:

#include<stdio.h>
#define s 2
int main()
{
    int n;
    while (~scanf("%d",&n))
    {
        int a[10000];
        int flag=-1;
        int flag2=0;
        int flag3=0;

     int  j;
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        for(int i=0; i<s; i++)
        {
            for(j=0; j<n-1-i; j++)
            {
                if((a[j]<a[j+1]||a[j+1]<=flag)&&a[j]>flag)
                {
                    int t=a[j];
                    a[j]=a[j+1];
                    a[j+1]=t;
                }
            }
            if(a[j]<=flag)
            {
                flag3=1;
                break;
            }
            flag=a[j];
        }
        if(!flag3)
            printf("%d\n",a[n-s]);
        else
            printf("No find\n");
    }
}

  比赛的后台并没有这样的测试样例,so。。。没有结果返回了,不过自己把想到的数据都测了,结果无误。  至此,脑洞已全部填完。。。         

      
时间: 2024-10-13 16:32:38

第s名的小红的相关文章

eclipse工程名出现小红叉的解决办法

前提是eclipse工程中每个子文件都没错,工程名上却显示了小红叉. 打开[Window]->[Show View]->[General]->[Problems],看看Problems窗口提示的错误. 我的错误显示是:Target runtime Apache Tomcat v6.0 is not defined. 这就对了,因为我使用的Tomcat版本是7.0,明显是某些地方出了差错. 打开相应工程文件夹下.settings文件夹,编辑其中的org.eclipse.wst.common

Java面向对象之构造器

目录 Java面向对象之构造器 利用构造器确保初始化 构造器重载 Java面向对象之构造器 利用构造器确保初始化 初始化问题是关系编程方式是否安全的一个重要的问题. 功能:在创建对象时执行初始化. 在Java中,每个类至少有一个构造器.格式如下: [修饰符] 构造器名(参数列表){ ...执行体 } 这时,突然迷惑,之前写过的代码里都没有构造器的说法呀,是怎么回事呢? 先看下面的语句: Student s0 = new Student(); 这是我们之前经常写的,我们管他叫做创建对象,并让引用变

项目小结二:APP 小红点中数字的处理

小红点,是 APP 中最常见的一个功能,我们先来看一下面的案例,下图中,待评价的商品有 2 个,点击“评价晒单”按钮进行评价后,那么待评价数量应该变成 1,那么这个功能是如何去实现的呢? 一般来说,实现的方法有三种: 一.刷新整个页面的数据 就是说,每显示一次,都重新从服务端把数据拉下来,这种方法虽然简单,但是,加大了服务端的负荷,并且由于要整页刷新,用户体验不好. 二.利用事件实现 比如说:增加一个名为 评价晒单 的事件,个人中心页面监听这个事件,而在用户进行评价晒单操作时,服务端返回待评价数

自定义ActionProvider ToolBar 自定义Menu小红点

自定义ActionProvider ToolBar 自定义Menu小红点 版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 今天的几个目标: 1. 自定义ActionProvider 2. Toolbar ActionBar自定义Menu 3. Toolbar ActionBar 右侧Menu添加角标(Toolbar ActionBar Menu添加小红点) 源代码在文章末尾. 效果预览 自定义Menu后不影响原生MD的任何效果

2月第3周业务风控关注|上海网信办复测23个被约谈APP 涉及1号店、小红书等

易盾业务风控周报每周呈报值得关注的安全技术和事件,包括但不限于内容安全.移动安全.业务安全和网络安全,帮助企业提高警惕,规避这些似小实大.影响业务健康发展的安全风险. 1.上海网信办复测23个被约谈APP 涉及1号店.小红书等 近日,上海市网信办对此前被约谈的23个APP开展"回头看"复测工作,要求各企业按照整改报告切实做好整改工作.2018年10月,上海市网信办对本地最常用的23个App获取用户个人信息等权限申请情况开展安全抽查,并就抽查中发现的申请权限不合理.过度索取用户个人信息等

值不能为null.参数名: viewInfo,如何解决

有蓝队网络服务器租用客户反映在一台服务器上使用数据库管理工具时弹出了如下错误 :值不能为null.参数名: viewInfo (Microsoft.SqlServer.Management.SqlStudio.Explorer 错误信息如上图: 解决方法:点击确定 登陆上去.查看---已注册的服务弹出报错信息,点详细. 会找到一个类似无法读取C:\Users\www.landui.com\AppData\Local\Temp\3\xx.tmp 的报错信息. 打开对应目录C:\Users\www.

Ubuntu系统下如何在不重启的情况下永久修改hostname主机名

刚在Vmware下安装了一个Ubuntu的操作系统,打开终端后发现主机名这个长啊,整个窗口都被占满了. 使用hostname修改主机名,运行命令:"hostname 新主机名" #hostname test-vm 这个修改只是临时的,修改完成需要重新打开终端窗口才会变. 而且修改过之后,再执行命令的时候就需要等待很长时间,并提示无法解析主机 这时需要修改hosts文件,来修改主机名到本机IP的映射. 要永久的修改hostname需要修改文件/etc/hostname sudo vi /

C# 发送邮件 附件名称为空

 示例代码: // 1.创建邮件 MailMessage mailMsg = new MailMessage(); mailMsg.To.Add(new MailAddress("[email protected]")); // 2.设置邮件标题.正文等信息 mailMsg.HeadersEncoding = Encoding.GetEncoding("gb2312"); mailMsg.SubjectEncoding = Encoding.GetEncoding(

centos linux中怎么查看和修改计算机名/etc/sysconfig/network

centos linux中怎么查看和修改计算机名 查看计算机名:在终端输入hostname 修改的话 hostname +计算机名(重启后失效)要永久修改的话要修改配置文件/etc/sysconfig/network修改hostname=你要改的名字