求字符串内不包含重复字符的最长子串
2015-07-13 22:34
381 查看
今天我遇到一个问题,题目描述如下:
一个字符串,求这个字符串中不包含重复字符的最长子串的长度,如abba返回2,aaaaabc返回3,bbbbbbb返回1,等等上面是测试用例。那么我解决这个问题的思路有两种:
第一种是,设一个头指针和一个尾指针,头指针指向,不包含重复字符子串的第一个字符,尾指针指向不包含重复子串的最后一个字符,用一个hashset保存已经出现过的字符,例如abba,如果尾指针指向的字符,在集合中没有出现,那么将这个字符放入结合,然后尾指针向后移动,这是尾指针会移动到第二个b的位置,如果集合中已经包含了这个字符,那么用尾指针的索引减去头指针的索引,会求出一个子串的长度,如果该长度大于当前的最大长度,那么就令当前最大长度等于目前的长度,然后清空集合,头指针向后移动一个字符,尾指针再指向头指针,然后重复上面的过程,这样既可求出最大长度。但是这种思路的时间复杂度高,为o(n*n)的时间复杂度,所以这种算法的效率不太高,下面是我的代码:
第二种思路比较巧妙,思路是这样的这次要以一个hashmap作为辅助,map的key存储的是字符,value存储的是该字符当前的位置,首先设置一个头指针,指向字符串开头,那么从开始遍历字符串,如果map当中不包含这个字符,那么用这个字符当前所在的位置减去头指针的位置,然后与最大长度做比较,选打的成为最大长度,然后把当前字符的以及位置放入map,以abba为例,头指针指向a,当前为a,那么长度为1,map。put(‘a’,0),当前为b,那么长度为2,map.put('b',1),如果说map中存在当前字符,那么把头指针指向,头指针当前的位置与map中存储该字符位置的下一个位置当中的较大者,成为新的头指针位置,比如当走到第二个b的时候,那么头指针原来是0,当前map中存放b的位置是1,那么头指针指向2,所以长度为1,比最大长度小不进行替换,最后将当前的字符及位置放入map,现在是map.put('b',2),然后走到了a,那么当前map中a的位置是0,那么它的下一个位置是1,与当前头指针位置2相比,小于当前头指针的位置,那么头指针不跟新,所以长度为2,与最大长度相等,所以不替换,最后求出最大长度为2.
这种思路的时间复杂度为o(n),效率比较高,但是思考起来比较复杂,个人建议这种思路,下面是我的代码:
一个字符串,求这个字符串中不包含重复字符的最长子串的长度,如abba返回2,aaaaabc返回3,bbbbbbb返回1,等等上面是测试用例。那么我解决这个问题的思路有两种:
第一种是,设一个头指针和一个尾指针,头指针指向,不包含重复字符子串的第一个字符,尾指针指向不包含重复子串的最后一个字符,用一个hashset保存已经出现过的字符,例如abba,如果尾指针指向的字符,在集合中没有出现,那么将这个字符放入结合,然后尾指针向后移动,这是尾指针会移动到第二个b的位置,如果集合中已经包含了这个字符,那么用尾指针的索引减去头指针的索引,会求出一个子串的长度,如果该长度大于当前的最大长度,那么就令当前最大长度等于目前的长度,然后清空集合,头指针向后移动一个字符,尾指针再指向头指针,然后重复上面的过程,这样既可求出最大长度。但是这种思路的时间复杂度高,为o(n*n)的时间复杂度,所以这种算法的效率不太高,下面是我的代码:
package com.test; import java.util.HashSet; import java.util.Set; public class Main { public static int maxLength(String str){ if(str==null||str.equals("")){ return 0; } Set<Character> set=new HashSet<Character>(); int maxLength=0; int pre=0; int after=0; while(after<str.length()){ if(!set.contains(str.charAt(after))){ set.add(str.charAt(after)); after++; }else{ set.clear(); //System.out.println("pre: "+pre+" after: "+after); if((after-pre)>maxLength){ maxLength=after-pre; } pre++; after=pre; } } if((after-pre)>maxLength){ maxLength=after-pre; } return maxLength; } public static void main(String[] args) { String str="abcdaf"; System.out.println(maxLength(str)); } }
第二种思路比较巧妙,思路是这样的这次要以一个hashmap作为辅助,map的key存储的是字符,value存储的是该字符当前的位置,首先设置一个头指针,指向字符串开头,那么从开始遍历字符串,如果map当中不包含这个字符,那么用这个字符当前所在的位置减去头指针的位置,然后与最大长度做比较,选打的成为最大长度,然后把当前字符的以及位置放入map,以abba为例,头指针指向a,当前为a,那么长度为1,map。put(‘a’,0),当前为b,那么长度为2,map.put('b',1),如果说map中存在当前字符,那么把头指针指向,头指针当前的位置与map中存储该字符位置的下一个位置当中的较大者,成为新的头指针位置,比如当走到第二个b的时候,那么头指针原来是0,当前map中存放b的位置是1,那么头指针指向2,所以长度为1,比最大长度小不进行替换,最后将当前的字符及位置放入map,现在是map.put('b',2),然后走到了a,那么当前map中a的位置是0,那么它的下一个位置是1,与当前头指针位置2相比,小于当前头指针的位置,那么头指针不跟新,所以长度为2,与最大长度相等,所以不替换,最后求出最大长度为2.
这种思路的时间复杂度为o(n),效率比较高,但是思考起来比较复杂,个人建议这种思路,下面是我的代码:
package com.test; import java.util.HashMap; import java.util.Map; public class Main2 { public static int lengthOfLongestSubstring(String s) { Map<Character,Integer> map=new HashMap<Character,Integer>(); int maxLength=0; int now=0; for(int i=0;i<s.length();i++){ //System.out.println(now); //System.out.println(map); if(map.containsKey(s.charAt(i))){ //System.out.println("now:"+now); now=Math.max(map.get(s.charAt(i))+1,now); if((i-now+1)>maxLength){ maxLength=i-now+1; } }else{ if((i-now+1)>maxLength){ maxLength=i-now+1; } } map.put(s.charAt(i), i); } return maxLength; } public static void main(String[] args) { // TODO Auto-generated method stub String str="abba"; System.out.println(lengthOfLongestSubstring(str)); } }
相关文章推荐
- vimer
- 解决 PowerDesigner 错误 The generation has been cancelled because errors have been found by the check model.
- java实现顺序栈
- 知识点——操作系统
- web设计_4_可扩展的行
- 处理一些编译警告的简单
- android launcher
- [LeetCode][JavaScript]Lowest Common Ancestor of a Binary Tree
- 黑马程序员——Java包、内部类、Object类
- mvc框架
- 跨域访问实现依据
- UPUPW_NGINX_PHP5.3.29_1504.7z的问题 REQUEST 数字的时候,有时候会失效
- UVALive 6953 Digi Comp II(搜索)
- Two Sum
- ClearCase命令mkbl的描述
- HDU 5280 BestCoder Round#47 1001 ---枚举+dp
- Android学习笔记(十)
- codeforces 556 D Case of Fugitive
- iOS中形参个数可变的方法
- android ExpandableListView二级列表