【力扣】第三题-寻找不重复的最长字串的长度

寻找字串的问题常常用到滑动窗口法,就是利用两个下标之间的间距去解决问题
先说我的想法,前面的坐标去取元素,然后去和前面的元素数组去比较(看这个数组里是否包含这个元素,如果包含返回此坐标,如果不包含,开始下次循环)。如果前面数组元素包含upIndex元素,就让underIndex等于返回下标+1,目的就是让underIndex和upIndex里面不包含重复的元素。这样也有一个问题,就是最后一个元素无法判断…下面为本人代码(有BUG)

    public int lengthOfLongestSubstring(String s) {
        char[] ss = new char[s.length()];
        int length = 1;
        int underIndex = 0;
        int upIndex = 1;
        for (int i = 0; i < s.length(); i++) {
            ss[i] = s.charAt(i);
            int index = belongsTo(s.charAt(upIndex), ss, underIndex, upIndex);
            if (upIndex - underIndex > length){
                length = upIndex - underIndex;
            }
            if (index != -1) {
                underIndex = index+1;
            }
            if (upIndex < s.length()-1){
                upIndex++;
            }
        }
        return length;
    }

    public int belongsTo(char s,char[] ss,int m,int n){
        for (int i = m; i <= n; i++) {
            if (s == (ss[i])){
                return i;
            }
        }
        return -1;
    }

经过一晚上的折磨还是看了评论区,看到一个和我的思想类似,但是他的方法更好,他是利用HashMap的key值唯一性来判断是否重复(就是利用这点来取代我第二个方法)这样可不用考虑最后一个元素的问题,不得不佩服。下面是源码

public static int lengthOfLongestSubstring(String s) {
        int  length=0,left=0,right=0;
        Integer n ;
        HashMap<Character, Integer> hm = new HashMap<>();
        for (right=0; right < s.length(); right++) {//右窗逐个滑动
            n = hm.put(s.charAt(right), right);//每个新字符放入hashMap。如果有重复,即第right号字符与前面的第n号字符重复,则hashMap中right会替代n,并返回n。
            if (n != null) {//如果发现重复字符,第n号字符
                if(n>=left){//重复的字符如果落在窗内,则左窗直接收缩至该元素的后一个元素,无需逐个收缩
                    length = Math.max(length,(right-left));//左窗收缩前,先记录最大长度,即从第left号到第right-1号字符,共(right-1)-left+1=right-left个元素
                    left=n+1;//左窗直接收缩至该字符后面一个元字符
                }
            }
        }
        //如果遍历到最后一个字符之后,都没有重复,则再刷新一次Length,此时right = s.length()
        length = Math.max(length, (right-left));
        return length;
    }

最后来说终极大佬的办法,代码非常简洁,非常难懂,但是理解了上面的思想会对理解此方法有一定的帮助。他是利用ASCII码来决定元素在数组的存放位置及出现的次数。他里面有两个max函数,第一个的作用就是为了判断这个元素是否已经出现过。如果后面大就是重复元素,如果前面大就是非重复元素。第二个max函数是记录连个坐标之间的距离的。其实他的i相当于我的upIndex,start相当于我的underIndex,这个大佬的办法属实太经典了,绝非凡人,耐人寻味

public int lengthOfLongestSubstring(String s) {
        // 记录字符上一次出现的位置
        int[] last = new int[128];
        for(int i = 0; i < 128; i++) {
            last[i] = -1;
        }
        int n = s.length();

        int res = 0;
        int start = 0; // 窗口开始位置
        for(int i = 0; i < n; i++) {
            int index = s.charAt(i);
            start = Math.max(start, last[index] + 1);
            res   = Math.max(res, i - start + 1);
            last[index] = i;
        }

        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值