• [LeetCode]3. Longest Substring Without Repeating Characters


    原题链接:https://leetcode.com/problems/longest-substring-without-repeating-characters/description/

    意思是给定字符串,输出无重复字符的最长子串长度

    我的实现(Brute Force)生成全部无重复子串,从而得到最大长度:

    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            int max_length = 0;
            
            if (!s.empty())
                max_length = 1;
            
            for (int i = 0; i < s.length(); i++) {
                for (int j = i + 1; j < s.length(); j++) {
                    string sub = s.substr(i, j - i);
                    int pos = sub.find(s.at(j));
                    if (pos == string::npos) {
                        if (max_length < sub.length() + 1)
                            max_length = sub.length() + 1;
                    } else {
                        break;
                    }
                }
            }
            
            return max_length;
        }
    };

    时间复杂度:O(n3​​).

    空间复杂度:O(n). 

    如何提升:

    Sliding Window + HashSet

    Sliding Window:指的是由起始和终止索引所确定的子段[i,j) (left-closed, right-open). 

    HashSet:集合元素的唯一性,比起我用字符串好多了(无重复元素的问题)

    思想:[i, j-1]已知无重复字符,只需判断是否要拓展j:

    1.如果j位置的字符在集合中已存在,则对于i开始的最长无重复字符串在j-1时就结束了,接下来开始寻找i+1开始的最长无重复字符串,同时字符集合中需去除i位置字符;

    2.如果j位置的字符在集合中不存在,则将j位置的字符加入字符集合,再判断是否拓展j+1。

    可以看到它的重点在于字符集合和已经确定了无重复字符段的使用。实现代码(Java):

    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;
        }
    }

    时间复杂度:O(n).

    空间复杂度:O(min(m,n)). m为字符集合的长度

    在Sliding Window基础上进一步优化:

    前面我们是发现重复字符就将i加1,但可能i位置的字符并不是重复的字符,我们可以直接跳到Sliding Window中重复字符所在位置的后面,不用每次将i加1,从而避免了一些无意义的操作;获取Sliding Window中重复字符位置可以用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;
        }
    }
    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;
        }
    }

    总结:Set、已确定无重复段的使用,对重复字符位置的处理。

  • 相关阅读:
    VC++对话框笔记
    STL中用erase()方法遍历删除元素
    VC++中不小心选错工程类型的解决办法
    directX中常用的数学计算
    VC++中string、char* 转换为LPCSTR
    判断空间上点是否在直线上
    vc6.0插件
    VC++常用定义(如SAFE_DELETE等)
    关于控件的AutoSize属性影响界面布局的问题解决
    C#判断日期是否正确(1900~今年,月份,天数)
  • 原文地址:https://www.cnblogs.com/qianzixuan1996/p/8287300.html
Copyright © 2020-2023  润新知