大致题意:
题意不难懂,对于任意的数字串n,都可以压缩存储为
c1 d1 c2 d2 .... ck dk 形式的数字串
而存在一些特别的数字串,其压缩前后的样子是一模一样的
定义这种数字串为self-inventorying
当我们把n看成原串,
A为n压缩1次后的数字串,
B为n压缩2次后的数字串(即A压缩1次后的数字串)
....以此类推
K为n压缩k次后的数字串(即K-1压缩k-1次后的数字串)
则可以延伸出数字串n的3种属性:
1、 n压缩1次就马上出现self-inventorying特性,即 n n n n n n n .....
2、 n压缩j次后的数字串J出现self-inventorying特性,即 n A B C....H I J J J J J J J
3、 n压缩j次后的数字串J,每再压缩K次,重新出现数字串J,即n A B... J ..K J ..K J..K J
其中K称为循环间隔,K>=2
现给定一字符串,输出其属性。 属性1优于属性2,属性2优于属性3
一、问题分析
本文问题分析部分参考http://www.blogjava.net/DreamAngel/articles/294138.html
举一个例子来说明:
一个数5553141:他包含了2个1,1个3,1个4,3个5;那么和起来写:21131435就是5553141的Inventory 数;
然后题目要求,给出一个数n( 最多80位),他可以被归到如下四类:
1)n is self-inventorying(n用给出那个数代,下同)
即对给出的数,求出他的Inventory 数,如果是本身,则输出该行;
例如:31123314的Inventory数仍然是31123314,输出: 31123314 is self-inventorying
2) n is self-inventorying after j steps
对一个数求他的Inventory 数,然后再对他的Inventory数继续求,如实我们可以得到一个序列:n[0]->n[1]->n[2]…n[j]…. 如此往复,当1<=j<=15时。如果n[j]的Inventory数等于他本身,则输出该行;
例如: 21221314 -> 31321314 -> (31321314),输出: 21221314 is self-inventorying after 2 steps
3) n enters an inventory loop of length k
仍然用n的序列说明: n[0]->n[1]->n[2]…n[j]…n[i]…. (0<=j<i<=15),当n[i]的Inventory数(记作n[k]) 等于n[0]…n[i-1]的中n[j]时,那么很显然,再求下会形成一个循环;因此我们要找出是否存在最小(k>=1)使得n序列够成循环,输出这个k;
例如: 314213241519 --> 412223241519 -->314213241519,对应上述的n[j] --> n[i] -> (n[k])
4) n can not be classified after 15 iterations
如果在找出15个数后,没有满足上述的任何一条,那么就输出该行;
二、常用知识点
1、特定跳出的常用形式:
while(true){
if( .equals( )){
break;
}
}
2、统计数字串中数各个数字出现的次数
i 0 1 2 ······ 9
count[i]
for(i=0;i< n;i++)
count[s.charAt(i)-'0']++;
3、
import java.util.*;
import java.io.*;
/**
* 以下对程序可能出现的几种结果进行分析:
*
* 1)n is self-inventorying 第一次处理后与输入一致
* 2)n is self-inventorying after j steps 再经>1次处理后与输入一致
* 3)n enters an inventory loop of length k 再经>1次处理后,出现循环
* 4)n can not be classified after 15 iterations 总共处理15次后仍不满足以上要求
*
* 1、1)和2)的相同点在于二者都是连续重复型,差别在于1)是在第一次便开始重复
* 2、1)、2)、3)都是重复型,但与1)、2)不同的是4)不是连续重复型
*/
public class Main{
public static void main(String rgs[]) throws Exception
{
Scanner cin = new Scanner(new BufferedInputStream(System.in));
/**
* 特定跳出的常用形式:
* while(true){
*
* if( .equals( )){
* break;
* }
*
* }
*/
while(true){
String s = cin.next();
if(s.equals("-1"))
break;
String[] t = new String[16];//保存s与15个变换结果
int i;
t[0]=s;
for(i=0;i< 15;i++){
t[i+1] = change(t[i]);//对当前字符串进行压缩
int res = Judge (t,i+1); //判断判断字符串的重复情况
if(res==1 && i==0){
System.out.println(s+" is self-inventorying ");
break;
}
if(res==1){
System.out.println(s+" is self-inventorying after "+i+" steps ");
break;
}
if(res>0){
System.out.println(s+" enters an inventory loop of length "+res+" ");
break;
}
}
if(i==15)
System.out.println(s+" can not be classified after 15 iterations ");
}
}
/**
* change(String s) 主要完成对字符串s的压缩,其主要算法如下:
*
* 1)首先设置默认值. Arrays.fill(count,0);
* 2)设置统计值. count[s.charAt(i)-'0']++;
* 3)输出压缩后的字符串. t+=String.valueOf(count[i])+String.valueOf(i);
*
* @param s 要进行压缩的字符串
* @return
*/
//输出s的Inventory 数,输入5553141则输出21131435
public static String change(String s){
int i,n=s.length();//获得字符串的长度
int[] count=new int[10];//用来存储各个数字出现的次数
String t="";//用来记录压缩后的数字串
//fill(int[] a, int val) .将指定的 int 值分配给指定 int 型数组的每个元素。
Arrays.fill(count,0);//将所有的次数默认设置为0
//统计数字串中数各个数字出现的次数
/**
* i 0 1 2 ······ 9
* count[i]
*/
for(i=0;i< n;i++)
count[s.charAt(i)-'0']++;
//输出压缩后的数字
for(i=0;i< 10;i++){
if(count[i]>0)
//返回inventory数字串的形式
t+=String.valueOf(count[i])+String.valueOf(i);
}
return t;
}
/**
* Judge(String[] t,int ind) 主要完成将 第ind次变换结果与前面所有结果比较
* ,主要算法如下:
* 1)首先判断是否重复. if(t[ind].equals(t[i]))
* 2)在1)的基础上判断是否是连续重复. if(ind==i+1)
*
* @param t 存储有压缩字符串的字符串数组
* @param ind 要进行判断的字符串的下标
* @return
*/
public static int Judge(String[] t,int ind){
for(int i=0;i< ind;i++){
if(t[ind].equals(t[i])){//判断是否是重复型
//包括从第一次就self inventory或第n次以后self inventory的情况,不包括循环间隔的情况
if(ind==i+1)//判断是否是连续型
return 1;
else //不是连续重复型
return ind-i;//返回的ind-i就是循环的间隔
}
}
return 0;
}
}