现在的位置: 首页 > 综合 > 正文

贪心题目循环和控制台折行

2016年02月23日 ⁄ 综合 ⁄ 共 2980字 ⁄ 字号 评论关闭
文章目录

题目描述

夏娜酱最喜欢菠萝包了,于是威尔艾米娜从天道宫下来买了一大堆菠萝包。夏娜酱先将这些菠萝包按某种顺序排成一列,然后给每个菠萝包起了个名字,名字都是单个 的大写字母A-Z。小白想检验一下夏娜酱的学习成果,要求夏娜酱以下两种方式将这些菠萝包重排为新序列,使这些菠萝包的名字组成的新序列字典序最小。

1.从原序列的前端取出一个菠萝包,放在新序列的尾端

2.从原序列的尾端取出一个菠萝包,放在新序列的尾端

注:字典序的比较如:ABCDE<BCDEA,   ABCDE<ABDCE。

聪明的夏娜酱已经完成这个任务了,现在,轮到你来造出这样的新序列了。

输入:

输入包含多组用例,每组用例占两行,在每组用例中,第一行为一个整数n(1<=n<=2000),第二行为一个只包含大写字母的原序列。

输出:

对每组用例,输出符合要求的新序列,每80个字符换一次行,当然串尾要换行。

分析:

光用脑子想感觉很简单,就是每次找两端的较小值放入新数组里。如果两端相等,就不断往里找,离较小值较近的一端放入新数组。

然而,实际上,具体编程的时候遇到了严重的问题, 就是如何考虑周全两个指针将要碰到一起甚至交错的时候的情况。

代码

#include <stdio.h>
#include <string.h>
#define CONTAIN 2005
void print(char *str);
int main()
{
	freopen("/home/langley/programe/sample.txt","r",stdin);
        int n = 0;//number of letters
	while(scanf("%d",&n) != EOF)
	{
	    char str[CONTAIN] = {0};//string of input
    	getchar();
    	for(int i = 0;i < n;i ++)
    	{
    		str[i] = getchar();
    	}
    	char display[CONTAIN] = {0};//string of output
    	int p = 0;//a whole varible as the index of display
    	int start = 0,end = strlen(str) - 1;//the range of the string
    	while(1)
    	{
    		if(str[start] != str[end])
    		{
    			if(str[start] < str[end])
    			{
    				display[p] = str[start];
    				start ++;
    			}
    			else
    			{
    				display[p] = str[end];
    				end --;
    			}
    		}
    		else
    		{
    			int temp_s = start,temp_e = end;
    			for( ;temp_s <= temp_e && str[temp_s] == str[temp_e] ;temp_s ++,temp_e --);
    			if(temp_s < temp_e)
    			{
    				if(str[temp_s] < str[temp_e])
    				{
    					display[p] = str[start];
    					start ++;
    				}
    				else if(str[temp_s] > str[temp_e])
    				{
    					display[p] = str[end];
    					end --;
    				}
    			}
    			else if(temp_s >= temp_e)//sys
    			{
    				display[p] = str[start];
    				start ++;
    			}
    		}
    		//No need to consider this much
    		/*if(start == end)
    		{
    			display[p+1] = str[start];
    			break;
    		}*/

    		if(start > end)//you could have put this in while();
    			break;
    		p ++;
    	}
		display[n] = 0;
    	print(display);
    }
	return 0;
}

void print(char *str)
{
   char *p = str;
   while(1)
   {
        for(int i = 0;i < 80 && *p != 0;i ++)
        {
            putchar(*p);
            p ++;
        }
        if(*p == 0)
            break;
        putchar(10);
    }
    putchar(10);
}

这里主要困住我的是两个问题:(1)从原数组取数字时的循环结束条件,(2)按80一行打印
(1)对于最外层的循环,是start > end的时候跳出循环还是start >= end 的时候就要跳出来?
  当两个字母相同的时候开始的内层的循环,是temp_s > temp_e的时候跳出来还是temp_s >= temp_e 的时候跳出来?
这些问题在设计算法的时候就应该充分的考虑清楚,否则输入代码的时候会越来越凌乱。
首先看较小的循环,进入这个循环有个前提条件,就是数组左右端字母是相等的。要考虑的就是偶数和奇数的对称数组的区别。比如,BAB和BAAB。对于BAB,temp向中间靠拢会指向同一个值,因为有对称的结构,此时跳出还是再走一步跳出都没有关系。而对于BAAB,temp逐渐向里缩会出现交错,即temp_s
> temp_e,跳出循环。所以temp_s >= temp_e或temp_s > temp_e都可以为跳出循环的条件,跳出来之后呢?其实这样对称的情形不管怎么打印都无所谓了,所以都打印start就好了。
看较大的循环,当start与end碰到一起的时候,如果跳出,这个位置的字母就会miss;如果不跳出,会进入str[start] == stt[end]的情况,不会进入小循环,直接打印str[start],然后start > end,符合我们的预想,这个时候应该跳出。所以循环继续的条件应该是start
<= end。
除此之外,还要考虑一下start和end会跳出数组范围的情况,即str[start]和str[end]某个位置不在输入的值的范围之内,此时网教的不知装了什么奇葩插件的gcc会Runtime Erro ,提示无效内存引用。这个问题我在之前一片日志《集合求交》中着重提醒过这样的问题。不过幸运的是,这道题如果按照上面的条件终止循环,不会出现这样的问题。因为start的值一直小于end,充其量只会比end大1,而当start
== end + 1时,已经达到的循环终止条件,start和end不会作为索引取数组中的值,直接跳出。只要start别跳出数组的范围(这里是2005),即使该索引位置没有值也无关紧要。
(2)主要困住我的是第二个问题,按80个换行打印。考虑两种情形,字母是或不是80的整数倍。
如果仅仅是输入80个字母换行,然后全输入完时换行,就会出现80个字母的序列换两行的现象。
我一开始是这么写的print函数:
void print(char *str) 
{ 
   char *p = str; 
   while(1) 
   { 
      for(int i = 0;i < 80;i ++) 
      { 
          if(*p != 0) 
          { 
              putchar(*p); 
                p ++; 
          } 
          else if(*p == 0 ) 
          { 
                if(i != 0) 
                { 
                    putchar(10); 
                    return ; 
                } 
                else 
                    return ; 
          } 
     } 
} 

这样的打印方法一直过不了网教,在我的电脑上却“似乎”是对的。

起初一直不明白为什么,知道我用全屏在终端上打印出来
真相才浮出水面,原来codeblocks的袖珍控制台一行只能显示80个字符,包括终端在没有最大化的时候也是一行显示80个字符,超过80会自动折行……原来前面那段代码错的如此离谱却因为这个一直没有发现。
当初对80的整数倍个数考虑复杂了,其实只要先检测是否到达结尾再换行就好了。如果已经到达字符串末尾,直接跳出循环,打印程序最终的回车就好了。
修改之后就可以正确显示了。

抱歉!评论已关闭.