剑指Offer+第35题+第一个只出现一次的字符+java

题目:在字符串中找出第一个只出现一次的字符。如输入"abaccdeff",则输出'b'.

方法1,数组实现hashmap

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符的位置。若为空串,返回-1。位置索引从0开始。

如果从头开始让每一个字符都与其后面的字符相比较,当第一个出现一次的字符,就结束程序。但是这种算法的时间复杂度是O(n^2);

思路:我们可以遍历统计每个字符在字符串中出现的次数,把它保存在数组中,可以利用哈希算法,让字符的ASCII码与数组的键值保持一定的关系,数组的值用来保存次数,这样就形成key-value对,根据字符的ASCII值就可以找到它它在数组中保存它出现的次数的位置。

题目中是全部由字母组成,大写字母的ASCII码在65-90,小写字母在97-122之间,一共有52个字母。

(1)创建一个数组大小为52的数组,来保存每个字母出现的次数;

(2)ASCII码值与数组索引之间的关系,

A(ASCII码65)保存在数组中0位置,即大写字母的ASCII码(设为m)与其在数组中的位置之间的关系:m-65

a(ASCII码97)保存在数组中26位置,即小写写字母的ASCII码(设为n)与其在数组中的位置之间的关系:n-71

(3)第一次遍历字符串,更新字母出现次数,每扫描到一个字符就在其数组中对应的位置将其次数+1;

(4)第二次遍历字符串,查找字母出现次数,每扫描到一个字符就查找器在数组中对应位置的值是否为1,找到第一个,将数组索引大小返回并退出程序。
 

方法2,直接hashmap

由于题目与字符出现的次数有关,我们是不是可疑统计每个字符在该字符串中出现的次数,要达到这个目的,我们需要一个数据容器来存放每个字符出现的次数。在这个容器中可以根据字符来查找它出现的次数,也就是说这个容器的作用就是把一个字符映射称一个数字。在常用的数据容器中,哈希表正是这个用途。

为了解决这个问题,我们可以定义哈希表的键值(key)是字符,而值(Value)是该字符出现的次数。同时我们还需要从头开始扫描字符串两次。第一次扫描字符串时,每扫描到一个字符就在哈希表中的对应项中把次数加1.接下来第二次扫描时,每扫描到一个字符就能从哈希表中得到该字符出现的次数。这样第一个只出现一次的字符就是符合要求的输出。
 

代码:

import java.util.LinkedHashMap;

public class Offer35 {

	//方法1,数组实现哈希表
	public int firstNotReaptingChar(String str){
		int index = 0;
		if(str == null){
			return -1;
		}

		
		char [] charArray = str.toCharArray();
		int [] count = new int[52];
		
		for(int i = 0;i<charArray.length;i++){
			if(charArray[i] >= 65 && charArray[i]<=90)
				count[charArray[i]-65]++;
			
			if(charArray[i]>=97&& charArray[i]<=122)
				count[charArray[i]-71]++;
		}
		
		for(int i = 0;i<charArray.length;i++){
			if(charArray[i]>=65 && charArray[i]<=90)
				if(count[charArray[i]-65] == 1){
					index = i;
					break;
				}
			if(charArray[i]>=97 && charArray[i]<=122)
				if(count[charArray[i]-71] == 1){
					index = i;
					break;
				}
		}
		return index;
	}
	
/*
 * LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,
 * LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。	
 */
	//方法2
	public Character firstNotReaptingChar_2(String str){
		if(str == null)
			return null;
		char [] strChar = str.toCharArray();
		LinkedHashMap<Character, Integer> map = new LinkedHashMap<Character, Integer>();
		for(char item : strChar){
			if(map.containsKey(item))
				map.put(item, map.get(item)+1);
			else
				map.put(item, 1);
		}
		for(char key:map.keySet()){
			if(map.get(key) == 1)
				return key;
		}
		return null;
	}
	
	
	
	public static void main(String[] args) {
		
		Offer35 of35 = new Offer35();
		
		//功能测试,1,字符串中存在只出现一次的字符
		String str1 = "abaccdeff";
		System.out.println("测试1,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar(str1));
		System.out.println("测试1,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar_2(str1));
		
		//功能测试,2,字符串中不存在只出现一次的字符
		String str2 = "aaab";//abacbdcdeeff
		System.out.println("测试2,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar(str2));
		System.out.println("测试2,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar_2(str2));
		
		//功能测试,3,字符串中所有字符只出现一次
		String str3 = "abcDFRG";//abacbdcdeeff
		System.out.println("测试3,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar(str3));
		System.out.println("测试3,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar_2(str3));
		
		//特殊输入测试,4,字符串为NULL指针
		String str4 = null;//abacbdcdeeff
		System.out.println("测试4,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar(str4));
		System.out.println("测试4,第一个只出现一次的字符的位置为:  "+of35.firstNotReaptingChar_2(str4));

	}

}

运行结果:

测试1,第一个只出现一次的字符的位置为:  1
测试1,第一个只出现一次的字符的位置为:  b
测试2,第一个只出现一次的字符的位置为:  3
测试2,第一个只出现一次的字符的位置为:  b
测试3,第一个只出现一次的字符的位置为:  0
测试3,第一个只出现一次的字符的位置为:  a
测试4,第一个只出现一次的字符的位置为:  -1
测试4,第一个只出现一次的字符的位置为:  null

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值