zoukankan      html  css  js  c++  java
  • 给定字符串,求其最长不重复子串

    原文:https://blog.csdn.net/z69183787/article/details/103291318

    问题描述:
    输入:abdca 返回:abdc

    方法一:
    暴力解析:遍历出给定字符串的所有子串,判断其中是否有重复字符,没有则记录长度,与下一次也无重复字符的子串比较长度,最长的即为所求。

    代码:

    public static String noDuplicate(String str) {
            if(str==null||str.length()==0){
                return null;
            }
            Set<String> set = new HashSet<>();
            String result = "";
            System.out.println("length:" + str.length());
            for (int i = 0; i < str.length(); i++) {
                for (int j = i + 1; j <= str.length(); j++) {
                    String s = str.substring(i, j);
                    set.add(s);
                }
            }
            int max = 0;
            Iterator iterator = set.iterator();
            while (iterator.hasNext()) {
                LinkedHashSet<String> setchar = new LinkedHashSet<>();
                String  st = iterator.next().toString();
                for (int a = 0; a < st.length(); a++) {
                    setchar.add(String.valueOf(st.charAt(a)));
                }
                if(setchar.size()==st.length()){
                    int len = st.length();
                    if(max<len){
                        max = Math.max(max, len);
                        result = st;
                    }
                }
            }
            System.out.println(max);
            return result;
        }

    暴力法的时间复杂度为:n2+n2===>2n2 即O(n2) 
    时间复杂度排序: 
    Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)

    方法二:
    滑动窗口:保证窗口中都是不重复的子串实现 _有回溯

    public static String getMaxsubHuisu(String s) {
            if (s == null || s.length() == 0) {
                return null;
            }
     
            int start = 0;//滑动窗口的开始值
            int maxlen = 0;
            int len = 0;
            int startMaxIndex = 0;//最长子串的开始值
            Map<Character, Integer> map = new HashMap<>();//存储窗口内字符跟位置
            int i;
            for (i = 0; i < s.length(); i++) {
                char ch = s.charAt(i);
                Integer value = map.get(ch);
                if (map.containsKey(ch)) {//map中包含字符,则出现重复字符
                    start = value + 1;//下一次开始的位置是,存在map中重复字符的下一个位置
                    len = 0;//重新开始新的窗口,len置为0
                    map = new HashMap<>();//map置空
                    i=value;//下次从重复的值开始回溯
                } else {
                    map.put(ch, i);//不存在重复的,就存入map
                    len++;//每次进来长度自增1
                    if (len > maxlen) {//如果当前的窗口长度>最长字符串则,更新最长串,跟最长子串开始位置
                        maxlen = len;
                        startMaxIndex = start;
                    }
                }
            }
            return s.substring(startMaxIndex, (startMaxIndex + maxlen));\截取字符串,substring为左闭右开
        }

    实现 _无回溯

    public static String getMaxsub(String s) {
            if (s == null || s.length() == 0) {
                return null;
            }
     
            int start = 0;//滑动窗口的开始值
            int maxlen = 0;
            int len = 0;
            int startMaxIndex = 0;//最长子串的开始值
            Map<Character, Integer> map = new HashMap<>();
            int i;
            for (i = 0; i < s.length(); i++) {
                char ch = s.charAt(i);
                Integer value = map.get(ch);
                if (value != null && value >= start) {//map中存在在字符,且字符的位置在窗口范围内,即字符有效
                    start = value + 1;//下次开始的位置为,重复字符的下一个位置
                    len = i - value;//长度为当前的遍历字符的位置-重复字符的位置
                } else {
                    len++;//若不存在,则字符+1
                    if (len > maxlen) {//若当前窗口的长度>最长子串的位置,则更新最长子串的长度跟最长子串的起始位置
                        maxlen = len;
                        startMaxIndex = start;
                    }
                }
                map.put(ch, i);//无论存在不存在重复字符,都要把遍历的 字符存入map中,重复的则覆盖
            }
            return s.substring(startMaxIndex, (startMaxIndex + maxlen));
     
     
        }

    无回溯_具体过程示意图

    时间复杂度
    有回溯:最好情况无回溯,时间复杂度O(n),最坏情况,每次都回溯O(2n),平均值为O(3/2 *n) 
    无回溯:O(n) 
    在特别长的字符串情况下,会有差异

    小结:
    1.第一步对输入的值做判断,不可忘; 
    2. 滑动窗口法的思路很重要,先用一个窗口限定字符,每次判断字符是否重复,记录位置,最长子串开始位置跟长度,为之后截取字符串做准备 
    3. 要想明白过程,出现重复字符的时候需要做的,不出现重复时候需要做的: 
    出现重复的 时候:更新窗口位置,当前窗口的长度。 
    不出现重复的时候:当前长度自增,判断更新最长子串长度与起始位置,存字符。 
    边界值出错的时候,要重缕思路,不能只是去试,要看思路边界上哪里有问题

  • 相关阅读:
    C# 特性学习笔记
    Nhibernate学习的第二天
    Nhibernate学习的第一天
    SQL循环添加表中的字段
    加班
    bat文件重启SQL服务和IIS服务
    判断是不是手机访问的网站
    解决Ueditor 不兼容IE7 和IE8
    实现链表的初始化,按值查找,插入,删除
    判断任一二叉树,是否为满二叉树.(输出二叉树,节点总数,二叉树深度)
  • 原文地址:https://www.cnblogs.com/UncleWang001/p/13801388.html
Copyright © 2011-2022 走看看