(LeetCode)无重复字符的最长子串(弱智向)

无重复字符的最长子串

题目:

在这里插入图片描述
首先,先用了一个很蠢的算法,就是直接暴力求解。
用两个循环,外层循环提供子串开始字符,内层循环一直加一,直到出现重复字符退出。重复字符的计数用了哈希表的一点思想,直接将字符ASCII码作为索引下标,时间复杂度是O(n^2)。

public class Longest{
    public static void main(String[] args) {
        String s = new String("abcabcbb");
        System.out.println(lengthOfLongestSubstring(s)); 
    }
    public static int lengthOfLongestSubstring(String s){
       
        int res=0;
        //int hold=0;
        for(int i=0;i<s.length();i++){
            boolean[] arr=new boolean['z'+1];//没被选就是false
            int j=i;
            while(j<s.length()&&arr[s.charAt(j)]!=true){
                arr[s.charAt(j)]=true;
                j++;
            }
            if(j-i>res)res=j-i;
        }
        return res;
    }
    
}

最后效果是真滴想吐槽。。。你们设计得也太慢了点吧(或者说他这个排名是所有语言统一的?我占了java的便宜?但是C++理论上比java快个四五倍吧)
在这里插入图片描述

改进

如何改进我是这样想的,实际上,中间有很多是没有必要算的,即一个无重复子串中,从第一个到被退出的那个字符间,之后是没必要再遍历了。如,“rbcadabefg”中,第一个符合条件的子串即rbcad,其中从r到a之后都不用再遍历了,下一次找符合的子串的开头从d开始就可以了。这有点动态规划的意思在里面。基于这样的思想,我就这样写了:

 public static int lengthOfLongestSubstring(String s){
       
        int res=0;
        //int hold=0;
        
       for(int i=0;i<s.length();){
            int[] arr=new int[128];//没被选就是-1
            for(int t=0;t<128;t++)arr[t]=-1;
            int j=i;
            while(j<s.length()&&arr[s.charAt(j)]==-1){
                arr[s.charAt(j)]=j;
                j++;
            }
            if(j-i>res)res=j-i;
            if(j>=s.length()-1)break;
            i=arr[s.charAt(j)]+1;
           
        }
        return res;
    }

然后。。。令我吃惊的是。。。。
在这里插入图片描述
???WHAT THE MOTHER FUCKER????
后来我在评论里面找到了一位大佬的做法
感觉基本思路大同小异

 public static int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
//         用map来保存每个字符的位置,初始时为-1
        int[] map = new int[128];
        for (int i = 0; i < 128; i++) {
            map[i] = -1;
        }
//         i是当前位置,start是当前子字符串的起始位置
        int start = 0, max = 1, i = 0, index;
        for (; i < s.length(); i++) {
//             将字符转为数字作为数组索引
            index = (int) s.charAt(i);
//             如果当前字符在数组中存在且位置不小于起始位置,说明此字符重复
//             更新最大长度,将起始位置挪到此位置之后
            if (map[index] >= start) {
                max = Math.max(i - start, max);
                start = map[index] + 1;
            }
//             更新当前字符的位置
            map[index] = i;
        }
        max = Math.max(i - start, max);
        return max;
    }

但是实际效果大不一样
在这里插入图片描述
认真读了别人的代码之后,发现大佬比我牛的地方在于,大佬只用了一次循环,只初始化了一次数组。实际上大佬的复杂度只有O(n),而我有着大量多余的设定。
在深入的推测下大佬是怎么想到的。
很像前面的“最长升序子集问题”,核心思想就是,从第一个字符开始,找到当前状态的最大子串,然后往后面依次挪动,顺理成章的就有后面一个字符符合条件与否的判断。
在这里插入图片描述
在这里插入图片描述

还有,就是我的代码写得是真的丑,
以后一定要尽可能漂亮一点。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值