一个简单算法题引发的思考<DNA sorting>(about cin/template/new etc)

首先是昨天在北京大学oj网上看到一个简单的算法题目,虽然简单,但是如何完成一段高效、简洁、让人容易看懂的代码对于我这个基础不好,刚刚进入计算机行业的小白来说还是有意义的。而且在写代码的过程中,会发现自己平时学习中不会发现的问题,所以想写下这个博客,主要是便于自己对算法的理解。

来,上题。

DNA Sorting

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 91599   Accepted: 36781

Description

One measure of ``unsortedness‘‘ in a sequence is the number of pairs of entries that are out of order with respect to each other. For instance, in the letter sequence ``DAABEC‘‘, this measure is 5, since D is greater than four letters to its right and E is greater than one letter to its right. This measure is called the number of inversions in the sequence. The sequence ``AACEDGG‘‘ has only one inversion (E and D)---it is nearly sorted---while the sequence ``ZWQM‘‘ has 6 inversions (it is as unsorted as can be---exactly the reverse of sorted).

You are responsible for cataloguing a sequence of DNA strings (sequences containing only the four letters A, C, G, and T). However, you want to catalog them, not in alphabetical order, but rather in order of ``sortedness‘‘, from ``most sorted‘‘ to ``least sorted‘‘. All the strings are of the same length.

Input

The first line contains two integers: a positive integer n (0 < n <= 50) giving the length of the strings; and a positive integer m (0 < m <= 100) giving the number of strings. These are followed by m lines, each containing a string of length n.

Output

Output the list of input strings, arranged from ``most sorted‘‘ to ``least sorted‘‘. Since two strings can be equally sorted, then output them according to the orginal order.

Sample Input

10 6
AACATGAAGG
TTTTGGCCAA
TTTGGCCAAA
GATCAGATTT
CCCGGGGGGA
ATCGATGCAT

Sample Output

CCCGGGGGGA
AACATGAAGG
GATCAGATTT
ATCGATGCAT
TTTTGGCCAA
TTTGGCCAAA

#01、这是一个很简单的题目,基本上就是看完题目,思路就出来的那种。这个题目主要要解决以下几个小麻烦。0X001:存放DNA序列的数据结构,存放这种类型的数据,最好的当然是二维数组啦。m,n是在程序运行过程中用户输入的,显然不能直接char N_DNA[n][m]来定义。虽然题目中给出了m和n都要小于等于50,但是设一个太大的数组,还有很多空间浪费,作为一个较真的程序员,显然是心里过不去的。如是,我们可以采用下面的方法定义数组,并分配空间。
 1 template <typename T>
 2 //定义Arr数据类型
 3 class Arr
 4 {
 5 public:
 6     Arr(int length)
 7     {
 8         this->length = length;
 9         data = new T[length];
10     }
11     T *data;
12     unsigned int length;
13 };
14 typedef Arr<char>* P_of_Arr;//P_of_Arr是一维Arr数组的指针类型
15 void main()
16 {
17     int m, n;
18     scanf("%d %d", &m, &n);
19     //构造N_DNA数组
20      Arr<P_of_Arr> N_DNA(n);
21    //给N_DNA的data数组的每个指针分配空间
22      int t;
23      for (t = 0; t < n; t++)
24      {
25          N_DNA.data[t] = new Arr<char>(m);
26      }
27 }

这里面主要用到两个c++的知识,写出来,加强一下自己的理解。

其一就是temptale的使用,关键字template在这里的作用让class Arr的类型多向化,就是让class Arr可以有多种理解,就是让class Arr成为一个模板,当在其他一些相似但是又不相同的环境下可以被再次使用。通俗点讲,就是先假装,T是已经定义的类型。让编译器认可它,不报错。在Arr定义变量的时候,再来补上T的类型。因此,这样用template模板定义的类型,可以在不同的类型T的环境中使用。

其二是new的使用,首先我们定义一个Arr数组Arr<P_of_Arr> N_DNA(n);我们可以看到Arr构造函数里面,this->length = length;data = new T[length];将n传给Arr域里面的length,并且分配一个T[n]空间的数组,并把指针传给data(注意,这里data是二重指针,也就是数组是data[n],其中data[0,1....n]也是指针,因为定义Arr时,T是P_of_Arr,而typedef Arr<char>* P_of_Arr;//P_of_Arr是一维Arr数组的指针类型)。

 int t;
     for (t = 0; t < n; t++)
     {
         N_DNA.data[t] = new Arr<char>(m);
     }

然后我们循环,依次给data[0,1...n]分配空间.每一个data[i]指向一个一维的Arr类型的数据。

至此,我们就分配了N_DNA.data[n]->data[m]的数组。

#02数据的输入,cin的理解,cin是C++库函数里面的一系列函数,cin>>/cin.get/cin.getline...这些函数的用法在这里不再赘述。

可以参考以下两篇博客,里面讲的比较清楚

个人体会就是在使用和理解这些函数时,了解两个方面问题。

第一、space,tab,Enter是否被从缓冲区中舍弃。<sapce,tab,Enter>

第二、cin.getline在超出范围时,通过怎样影响输入标志位,来影响后续的输入。<failbit,eofbit,badbit//goodbit>

参考博客: 

     http://www.cnblogs.com/A-Song/archive/2012/01/29/2331204.html

     http://blog.csdn.net/dongtingzhizi/article/details/2299365

之后就是非常常规简单的代码了,定义一个数组rel记录DNA的逆值,然后依次按照逆值从小到大输出DNA序列。

完全的代码如下:

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<iostream>
 3 using namespace std;
 4 #define MAX 12768
 5 template <typename T>
 6 class Arr
 7 {
 8 public:
 9     Arr(int length)
10     {
11         this->length = length;
12         data = new T[length];
13     }
14     T *data;
15     unsigned int length;
16 };
17 typedef Arr<char>* P_of_Arr;
18 int main(void)
19 {
20     int m, n;
21     scanf("%d %d", &m, &n);
22     //构造N_DNA数组
23      Arr<P_of_Arr> N_DNA(n);
24      int t;
25      for (t = 0; t < n; t++)
26      {
27          N_DNA.data[t] = new Arr<char>(m);
28      }
29      int i,j,k;
30      int *rel = new int[n];
31      //输入DNA序列
32      cin.getline(N_DNA.data[0]->data, m + 1);
33      for (i = 0; i < n; i++)
34          cin.getline(N_DNA.data[i]->data, m+1);
35      //循环遍历,用rel记录各个DNA序列的逆值
36      for (k = 0; k < n; k++)
37      {
38          rel[k] = 0;
39          for (i = 0; i < m; i++)
40              for (j = i; j < m; j++)
41                  if (N_DNA.data[k]->data[i]>N_DNA.data[k]->data[j])
42                      rel[k]++;
43      }
44      int *usedrel = new int[n];//标志rel是否被用
45      //初始化全为0
46      for (i = 0; i < n; i++)
47          usedrel[i] = 0;
48      //查找最小的逆值得DNA序列,并输出
49      for (i = 0; i < n; i++)
50      {
51          k = -1;//记录最小逆值的地址
52          int min=MAX;//记录最小的逆值
53          for (j = 0; j < n; j++)
54              if (rel[j] < min&&usedrel[j]==0)
55              {
56                  min = rel[j];
57                  k = j;
58              }
59          usedrel[k] = 1;//标记已经被访问
60          for (j = 0; j < m; j++)
61              cout << N_DNA.data[k]->data[j];
62          cout << endl;
63      }
64      return 0;
65 }

运行结果如下:

         

由于题目对于输入输出有要求,所以没有将输入输出分开。

时间: 2024-11-02 13:34:39

一个简单算法题引发的思考<DNA sorting>(about cin/template/new etc)的相关文章

0.28+0.34=? 一个简单小数加法引发的思考

0.28+0.34=? 我相信这个简单的加法,谁都会,肯定等于0.62嘛. 这是两个特别简单的加法,那如果我在其整数位置上加上其他的数字,或者多加几个和项,你是否还能快速算过来? 我想这时候,我们又得借助计算器了!而这,有时可能就是电脑!尤其是如果咱们借助简单程序语言来算的时候,嘿嘿,可能就不是那么回事了~ 不信你看,用javascript算的结果: 用python算的结果: 当然了,我尝试着用其他语言来试一下,结果好像并不都是这样. 其中,java只会在类型转换的时候出现奇怪的值:(当然这在我

一个截取字符串函数引发的思考

背景 前些天,遇到这样一个问题,问题的内容如下: 要求编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串.但是要保证汉字不被截半个,如"我ABC", 4,截取后的效果应该为"我AB",输入"我ABC汉DEF", 6,应该输出为"我ABC",而不是"我ABC+汉的半个". 问题 刚看到这个问题的时候,以为还是很简单的,但写出来之后,发现并不是想要的效果.回想一下当时的思路,就发现刚开

C# 一个简单的秒表引发的窗体卡死问题

一个秒表程序也是我的一个心病,因为一直想写这样的一个东西,但是总往GUI那边想,所以就比较怵,可能是上学的时候学MFC搞出的后遗症吧,不过当我今天想好用Win Form(话说还是第一次写win form)写这么一个东西的时候,居然so easy. 所以说,做不了不可怕,怕的是你不去做,因为你不去做,你就永远不知道你能不能做它.事实证明,大部分你犹豫能不能做的事情,实际上你都能搞定. 虽然成功实现了一个秒表的简单功能,即开始计时和停止.但是却引发了一个关于win form和C#线程的问题. 下面一

一道CTF题引发的思考-MySQL的几个特性

0x01   背景 前天在做一道CTF题目时一道盲注题,其实盲注也有可能可以回显数据的,如使用DNS或者HTTP等日志来快速的获取数据,MYSQL可以利用LOAD_FILE()函数读取数据,并向远程DNS主机发送数据信息,此时DNS日志文件中就会有盲注语句的查询结果.这里不做这部分的讨论,只是说下有这种方法,在这道题目中我是使用常规的盲注的方式获取数据的.其中遇到有以下几个问题: 过滤规则的判断与绕过 MySQL的一些少有人总结的特性 手动盲注的繁琐低效 这题确实让我思考了很多,当然还有一些特性

由一个简单算法想到的程序员素养问题

题记:五月从帝都回到武汉,旅游半个月后开始找新工作,六月选择了一家华中地区为数不多的移动互联网公司入职至今,略有感触——比较帝都码农与武汉码农的平均水平,就跟两个城市的经济发展水平差异一样大,不是说武汉这边没有优秀的程序员(我也算半个嘛),而是说平均水平确实不如其他一线城市.想想也正常,巨头公司都扎堆北上广深,以极具竞争力的薪酬福利和巨头光环吸引着广大程序员,反观武汉的互联网发展尚处在初级阶段,无论从公司规模.名气还是最实际的薪酬福利方面均不如一线城市,自然无法吸引广大程序员咯.本人在新公司待了

大话JS面向对象之扩展篇 面向对象与面向过程之间的博弈论(OO Vs 过程)------(一个简单的实例引发的沉思)

一,总体概要 1,笔者浅谈 我是从学习Java编程开始接触OOP(面向对象编程),刚开始使用Java编写程序的时候感觉很别扭(面向对象式编程因为引入了类.对象.实例等概念,非常贴合人类对于世间万物的认知方式和思考方式.对于复杂的事物,人类是如何去认识.归纳.总结的?面向对象式编程就是在努力回答这个问题,而答案的核心就是两个字:抽象.所以面向对象式编程特别适合处理业务逻辑,因此被广泛应用于目前的软件开发当中.因为我们开发软件就是为了解决问题,面向对象式编程符合人类对于“问题”的认知方式),因为我早

本猿新接触(内附PHP开发环境与PHP简单算法题)——2015.07上半月

PHP&MYSQL 开发环境准备 SAE http://sae.sina.com.cn/ GitHub https://github.com/ Git http://git-scm.com/ 代码部署手册 http://sae.sina.com.cn/doc/tutorial/code-deploy.html bootstrap.css http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.css Bootstrap前端开发框架 http://

一个简单的特效引发的大战之移动开发中我为什么放弃jquery mobile

我本想安静的做一个美男子,可是,老板不涨工资,反而,一月不如一月. 我为什么放弃jquery mobile插件选择自己写特效? 在开发中大家都知道效率很重要,一个好的工具可以在开发中大大提升效率,工作做的越多,相应的取得的报酬也就越多,相反就是我自己了. 最近一直在一件事情上,移动线上网站测试必须符合3星,将不合格的网站调优后保证3星,方便线上推广,难免会遇见一些问题,大致为题后期会写一篇随笔总结,“移动开发中网站如何优化”.其中遇见的一个问题就是JS文件过大,CSS文件过大,之前项目一直使用的

一道JS的简单算法题

今天百度了一下腾讯的前端面试题,找了好久只有找到这道题,顺便mark一下 题目是这样的:有一组数字,从1到n,从中减少了3个数,顺序也被打乱,放在一个n-3的数组里,请找出丢失的数字,最好能有程序,最好算法比较快. 网上的答案有一些出入,整理如下 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transiti