最长系列
- 1.LeetCode-32 最长有效括号--子串
- 2.LeetCode-300 最长上升子序列--长度
- 3.LeetCode-32 最长回文子串--是什么
- 5.LeetCode-512 最长回文子序列--长度
- 6.LeetCode-1143 最长公共子序列--长度
- 6.LeetCode-128 最长连续序列--长度
- 7.LeetCode-14 最长公共前缀-字符串
- 8.剑指offer-48 最长不含重复字符串的子字符串-长度
列表-子序列(连续/不连续)
字符串-子序列(不连续),子串(连续)
1.一维dp,dp[i] --以item[i]结尾的,有效的,最长XXX的长度
1.LeetCode-32 最长有效括号–子串
题目:给定一个只包含 ‘(’ 和 ‘)’ 的字符串s,找出最长的包含有效括号的子串的长度。
dp[i] --以s[i]结尾的,有效的子串的长度中,最长的一个。
显然有效的子串一定以)结尾,因此我们可以知道以(结尾的子串对应的dp 值必定为 0,我们只需要求解 )在dp 数组中对应位置的值。
同时因为子串要求连续,所以可以用相邻的dp[i-2]来更新符合条件的dp[i](s[i]==")"ands[i−1]=="("=>dp[i]=dp[i−2]+2s[i]==")" and \ s[i-1]=="("=>dp[i] = dp[i-2]+2s[i]==")"and s[i−1]=="("=>dp[i]=dp[i−2]+2})
# 1.s[i]==")" and s[i-1]=="(" dp[i] = dp[i-2]+2
# 2.s[i]==")" and s[i-1]==")" dp[i] = dp[i-1] + dp[i-dp[i-1]-2]+2 下标的合理性
# ((xx)) dp[i-1] 也有效的情况下
def longestValidParentheses(self, s):n=len(s)if n<2:return 0dp=[0]*nres=0for i in range(1,n):if i==1:if s[i]==")" and s[i-1]=="(":dp[1]=2else:if s[i]==")" and s[i-1]=="(":dp[i]=dp[i-2]+2 if s[i]==")" and s[i-1]==")":if i-1-dp[i-1]>=0 and s[i-1-dp[i-1]]=="(":dp[i]=dp[i-1]+2 # if i-2-dp[i-1]>=0:dp[i]+=dp[i-2-dp[i-1]]res=max(res,dp[i]) return res
2.LeetCode-300 最长上升子序列–长度
题目:给定一个无序的整数数组,找到其中最长上升子序列的长度。
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
dp[i] --以nums[i]结尾的,上升序列的长度中,最长的一个。
def lengthOfLIS(self, nums):""":type nums: List[int]:rtype: int"""# dp[i]表示以nums[i]为结尾的最长上升子序列的长度n = len(nums)if n < 2:return ndp = [1] * nres = 0for i in range(1,n):for j in range(i):if nums[j]< nums[i]:dp[i] = max(dp[i], dp[j]+1)res = max(res, dp[i]) # 这么写就需要考虑初值为1的时候return res
2.维度d
3.LeetCode-32 最长回文子串–是什么
独自一个人也,也可以二维dp, 强!二维dp实际上也是以每个字符为中心向两边扩展的情况。
dp[i][j] 表示s[i]-s[j]子串是否是回文子串,依赖于s[i]==s[j] and dp[i+1][j-1]
状态转移决定了dp初始化元素(对角线)和更新的方向(由下向上,由对角线往右)
def longestPalindrome(self, s):n = len(s)if n < 2: # 空字符和单个字符直接输出return sdp = [[False] * n for _ in range(n)]for i in range(n):dp[i][i] = Trueres_str, res_len = s[0], 1 # 两个字符的的时候,不相等时结果为单个字符for i in range(n-2,-1,-1):for j in range(i+1, n):if j == i+1: # 次对角线上的元素单独判断。if s[i] == s[j]:dp[i][j] = Trueif j-i+1 > res_len:res_str = s[i:j+1]res_len = j - i + 1else:if s[i] == s[j] and dp[i+1][j-1]:dp[i][j] = Trueif j-i+1 > res_len:res_str = s[i:j+1]res_len = j - i + 1return res_str
5.LeetCode-512 最长回文子序列–长度
和上题的基本思路一样,不过dp数组表示的含义变为
dp[i][j] 表示s[i]-s[j]子串中回文序列的长度
# if s[i]==s[j]:dp[i][j] = dp[i+1][j-i]+2,
# if s[i]!=s[j]:dp[i][j] = max(dp[i+1][j],dp[i][j-1])
def longestPalindromeSubseq(self, s):n = len(s)if n < 2:return ndp = [[0] * n for _ in range(n)]for i in range(n):dp[i][i] = 1for i in range(n-2, -1, -1):for j in range(i+1,n):if s[j] == s[i]:dp[i][j] = dp[i+1][j-1] + 2else:dp[i][j] = max(dp[i+1][j], dp[i][j-1])return dp[0][n-1]
6.LeetCode-1143 最长公共子序列–长度
(两个字符串,二维dp 才是标配嘛)
dp[i][j] 表示s1[0]-s1[i] 于s2[0]-s2[j] 的最长公共子序序列,更新形式于512题类似,只不过初值和方向不大一样,初值为第0行第0列均为0,方向由上到下,由左到右。
def longestCommonSubsequence(self, text1, text2):l1, l2 = len(text1), len(text2)dp = [[0] * (l2 + 1) for _ in range(l1 + 1)]for i in range(1, l1 + 1):for j in range(1, l2 + 1):if text1[i-1] == text2[j-1]:dp[i][j] = dp[i-1][j-1] + 1else:dp[i][j] = max(dp[i-1][j], dp[i][j-1])# return dp[-1][-1]# 回溯 只有加res_str=[""]*dp[-1][-1]i,j=l1,l2while(i>0):if dp[i][j]>dp[i-1][j]: # 比上面的大,不是来上面if dp[i][j]>dp[i][j-1]: # 比左边的大,不是来自左边res_str[dp[i][j]-1]=text1[i-1] # 来自对角线操作else: # 没有左边大,来自左边 横坐标操作i+=1 # i 需要先+1,最后的-1会抵消j-=1 # 没有左边大,来自左边,纵坐标操作i-=1print(res_str)
3.带技巧解题
6.LeetCode-128 最长连续序列–长度
给定一个未排序的整数数组,找出最长连续序列的长度。要求算法的时间复杂度为 O(n)。
数组本身无序,连续序列有序,只要能找到连续序列的开头,就能确定序列长度,迭代更新最长长度就可以了。
def longestConsecutive(self, nums):if not nums:return 0res = 1nums_set = set(nums)for val in nums_set:if val - 1 not in nums_set: # val 为连续序列的开头count = 1num = valwhile(num + 1 in nums_set):count += 1num = num + 1res = max(res, count)return res
7.LeetCode-14 最长公共前缀-字符串
暴力法:纵向扫描
先验:最长公共前缀不回比最短的字符串长,所以先求出最短的长度。
def longestCommonPrefix(self, strs):""":type strs: List[str]:rtype: str"""n = len(strs)if n == 0:return ""min_l = float("INF")for string in strs:min_l = min(len(string), min_l)i = 0con_pre = ""while(i < min_l):con_pre = strs[0][:i+1]for string in strs:if string[:i+1] != con_pre:return con_pre[:i]i += 1return con_pre
8.剑指offer-48 最长不含重复字符串的子字符串-长度
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
移动窗口,保证窗口内的字符无重复,如果有重复就缩小窗口。
def lengthOfLongestSubstring(self, s):""":type s: str:rtype: int"""win = {}left, right = 0, 0n = len(s)res = 0while (right < n):c1 = s[right]if win.get(c1):win[c1] += 1else:win[c1] = 1right += 1while(win[c1]>1):c2 = s[left]win[c2] -=1left += 1res = max(res, right - left)return res