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 的 源码,受教了~

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

  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/weixiao1717/p/14540862.html
Copyright © 2011-2022 走看看