寻找字符串的最长不重复子串,计算复杂度O(n),两种实现

问题描述:给定一个字符串,找出这个字符串中最长的不重复子串。比如对于字符串“sadus”,那么返回的结果应该是“sadu”或者“adus”(返回一个即可);对于字符串“acbba”,返回的应是“acb”。

       对于这样一个问题,想必大家首先想到利用的数据结构是HashMap,利用HashMap来保证子串的不重复。但是我们可以想想能不能不用HashMap呢?答案显然是可以的,因为字符数是固定的,不超过256个!所以我们可以用一个长度为256的数组来记录所有字符的出现情况。

       具体的思路是这样的:遍历整个字符串,针对每个字符做三件事

(1)   如果当前字符出现过并且该字符上一次出现时的index大于目前子串的初始index,那么将目前子串的初始index置为该字符上一次出现时的index。注意这个子串不一定是最大长度的子串,而是程序运行过程中当前的不重复子串。

(2)   如果当前的index与startIndex(目前子串的初始index)的差值大于maxLen(记录的最长不重复子串的长度),那么更新maxLen。注意,因为我们要输出这个不重复子串,所以我们在这时候(maxLen改变时)需要记录startIndex。

(3)   记录当前字符的index。

这样扫描完以后,我们就可以根据oriStartIndex(maxLen改变时记录的startIndex)和maxLen来得到最长不重复子串。

具体实现如下,其中findLongestSubString1()函数是利用HashMap来实现的,而findLongestSubString2()函数是利用数组来实现的,两者的算法思想是一模一样的,但是性能相差近10倍。

import java.util.HashMap;

public class MaxSubString {

	public static void main(String[] args) {
		
		String str = "jhhjnsfudufbdfyscfbsdjjSAFASFsefyrsjksaudhsduhasdbg" +
				"ywqep[m,mzaASFASFhuwenzsdjsjfasfyaehwzsjx ;ASFASFlpwisjd" +
				"asuwnad.pqwekASFqowe92347174nsd sdfsdf73bwASFawue821b9sa" +
				"dasjdnasdqASFASASFF2en128adasjdnqwudSAASFF	ASFw 1wq89ewa" +
				"dasjdASFhqw8edeqwhedhqwueASFuquweuqwuehqw e123xrkASFajs8" +
				"9da2qe54we24eDASASAFFdfsdifhsd";
		long a = System.nanoTime();
		for(int count = 0; count < 100000; count++){
			findLongestSubString1(str);
		}
		long b = System.nanoTime() - a;
		System.out.println(b);
		
		a = System.nanoTime();
		for(int count = 0; count < 100000; count++){
			findLongestSubString2(str);
		}
		b = System.nanoTime() - a;
		System.out.println(b);
		
		System.out.println(findLongestSubString1(str));
		System.out.println(findLongestSubString2(str));
	}
	
	private static String findLongestSubString1(String str) {
		if(str == null)	return null;
		StringBuilder maxSubString = new StringBuilder("");
		char [] strCharArr = str.toCharArray();
		HashMap<Character, Integer> charsIndex = new HashMap<Character, Integer>();
		int startIndex = -1, oriStartIndex = startIndex, maxLen = 0;
		for(int index = 0; index < strCharArr.length; index++) {
			if(charsIndex.containsKey(strCharArr[index])) {
				int oriIndex = charsIndex.get(strCharArr[index]);
				if(oriIndex > startIndex){
					startIndex = oriIndex;
				}
			}
			if(index - startIndex > maxLen) {
				maxLen = index - startIndex;
				oriStartIndex = startIndex;
			}
			charsIndex.put(strCharArr[index], index);
		}
		for(int index =  oriStartIndex + 1; index < oriStartIndex + maxLen + 1; index++) {
			maxSubString.append(strCharArr[index]);
		}
		return maxSubString.toString();
	}
	
	private static String findLongestSubString2(String str) {
		if(str == null)	return null;
		StringBuilder maxSubString = new StringBuilder("");
		char [] strCharArr = str.toCharArray();
		int [] charsIndex = new int[256];
		for(int index = 0; index < 256; index++)	charsIndex[index] = -1;
		int startIndex = -1, oriStartIndex = startIndex, maxLen = 0;
		for(int index = 0; index < strCharArr.length; index++) {
			if(charsIndex[strCharArr[index]] > startIndex)
				startIndex = charsIndex[strCharArr[index]];
			if(index - startIndex > maxLen) {
				maxLen = index - startIndex;
				oriStartIndex = startIndex;
			}
			charsIndex[strCharArr[index]] = index;
		}
		for(int index =  oriStartIndex + 1; index < oriStartIndex + maxLen + 1; index++) {
			maxSubString.append(strCharArr[index]);
		}
		return maxSubString.toString();
	}
}

程序运行结果:


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值