# 说到【最长】第一想法就是动规;【去重复】第一想法就是哈希 # 题目:无重复的子序列长度 # # @param arr int整型一维数组 the array # @return int整型 # class Solution: def maxLength(self , arr ): # write code here """ # 状态定义:以arr[i]结尾的最长子串长度为dp[i] dp = [1] + [0] * (len(arr)-1) mark = 0 # 寻找最长子串的开头位置 # 遍历整个串 for i,s in enumerate(arr): for j in range(mark, i): if s == arr[mark]: mark = j + 1 # mark 是从上一个状态开始变的,不用从头考虑 dp[i] = i - mark + 1 return max(dp) """ dic = {} res = tmp = 0 for j in range(len(arr)): i = dic.get(arr[j], -1) dic[arr[j]] = j tmp = j - i if tmp >= j - i else tmp + 1 res = max(res, tmp) return res
# 题目分析: # 长度为n的字符串共有n(n+1)/2个子字符串(复杂度为O(n^2) # 判断长度为n的字符串是否有重复字符的复杂度为O(n) # 因此本题使用暴力法解决的复杂度为O(n^3) # # 状态定义:dp[i]表示以str[i]结尾的最长不重复子串的个数 # 状态转移:添加新字符,dp[] # 状态初始化:dp[0]=1 # 是否包含重复字符如何判断?选择使用两个下标变量表示 class Solution: def lengthOfLongestSubstring(self, s: str) -> int: dp, j = [1] + [0] * (len(s) - 1), 0 # 用于比较i之前的元素是否与i所指元素一致 if s == '': return 0 for i in range(1, len(s)): # 每新加一个字符,就需要判断该字符是否在s[j:i]中包含,若不包含j不变,若包含j,那么j移动到下一个字符 for k in range(j, i): if s[i] == s[k]: j = k + 1 dp[i] = i - j + 1 print(i, j, dp) return max(dp) # 虽然解出来了,但是没有找到状态转移公式:dp[i]=dp[i-1]+1 if dp[i-1]<j-i else i-j # 并且时间复杂度为O(n^2),空间复杂度O(n)可以用tmp来降低 # 本题比较关键的点就是找前面子串中是否出现过当前字符,并且找出该字符的位置。(我的方式时遍历前面的子串) # 可以通过哈希表来存储各个字符出现最后一次的位置 class Solution1: def lengthOfLongestSubstring(self, s: str) -> int: dic = {} # 用于寻找重复出现的字符 res = tmp = 0 # 取代dp数组造成的空间复杂度 for j in range(len(s)): # 右边界(新添字符位置) i = dic.get(s[j], -1) # 获取左边界i dic[s[j]] = j # 更新哈希表 tmp = tmp + 1 if tmp < j - i else j - i # 状态转移 res = max(res, tmp) return res print(Solution1().lengthOfLongestSubstring('abcabcbb'))