• 乘风破浪:LeetCode真题_003_Longest Substring Without Repeating Characters


     乘风破浪:LeetCode真题_003_Longest Substring Without Repeating Characters

    一、前言

        在算法之中出现最多的就是字符串方面的问题了,关于字符串的模式匹配,回文字符串,等等问题都是非常经典的,同样的在字符串之中寻找最长的不重复的字符串的长度也是比较有意义的。

    二、LeetCode真题_003_Longest Substring Without Repeating Characters

    2.1 问题

    2.2 分析与解决

        问题是非常清晰的,我们最先想到的就是使用暴力算法,通过读取当前的字符和已经读取过的字符进行比较,如果冲突则调整开始的位置,并记录当前的最大长度,直至遍历结束,这样的时间复杂度就要到达O(n~3)了。那么有没有比较好的解决方案的,我们又想到了hash算法,这样就省去了比较需要花费的遍历时间,增加了程序需要占用的空间。

        首先看看官方的作答:

        暴力算法:

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

       使用HashSet:

    public class Solution {
        public int lengthOfLongestSubstring(String s) {
            int n = s.length();
            Set<Character> set = new HashSet<>();
            int ans = 0, i = 0, j = 0;
            while (i < n && j < n) {
                // try to extend the range [i, j]
                if (!set.contains(s.charAt(j))){
                    set.add(s.charAt(j++));
                    ans = Math.max(ans, j - i);
                }
                else {
                    set.remove(s.charAt(i++));
                }
            }
            return ans;
        }
    }
    

       使用HashMap:

    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);
                }
                ans = Math.max(ans, j - i + 1);
                map.put(s.charAt(j), j + 1);
            }
            return ans;
        }
    }
    

       假设只有ASCII的字符出现,没有中文:

     

    public class Solution {
        public int lengthOfLongestSubstring(String s) {
            int n = s.length(), ans = 0;
            int[] index = new int[128]; // current index of character
            // try to extend the range [i, j]
            for (int j = 0, i = 0; j < n; j++) {
                i = Math.max(index[s.charAt(j)], i);
                ans = Math.max(ans, j - i + 1);
                index[s.charAt(j)] = j + 1;
            }
            return ans;
        }
    }
    

     

       我们的算法:

     1 import java.util.Arrays;
     2 import java.util.HashMap;
     3 import java.util.Map;
     4 
     5 public class Solution {
     6 
     7     // 可以处理所有的UTF-8字符
     8     public int lengthOfLongestSubstring(String s) {
     9         // 字符串输入不合法
    10         if (s == null) {
    11             return 0;
    12         }
    13 
    14         // 当前处理的开始位置
    15         int start = 0;
    16         // 保存结果
    17         int result = 0;
    18         // 访问标记,记录最新一次访问的字符和位置
    19         Map<Character, Integer> map = new HashMap<>(s.length());
    20 
    21         for (int i = 0; i < s.length(); i++) {
    22             char ch = s.charAt(i);
    23             // 如果字符已经出现过(在标记开位置算起),就重新标记start
    24             if (map.containsKey(ch) && map.get(ch) >= start) {
    25                 start = map.get(ch) + 1;
    26             }
    27             // 如果没有出现过就求最大的非重复子串的长度
    28             else {
    29                 result = Math.max(result, i - start + 1);
    30             }
    31 
    32             // 更新访问记录
    33             map.put(ch, i);
    34         }
    35         return result;
    36     }
    37 
    38     // 只考虑ASCII字符
    39     public int lengthOfLongestSubstring2(String s) {
    40         // 字符串输入不合法
    41         if (s == null) {
    42             return 0;
    43         }
    44 
    45         // 标记字符是否出现过,并且记录是的最新一次访问的元素的位置
    46         int[] appear = new int[256];
    47         // 初始化为-1
    48         Arrays.fill(appear, -1);
    49         // 当前处理的开始位置
    50         int start = 0;
    51         // 保存结果
    52         int result = 0;
    53 
    54         for (int i = 0; i < s.length(); i++) {
    55             // 如果字符已经出现过(在标记开位置),就重新标记start
    56             if (appear[s.charAt(i)] >= start) {
    57                 start = i + 1;
    58             }
    59             // 如果没有出现过就求最大的非重复子串的长度
    60             else {
    61                 result = Math.max(result, i - start + 1);
    62             }
    63             // 标记第i个字符已经被访问过(最新是第i个位置)
    64             appear[s.charAt(i)] = i;
    65         }
    66 
    67         return result;
    68     }
    69 }

    三、总结

        字符串方面的问题我们要非常熟悉String的一些工具函数,以及考虑到hash算法的数据结构来优化和解决问题。

  • 相关阅读:
    Illegal access: this web application instance has been stopped already. could not load **
    mysql 分配内存大小配置
    top 命令
    Linux 创建用户 限制SFTP用户只能访问某个目录
    curl get请求
    VMware虚拟机ubuntu显示屏幕太小解决办法
    Micropython TPYBoard V10X拼插编程实践之定时器 代码不精通?...
    Micropython TPYBoard v102 自动浇花实验
    Micropython TPYBoard读取芯片上的温度传感器
    TPYBoard v102 DIY照相机(视频和制作流程)
  • 原文地址:https://www.cnblogs.com/zyrblog/p/10208079.html
Copyright © 2020-2023  润新知