(Java) 无重复字符的最长子串(HashMap详解)

题目:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

 

一开始我的想法是用list集合做,结果虽然很省空间但是用时过长

这是一开始的代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int max = 1;
        if (s.equals("")) {
            max = 0;
        } else {
            List list = new ArrayList();

            int length[] = new int[s.length()];//list集合长度,元素在循环中添加,寻找出最长的
            for (int i = 0; i < length.length; i++) {
                length[i] = 1;
            }
            for (int j = 0; j < length.length-1; j++) {
                list.add(s.charAt(j));
                for (int i = j+1; i < s.length(); i++) {
                    if (!list.contains(s.charAt(i))) {
                        list.add(s.charAt(i));
                        length[j]++;
                    } else {
                        list.clear();
                        break;
                    }
                }
            }

            max = length[0];
            for (int i = 1; i < length.length-1; i++) {
                if (max < length[i]) {
                    max = length[i];
                }
            }

 


 

后来看了大佬们的解析以后才发现自己好傻.....

这是改进后的代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        
        HashMap<Character,Integer> map = new HashMap();
        int ans = 0;//最大值
        int left = 0;//左指针
        for (int i = 0; i < s.length(); i++) {
            if (map.containsKey(s.charAt(i))) {
                left = Math.max(left, map.get(s.charAt(i)) + 1);
            }
            //无论是否相等我们都要录入下一个数的值和位置
            map.put(s.charAt(i), i);
            ans = Math.max(ans, i - left + 1);
        }
        return ans;
    }
}

首先我们定义了一个left值它被认为是左边界,我们的每一次计算字符串字串长度都是从它指向的位置开始(即后面的 i-left+1)

每次录入之前我们先判断HashMap中是否存在该元素

(1)如果不存在的话,我们直接把这个元素和它在字符串中的位置录入进去,以pwwkew为例,p录入进去时,也把它的位置0录入了进去,第一个w录入进去是,它的位置1也被录入进去,随后我们就重新计算字串的长度,i-left代表它们之间的距离,再+1就是字串的长度了,

至于如果不理解为什么用max方法,我们下文会讲到

(2)如果存在的话,那么我们就应该先找到HashMap中存在的这个元素的位置,还是以pwwkew为例  当我们要录入第二个w时,我们发现map中已经存在w元素了,所以我们通过get方法来找到第一个w的位置,也就是1

这个时候我们再让这个数+1,把它赋给left指针

如图所示

原来left指向0位置,现在它变成了1+1  ==2的位置,然后我们要做的事情是,把w这个元素再次记录到map中(其实也就是相当于刷新了它最后一次出现的位置),到这里第一个无重复元素的字串的长度记录工作结束,这时我们得到了长度ans==2

接下来就是记录第二个字串的长度,与上面相同的操作,我们每一次都做判断是否存在,录入map,以及计算字串长度的操作

(现在我们就可以知道为什么要用max方法了,因为第二个字串的初始长度可能是小于上一个字串的长度的,所以我们要去最大的那个长度),直到i==5也就是第三个w的时候,在这之前ans==4-2+1 ==3,

然后我们根据map.get()方法判断上一次w出现的位置,也就是2,所以现在left指向了2+1==3也就是k,我们将w录入也就是刷新它的最后一次出现的位置,然后计算字串的长度,5-3+1 == 3。

所以最大长度ans就是3

 

还有一个需要注意的点就是

                left = Math.max(left, map.get(s.charAt(i)) + 1);

千万不要觉得max没用就写成 left = map.get(s.charAt(i))+1;

像abba这种情况,当我们录入第二个b的时候 left就会等于 1+1 ==2,但是后面又出现了一个a,这个时候如果是这种形式的话,left就会变成0+1 == 1也就相当于left左移了,这个时候的字串就变成了bba了

所以我们一定要取它的max值

 

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值