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

    时间:2020/03/24

    一.题目描述

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

    示例 1:

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

    示例2:

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

    示例3:

    输入: "pwwkew"
    输出: 3
    解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
      请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

    二.算法

    1.暴力法

    题解:

    通过双层循环找出s的所有子串,并对每个字串判定是否含有重复字符,在判定的过程中使用HashSet。使用该方法虽然可以,但是会超过题目要求的时间复杂度。

    代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            if("".equals(s)){
                return 0;
            }
            else{
                int len = s.length();
                int num = 1;
                for(int i = 0; i < len; i++){
                    for(int j = i + 1; j < len; j++){
                        if(noRepetition(s, i, j))
                        num = Math.max(num, j - i + 1);
                    }
                }
                return num;
            }
        }
    
        public boolean noRepetition(String s, int start, int end){
            Set<Character> set = new HashSet<>();
            for(int i = start; i <= end; i++){
                if(set.contains(s.charAt(i)))   return false;
                set.add(s.charAt(i));
            }
            return true;
        }
    }

     时间复杂度:O(n3

    2. 滑动窗口

    概念:

    滑动窗口是解决数组以及字符串问题的常用抽象概念。窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即[i, j)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将[i, j)向右滑动1个元素,则它将变为[i+1, j+1)。注意:这里不一定左右边界都加1,可以只是一个边界加1。

    题解:

    开始时左右边界都为0,并且创建一个HashSet来存放整个窗口,使用HashSet的优点是查找的时间复杂度可以认为是O(1)。然后开始遍历,判断该位置的字符是否在set中,如果不在,需要添加到set中,如果在,则要判断当前窗口和num(即现有最长子串的长度)哪一个大,将大的赋值给num,之后还要让左边界右移一个单位。这里还有需要注意的一点:在循环外需要再判断一次。(这里与官方题解不同,算是一点小的优化)

    代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int len = s.length();
            Set<Character> set = new HashSet<>();
            int num = 0, i = 0, j = 0;
            while(i < len && j < len){
                if(!set.contains(s.charAt(j))){
                    set.add(s.charAt(j++));
                }
                else{
                    num = Math.max(num, j - i);
                    set.remove(s.charAt(i++));
                }
            }
            num = Math.max(num, j - i);
            return num;
        }
    }

     时间复杂度:O(n)

     3.优化的滑动窗口

    题解:

    该方法在上面方法的基础上改用HashMap来存储字符,这样可以建立从子符到索引的映射,注意:在HashMap中,当键已经存在时,值会被覆盖。就是说,如果s[j]在[i, j)范围内有与当前字符相同的字符,假设该字符的位置是k,我们不需要逐渐增加i,可以直接跳过[i, k]范围内的所有字符,并将i变为k+1。

    代码:

    public class Solution {
        public int lengthOfLongestSubstring(String s) {
            int n = s.length(), ans = 0;
            Map<Character, Integer> map = new HashMap<>(); // current index of character
            // try to extend the range [i, j]
            for (int j = 0, i = 0; j < n; j++) {
                if (map.containsKey(s.charAt(j))) {
                    i = Math.max(map.get(s.charAt(j)), i);  //look
                }
                ans = Math.max(ans, j - i + 1);
                map.put(s.charAt(j), j + 1);
            }
            return ans;
        }
    }

    注意:大家可能会对注释了look的那一行产生疑问,为什么要与i比较并取最大值呢?这里举一个例子:字符串s为abba。你自己在脑海中运行一遍这个例子就知道了。

    时间复杂度:O(n)

    4.我自己的方法

    题解:

    这是我做这道题时第一次想到的方法,主要思想就是遍历整个字符串,找到每个位置字符所能组成的最大的不重复的子串,然后取其中的最大长度就是答案。

    代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int num = 0;
            if(s == null){
                return num;
            }
            else{
                char[] c = s.toCharArray();
                HashMap<Character, Integer> map = new HashMap<>();
                int nowNum = 0;
                int len = c.length;
                int index = 0;
                for(int i = 0; i < len; i++){
                    if(!map.containsKey(c[i])){
                        nowNum++;
                        map.put(c[i], 1);
                    }
                    else{
                        if(nowNum > num){
                            num = nowNum;
                        }
                        nowNum = 0;
                        map.clear();
                        index++;
                        i = index - 1;
                        // System.out.println(map);
                    }
                }
                if(nowNum > num){
                    num = nowNum;
                }
            }
            return num;
        }
    }
  • 相关阅读:
    基本内置类型
    多维数组
    数组
    迭代器
    标准库类型 vector
    标准库类型 string
    运算符优先级表
    类型转换
    sizeof 和逗号运算符
    位运算符
  • 原文地址:https://www.cnblogs.com/machi12/p/12560634.html
Copyright © 2011-2022 走看看