zoukankan      html  css  js  c++  java
  • 无重复字符的最长子串

    题目

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

    示例 1:

    输入: s = "abcabcbb"
    输出: 3
    解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

    示例 2:

    输入: s = "bbbbb"
    输出: 1
    解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

    示例 3:

    输入: s = "pwwkew"
    输出: 3
    解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

    请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

    示例 4:

    输入: s = ""
    输出: 0

    解题思路

    当字符串为空或者长度为1时,直接返回字符串的长度

    当字符串的长度大于1时,默认不重复字符串最大长度为1,采用两个指针 up 和 down 分别指向 字符数组的第一个、第二个位置

    如果 up 和 down 指向的字符不相同,则 up 不动,down 向后移动,

    否则,取出[up,down)之间的字符组成字符串,并同存储的不重复字符串最大长度比较,如果大于存储的不重复字符串最大长度,就更新其值,然后 down 指针不动,up向后移动,接着重复上述过程

    移动过程中始终保持 down 指针 在 up指针的后面

    代码

    版本1.1

    public class prac3 {
        public static void main(String[] args) {
            int len = lengthOfLongestSubstring("ckilbkd");
            System.out.println(len);
        }
    
        public static int lengthOfLongestSubstring(String s) {
            //如果字符串为空或为单个字符,直接返回字符串的长度
            if (s.length() <= 1) {
                return s.length();
            }
            //字符串的长度大于1的情况
            //将字符串转为字符数组
            char[] chars = s.toCharArray();
            //定义两个指针,up,down
            int up = 0;
            int down = 1;
            int max_str_len = 1;
            String split_str = "" + chars[0];
            while (down < s.length()) {
                if (!split_str.contains("" + chars[down])) {
                    split_str = split_str + chars[down];
                    down++;
                } else {
                    String temp = getStr(chars, up, down);
                    if(temp.length()>max_str_len){
                        max_str_len = temp.length();
                    }
                    up++;
                    if(up==down){
                        down++;
                    }
                    split_str = getStr(chars,up,down);
                }
            }
            if(split_str.length()>max_str_len){
                max_str_len = split_str.length();
            }
            return max_str_len;
        }
    
        public static String getStr(char[] chars, int i, int j) {
            String str = "";
            for (int k = i; k < j; k++) {
                str += chars[k];
            }
            return str;
        }
    
    }
    
    

    版本1.2

    public class prac3 {
        public static void main(String[] args) {
            int len = lengthOfLongestSubstring("pwwkew");
            System.out.println(len);
        }
    
        public static int lengthOfLongestSubstring(String s) {
            //如果字符串为空或为单个字符,直接返回字符串的长度("","d")
            if (s.length() <= 1) {
                return s.length();
            }
            //字符串的长度大于1的情况
            //将字符串转为字符数组
            char[] chars = s.toCharArray();
            //定义两个指针,up,down
            int up = 0;
            int down = 1;
            int max_str_len = 1;
            String split_str = "" + chars[0];
            while (down < s.length()) {
                if (!split_str.contains("" + chars[down])) {
                    split_str = split_str + chars[down];
                    down++;
                } else {
                    String temp = getStr(chars, up, down);
                    if(temp.length()>max_str_len){
                        max_str_len = temp.length();
                    }
                    //"abcdc":down指针指向第二个'c'时,发现了重复,为了避免重复比较,采用
                    //此方式将 up指针 直接指向 'd'
                    up = down - (temp.length() - temp.indexOf(chars[down])) + 1;
                    //down指针和 up指针 有时会指向同一个字符
                    // 采用此方式始终保持 down 在 up 的后面,例子:("aaabcd")
                    if(up==down){
                        down++;
                    }
                    split_str = getStr(chars,up,down);
                }
            }
            //针对没有重复字符串的情况(abcde)
            if(split_str.length()>max_str_len){
                max_str_len = split_str.length();
            }
            return max_str_len;
        }
    
        public static String getStr(char[] chars, int i, int j) {
            String str = "";
            for (int k = i; k < j; k++) {
                str += chars[k];
            }
            return str;
        }
    
    }
    

    大佬代码学习

    思路
    • 标签:滑动窗口

    • 暴力解法时间复杂度较高,会达到 O(n^2),故而采取滑动窗口的方法降低时间复杂度

    • 定义一个 map 数据结构存储 (k, v),其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复

    • 我们定义不重复子串的开始位置为 start,结束位置为 end

    • 随着 end 不断遍历向后,会遇到与 [start, end] 区间内字符相同的情况,此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 区间内不存在重复字符

    • 无论是否更新 start,都会更新其 map 数据结构和结果 ans。

    • 时间复杂度:O(n)

    • 作者:guanpengchn
      链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/hua-jie-suan-fa-3-wu-zhong-fu-zi-fu-de-zui-chang-z/

      来源:力扣

    代码示例
    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int n = s.length(), ans = 0;
            Map<Character, Integer> map = new HashMap<>();
            for (int end = 0, start = 0; end < n; end++) {
                char alpha = s.charAt(end);
                if (map.containsKey(alpha)) {
                    start = Math.max(map.get(alpha), start);
                }
                ans = Math.max(ans, end - start + 1);
                map.put(s.charAt(end), end + 1);
            }
            return ans;
        }
    }
    

    个人感受:感觉大佬这个算法还是挺好的,但是不好理解,我觉得存储字符下标更容易理解,在理解大佬的思想后,自己又写了一份代码,感觉确实优化了不少。

    class Solution {
        public int lengthOfLongestSubstring(String s) {
           int len = s.length();
            int max_len =  0;
            HashMap<Character,Integer> map = new HashMap<>();
            for (int end=0,start=0; end < len; end++) {
                char alpha = s.charAt(end);
                if(map.containsKey(alpha)){
                    //原先自己的思路是采用 start = map.get(alpha) + 1 来
                    //更新start指针的位置,后来发现有问题
                    //在测试字符串 "abba" 时,当 end 指向 最后一个 'a' 时,发现重复
                    //于是将 start 更新为 第一个字符'a'的位置,这就增大了最大无重复字符串的长度
                    start = Math.max(map.get(alpha) + 1,start);
                }
                map.put(alpha,end);
                max_len = Math.max(max_len,end - start + 1);
            }
            return max_len;
        }
    }
    
    • 测试案例: "" "a" "aaaa" "aaabbw" "pwwkew" "abcabcbb" "abba"
    • 感觉力扣给出的测试案例还是挺好的,通过案例很容易发现问题并改进自己的代码,这道题感觉自己想复杂了,字符串长度完全可以通过两个指针来得到,自己却先将其截取,再求长度,使问题变得更复杂,HashMap真是好用,怪不得面试总爱问 hashMap 的 源码,受教了~

    感想:第一次做力扣的算法题,感觉还是挺难的,一方面自己思路不清晰,另一方面容易少考虑情况,提交了好几次都是错的~,代码还是使用笨的方法实现的,这道题的类型属于滑动窗口,明天准备学习下大神的代码,并学习下左神算法的视频,以后要坚持刷算法题

  • 相关阅读:
    20145214 《信息安全系统设计基础》实验五 网络通信
    20145214 《信息安全系统设计基础》第12周学习总结
    20145214 《信息安全系统设计基础》第11周学习总结
    20145214 《信息安全系统设计基础》实验四 驱动程序设计
    20145214 《信息安全系统设计基础》实验三 实时系统的移植
    20145214 《信息安全系统设计基础》第10周学习总结
    20145214 《信息安全系统设计基础》实验二 固件开发
    20145214 《信息安全系统设计基础》第9周学习总结
    20145325张梓靖 《网络对抗技术》 第2周学习总结
    20145325 《信息安全系统设计基础》实验四 外设驱动程序设计(添加代码分析)
  • 原文地址:https://www.cnblogs.com/weixiao1717/p/14540862.html
Copyright © 2011-2022 走看看