@~第三届蓝桥杯第九题:密码发生器
1、要认真读题哦!~~
在对银行账户等重要权限设置密码的时候,我们常常遇到这样的烦恼:如果为了好记用生日吧,容易被破解,不
安全;如果设置不好记的密码,又担心自己也会忘记;如果写在纸上,担心纸张被别人发现或弄丢了
这个程序的任务就是把一串拼音字母转换为6位数字(密码)。我们可以使用任何好记的拼音串(比如名字,王喜明, 就写:wangximing)作为输入,程序输出6位数字。
变换的过程如下:
第一步. 把字符串6个一组折叠起来,比如wangximing则变为:
wangxi
ming
第二步. 把所有垂直在同一个位置的字符的ascii码值相加,得出6个数字,如上面的例子,则得出:
228 202 220 206 120 105
第三步. 再把每个数字“缩位”处理:就是把每个数的个位的数字相加,得出的数字如果不是一位数字,就再缩位,直到
变成一位数字为止。例如:
228 => 2+2+8=12 => 1+2=3
上面的数字缩位后变为:344836, 这就是程序最终的输出结果!
要求程序从标准输入接收数据,在标准输出上输出结果。
输入格式为:第一行是一个整数n(<100),表示下边有多少输入行,接下来是n行字符串,就是等待变换的字符串。
输出格式为:n行变换后的6位密码。
例如,输入:
5
zhangfeng
wangximing
jiujingfazi
woaibeijingtiananmen
haohaoxuexi
则输出:
772243
344836
297332
716652
875843
2、题目分析
1.题纲分析: 对应这种功能题型,我们只需要按照它的要求一步步实现即可,相对较简单。首先,根据题目要求,我们需要对输入的字符串先进行6位一个的字符串截取,再对各个字符串的字符垂直相加得到ascii码,最后对ascii进行一个缩位,即可得到密码。
2.要求一分析: 第一步要求我们对字符串进行6位字符一组的折叠,那么,这里我们可以考虑将其进行一个字符截取,每6位字符截取一次,然后将其用数组封装并返回。(这个功能较为简单,实现的细节就不详细说明了,笔笔也只能分享自己的思路,毕竟算法主要还是得靠自己思考,参考只是一时的,自己思考出来的才更加印象深刻)
3.要求二分析: 第二步需要我们将返回的字符串数组中的每一个字符串水平垂直的字符进行ascii相加 ,然后用数组封装这些值并返回。这里笔笔稍微详细一点,因为这一块虽然并不难,但却很容易出问题,笔笔在这一块也是因为下标的问题调试了近半个小时,唉!心乱了,手慢了,代码也敲不动了😞。嗯,废话就不多说了,直接开始分析:在做这一个功能的时候,笔笔第一个想到的就是直接遍历字符串数组,然后累加每个字符串的第i个字符的ascii码,但是,当数组中某个字符串的长度不一致时,累加第i个字符的就会出现下标越界的情况,为了解决这一问题,笔笔获取了两个变量,分别为字符串数组里的最长的字符串长度和最短的字符串的长度,同时,设置一个索引指针,用来指向当前字符的位置,这样一来,就可以通过指针的指向来判断要不要累加某个字符串的字符,比如当index=4,而其中一个字符串的长度也为4,那么它的最后一个字符的索引为3,故其后面已经没有字符了,所以累加的时候应该跳过它; 用语言可能比较抽象,具体的细节笔笔会在代码中注释。如有不理解的新手朋友,留言或者私信笔笔,笔笔看到一定会在第一时间回复。
4.要求三分析: 第三步,需要对上一步处理得到的ascii码进行一个缩位处理,使所有的ascii码值都缩到1位数,然后将其返回。这里其实也就是一个循环处理的过程,缩位,我们可以利用取余分别拿到个位、十位和百位,对其进行相加判断值是否大于10,如果大于就一直循环取余,直到个、十、百位相加小于10为止。
3、各个功能的代码实现
1.第一步功能实现:分组折叠
/**
* 分组折叠
* @param name 需要折叠的name
* @return 返回name的6位字符一组的字符串数组
*/
public static String[] foldsGroup(String name) {
// 三元:如果按6分组有剩余,则长度+1
int len = name.length() % 6 == 0 ? name.length() / 6 : name.length() / 6 + 1;
String group[] = new String[len];
//指向字符串开始截取的索引
int des = 0;
for (int i = 0; i < group.length; i++) {
if (i == group.length - 1) {
group[i] = name.substring(des);
break;
}
group[i] = name.substring(des, des + 6);
//下一次截取需要从上一次截取的末尾处开始
des += group[i].length();
}
return group;
}
2.第二步功能实现:获取水平垂直字符的ascii码和
/**
* @function 获取字符串垂直对应的ascii码
* @param group 分好组的字符串数组
* @return 各组对应的ascii码
*/
public static int[] getAscii(String group[]) {
//最短的字符串长度
int minLen = group[0].length();
//最长的字符串长度
int maxLen = group[0].length();
// 获取最小字符的长度以及最大字符的长度
for (int i = 1; i < group.length; i++) {
minLen = minLen < group[i].length() ? minLen : group[i].length();
maxLen = maxLen > group[i].length() ? maxLen : group[i].length();
}
// ascii码数组
int[] ascii = new int[maxLen];
// 字符指针:指向当前元素的第几个字符
int index = 0;
// 遍历ascii,赋值
for (int i = 0; i < ascii.length; i++) {
// 遍历字符串数组
for (int s = 0; s < group.length; s++) {
// 当index的指向小于最小字符串的长度时,正常赋值
if (index < minLen) {
ascii[i] += group[s].charAt(index);
// 当index的指向大于等于最小字符串的长度时,只有字符串长度大于最小
// 字符串的长度的字符串才赋值
} else if (index >= minLen && group[s].length() > minLen) {
ascii[i] += group[s].charAt(index);
}
}
// 指针后移
index++;
}
return ascii;
}
3.第三步功能实现:对ascii码进行缩位处理
/**
* @function 对翻译的ascii进行缩位处理,并返回处理之后的密码
* @param ascii 翻译后的ascii
* @return int[] 缩位后的ascii
*/
public static int[] condense(int ascii[]) {
for (int i = 0; i < ascii.length; i++) {
//如果当前的值没有小于10,就一直循环缩位,注意,这里不能为10,否则或有等于10的情况
while (ascii[i] > 9) {
ascii[i] = ascii[i] % 10 + ascii[i] % 100 / 10 + ascii[i] / 100;
}
}
return ascii;
}
4.测试
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
int sum = sc.nextInt();
String name;
int arr[][] = new int[sum][];
int index = 0;
while(sum-->0) {
name = sc.next();
String[] str = foldsGroup(name);
int ascii[] = getAscii(str);
ascii = condense(ascii);
arr[index] = ascii;
index++;
}
for(int i=0;i<arr.length;i++) {
for(int j=0;j<arr[i].length;j++) {
System.out.print(arr[i][j]);
}
System.out.println();
}
}
----------------------------------------------------------------------------- 输出结果------------------------------------------------------------------------------