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;
        }
    }
  • 相关阅读:
    稳扎稳打Silverlight(47) 4.0UI之操作剪切板, 隐式样式, CompositeTransform, 拖放外部文件到程序中
    返璞归真 asp.net mvc (9) asp.net mvc 3.0 新特性之 View(Razor)
    返璞归真 asp.net mvc (6) asp.net mvc 2.0 新特性
    稳扎稳打Silverlight(48) 4.0其它之打印, 动态绑定, 增强的导航系统, 杂七杂八
    精进不休 .NET 4.0 (9) ADO.NET Entity Framework 4.1 之 Code First
    稳扎稳打Silverlight(42) 4.0控件之Viewbox, RichTextBox
    稳扎稳打Silverlight(53) 4.0通信之对WCF NetTcpBinding的支持, 在Socket通信中通过HTTP检索策略文件, HTTP请求中的ClientHttp和BrowserHttp
    稳扎稳打 Silverlight 4.0 系列文章索引
    稳扎稳打Silverlight(54) 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”
    返璞归真 asp.net mvc (8) asp.net mvc 3.0 新特性之 Model
  • 原文地址:https://www.cnblogs.com/machi12/p/12560634.html
Copyright © 2011-2022 走看看