蓝杰第一堂课的总结
-------------基本数据类型和字符串
这节课有一个问题比较奇葩(原谅我的用词不当)。 就是:问一下这段程序的运行次数
for(byte i=0;i<1000;i++)
{
System.out.println(i); }
这主要考察对数据类型的表示范围的了解。
byte的表示范围是-128~127 那么i从0开始到127结束 那么这段程序的运行次数就是128次吗? 大部分人都是这样认为的,但实际上这段程序是一个死循环,当时我和我的小伙伴们都惊呆了! 刚开始真的觉得有点不可思议。 虽然上课时强哥说了byte类型的127+1后会变成-128(用2进制表示 首位为符号位). 但当时仍然无法理解。 后来经过各种baidu,才猛然发现这么一个结果:
在计算机中,是用补码形式表示二进制数。
正数:首位为0,后七位二进制数即为所表示正数的绝对值
负数:首位为1,将所有位取反,再加1,即为负数的绝对值
这样看来1000 0000按照上边的说法应该为负数(首位为1),取反加1结果还是1000 0000,大小为128
所以1000 0000也就表示了-128
一个byte由八个位组成,如00000000,其中,前7位表示数值,第8位是符号位(0为正,1为负)。这样+1就是00000001,-1就是10000001。最大的正数就是0 1111111,即2^0+2^1+……+2^6=127;最小的负数,同理,为1 1111111,即-127。
到这里应该是许多人不明白的地方,为什么负数会到-128。这不得不崇拜伟大的印度阿三们。
上述的描述会出现一个问题,就是0,会出现一个+0(00000000)和一个-0(10000000)。印度人他们规定-0为-128,这样就与计算机的补码(程序都是按补码运行的)完美的结合在一起。
(此处为copy baidu)
字符串的课后练习:统计字符串相同字符个数
其实我刚开始做的不是这个题目 是这个:将一个字符串中重复的字符删除 然后输出。
不过这两个也是大同小异,可以相互转换。
先说一下我自己的想法:
刚开始 我想一个字符串str(长度为L)要删去重复的字符,肯定有一个字符串的扫描操作(运用for循环)
//当然要先把字符串存储到一个字符数组中
char[] ch=new char[L];
for(int i=0;i<L;i++)
{
ch[i]=str.charAt(i);
}
假设扫描到的字符为“判定字符”。
定义一个i 的循环
for(int i=0;i<L;i++) //扫描字符串的操作
假设字符串为 “aaabbbcccddd”
那么先从第一个字符a开始 a为判定字符 然后在从a之后的字符中查找与a相同的字符并且删去。
定义一个j循环 for(int j=0;j<L;j++) //扫描“判定字符”之后的字符
这时涉及了一个判定字符是否相等以及删除字符的操作。
//判断字符是否相等
if(ch[i]==ch[j])
{
//扫描字符与判定字符相等,这时可以进行删除操作了
}
对于删除操作我的想法:以删除字符处为节点,将后面每个字符都向前移动一个,即将后面一个字符的值赋给前面一个字符
//删除字符
for(int k=j;k<L-1;k++)
{
ch[k]=ch[k+1];
}
L--; //删除掉一个字符之后将字符串长度减1
“aaabbbcccddd”经过一次扫描删除操作后变为“aabbbcccdddd”
整个过程为:
aaabbbcccddd-> aabbbcccdddd->abbbcccddddd->abbcccddddd->abcccdddddd->abcddddddd
-> abcddddddd-> abcddddddd
程序的运行后,最终L=4
此时,将字符串输出,只输出处理后L长度的字符串。
(如果要输出字符的个数,可以用一个整形数组来存储所删除掉的字符的个数)
for(int k=j;k<L-1;k++)
{
ch[k]=ch[k+1];
}
t[i]++; //记录所删除字母的个数
L--; //删除掉一个字符之后将字符串长度减1
这时候注意,其实所谓删除操作只是把所有“判定字符”之后的字符都向前“复制粘贴”移动了一个单位,整个字符串的长度其实并不变, 所谓的L-1也只是把要扫描的字符串长度减1,而非将整个字符串的长度都减1.
十分注意 删除掉一个重复字符后(即删除字符后的每个字符都向前移动了一位),
此时要将j减1 即 使“判定起点”仍在“判定字符”后一个。
这是整个程序:
public class Count2{
public static void main(String args[])
{
System.out.println("input ");
java.util.Scanner a=new java.util.Scanner(System.in);
String s= (String)a.next();
int L=s.length();
char[] ch=new char[L];
int [] t=new int[L];
for(int i=0;i<L;i++)
{
ch[i] = s.charAt(i);
}
for(int i=0;i<L;i++) //“扫描”字符串 从头到尾 设扫描到的某个字符为“判定字符”
{
for(int j=i+1;j<L;j++)
//从“判定字符”后一个开始,扫描字符串。把相同的删除
{
//删除字符
//即 将后一位字符赋给前一位 并将字符串长度L减1;
if(ch[j]==ch[i])
{
for(int k=j;k<L-1;k++) //delete operation
{
ch[k]=ch[k+1];
}
L--;
j--; //十分注意 删除掉一个重复字符后(即删除字符后的每个字符都向前移动了一位),
//此时要将j减1 即 使“判定起点”仍在“判定字符”后一个。
t[i]++; //记录所删除字母的个数
}
}
}
for(int h=0;h<L;h++)
{
System.out.print(ch[h]+"的个数为");
System.out.print(t[h]+1+" ");
}
}
}
个人觉得我自己的想法过于复杂,以至于苦苦思索了三四个小时才算把这段代码完成,而且里面有3个for循环,估计程序的运行效率比较低。
经过熊哥上课的启发,发现这个问题用ASCII码来实现将会十分方便。
大体的想法是:
1. 扫描整个字符串。
2. 每扫描到一个字符就获取其ASCII码值
3. 定义一个存储数组array[],将ASCII码值作为数组下标,每扫描一个字符,就将array[ASCII]++, 这样就相当于获得了字符的个数。
例如:a a b b c c d d
array
ASCII码值 | 97 | 98 | 99 |
数组元素值 | 2 | 2 | 2 |
|
|
|
|
4.将array数组输出 先输出(char)i (将元素的下标强制转型为字符型)
再输出array[i](即对应字符的个数)
当然我还copy到了我的小伙伴的想法,也非常简练。
想法大体是:
1. 写一个统计字符的函数cout(String s,char a){} 用来统计字符串s中字符a 的个数。
2. 扫描整个字符串,设扫描到的字符为“统计字符”;
3. 统计字符确定后,判断该字符在之前是否出现过(即是否被统计过了),如果没有出现过,就调用统计字符函数cout().