LeetCode系列:3 Longest Substring Without Repeating Characters

Q:Given a string, find the length of the longest substring without repeating characters.
Example 1:

Input: "abcabcbb"
Output: 3 
Explanation: The answer is "abc", with the length of 3. 
Example 2:

Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:

Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3. 
             Note that the answer must be a substring, "pwke" is a subsequence and not a substring.

E:给定一个字符串,计算出不重复的最长子串的长度。
e.g.
Example 1:
输入: "abcabcbb"
输出: 3
解释: 最长不重复子串是"acb"且长度为3

Example 2:
输入: "bbbbb"
输出: 1
解释: 最长不重复子串是"b"且长度为1
Example 3:

输入: "pwwkew"
输出: 3
解释: 最长不重复子串是"wke"且长度为3,请注意答案必须是子串,"pwke"是子序列而不是子串

A:

因为只需要计算最长长度,不需要记录子串,所以我们可以利用Dictionary或者Set不能重复的特性来存储当前遍历过的串,遇到相同字符,也就是key存在重复。

Approach 1:

方法一先考虑使用Dictionary的实现方式。这里key是遍历的字符,value是该字符在该字符串中的序号(不是下标)。我们使用一个变量记录当前子串的开始下标,当遇到重复字符的时候,这时我们需要去比较当前子串和上一个子串(若没有则为0)的长度,更新当前子串的开始下标(重复字符的下标加一或者还是当前开始下标),更新重复字符的下标,直到字符串遍历结束。

class Solution {
    func lengthOfLongestSubstring(_ s: String) -> Int {
        var begin = 0		//当前子串的开始下标
    	var maxLength = 0	//当前获取的子串的最长长度
    	var map : [Character : Int] = [:]   //key为字符,value为字符的序号(下标+1)
    	for (index, value) in s.enumerated() {//普通for循环与enumerated()性能差别很大,所以尽量使用enumerated(),在这个算法中,使用不同的for循环,性能相差达到100倍
        
        	if let existingIndex = map[value] {	//存在重复字符
            	begin = max(existingIndex, begin)	//更新当前子串的开始下标
        	}
        	maxLength = max(maxLength, index-begin+1)//更新当前获取到的子串的最大长度
        	map[value] = index+1	//更新重复字符的下标
        	// print(map)
    	}
    	return maxLength
    }
}
Complexity Analysis:
  • 时间复杂度: O(n)。(LeetCode:64 ms)
  • 空间复杂度:O(n)。

Approach 2:

方法二先考虑使用Set的实现方式。思路和方法一差不多,没有遇到相同字符的时候,将字符加入到Set中;遇到相同的字符时,更新最长子字符串的长度,更新当前子串的开始下标,同时判定当前字符串是不是重复的字符,若不是,将字符从Set中移除,当前子字符串的开始下标+1直到遇到相同字符。(如字符串是:“abcdecf"子字符是"abcde”,这时遇到相同字符’c’,需要将"ab"从Set中移除,begin指到第一个’c’的位置)。与方法一不同的是,如果最长的子字符是最后那个子串,这样是遍历不出的,所以还需要做一次比较:max(maxLength, charArray.count-begin)。

class Solution {
    func lengthOfLongestSubstring(_ s: String) -> Int {
        var maxLength = 0
        var begin = 0
        var set = Set<Character>()
        let charArray = Array(s)
        for (index, char) in charArray.enumerated() {
            if set.contains(char) {
                maxLength = max(maxLength, index-begin)
                while charArray[begin] != char {
                    set.remove(charArray[begin])
                    begin += 1
                    //print(set)
                }
                begin += 1
                //print(set)
            } else {
                set.insert(char)
                //print(set)
            }
        }
        return max(maxLength, charArray.count-begin)
    }
}
Complexity Analysis:
  • 时间复杂度: O(n)。(LeetCode:76 ms)
  • 空间复杂度:O(n)。

Approach 3:
class Solution {
    func lengthOfLongestSubstring(_ s: String) -> Int {
         var hash = [Int](repeating: 0, count: 256)
        let str = Array(s.utf8).map { Int($0) }
        
        let len = str.count
        var ans = 0
        var j = 0
        for i in 0..<len {
            while j < len && hash[str[j]] == 0 {
                hash[str[j]] = 1
                j += 1
                print(hash)
            }
            ans = max(ans, j - i)
            hash[str[i]] = 0
            print(hash)
        }
        return ans
    }
}
Complexity Analysis:
  • 时间复杂度: O(n)。(LeetCode:36 ms)
  • 空间复杂度:O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值