题目来源: HJ10 字符个数统计
题目描述:
思路:
将字符串的每个字符与127相减后,由于每个字符的ASCII码不同,所以根据相减的结果的不同,使得对应下标的数组值进行+1的操作(数组通过初始化所有初始值都为0),最后将数组值不等于0的进行计数,即字符种类的个数
具体实现:
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
int ints[] = new int[500]; //默认初始值为0
for(int i = 0; i < str.length(); i ++){
char charAt = str.charAt(i);
ints[127-charAt] ++; //与127相减后,对应下标的数组值+1
}
int top = 0;
for(int i = 0; i < 500; i ++){
if(ints[i] != 0){ //将数组值不为0的个数进行统计
top++;
}
}
System.out.println(top);
}
- 时间复杂度:O(n) ——进行了遍历的操作
- 空间复杂度:O(n) ——引入了额外的数组
思路杂记
1.初始化数组int ints[] = new int[500];,一开始粗心写成了char[] chars = new char[500];,而char类型定义的数组,初始值就不是默认为0,而是0对应的字符,使用UTF8字符集的话,给出的结果是
同时,由于
java 中的数组初始值都为零,若填充其他值,可以用Arrays.fill方法,但只能填充一个一维数组,多维数组还得用循环。
int arr[] = new int[10];
Arrays.fill(arr,Integer.MIN_VALUE);
2.若将数组值不为0的个数进行统计的代码,稍加修改,也可以求字符串中出现次数最多的字符,改为
if(ints[i] > top)top = ints[i];,便求出了出现最多的次数,将每次对应的i记录下来,便可反求对应的字符
int top = 0;
char ch1 = 0;
for (int i = 0; i < 500; i++) {
if (ints[i] > top) {
top = ints[i]; //出现的次数
ch1 = (char) (127 - i); //出现次数所对应的字符
}
}
3.当然了,上面的第2点,是在区分大小写的前提下,因为大小写字母的ASCII值不同,如果不区分大小写的话,可以先进行统一小写的操作,在day2 计算某字符出现次数这篇文章中有使用到这个操作
思路拓展之利用HashMap
借鉴于该文章
-
直接利用Java中的
java.util.HashMap来进行存储,HashMap的具体存储原理以及源码分析可以参考文章 JDK 1.8 HashMap 源码解析 -
Java中LinkedHashMap(JDK1.8之后)中每个节点上都是链表,类似于邻接表,当邻接表的链表长度超过8时,会转换成红黑树。
-
同时LinkedHashMap的默认初始容量为16.
import java.util.Scanner;
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
HashMap<Integer,Boolean> hashMap = new HashMap<>();
String str = in.nextLine();
char c;
for(int i = 0; i < str.length(); i++){
c = str.charAt(i);
hashMap.putIfAbsent(c+0,true);
}
System.out.println(hashMap.keySet().size());
}
}
-
时间复杂度:
O(n)—— 根据LinkedHashMap原理,LinkedHashMap的默认初始容量为16,而最坏情况下有127个(回车符不会出现),邻接表的链表长度超过8时会最终转化成黑红树,但是在Hash函数平均分布的情况下不可能产生红黑树,因此最坏的情况下总时间为8n,时间复杂度为O(n)。 -
空间复杂度:
O(1)