區(qū)間dp降低時(shí)間復(fù)雜度
給你一個(gè)字符串 s 叉讥,找出其中最長(zhǎng)的回文子序列,并返回該序列的長(zhǎng)度饥追。
子序列定義為:不改變剩余字符順序的情況下图仓,刪除某些字符或者不刪除任何字符形成的一個(gè)序列。
示例 1:
輸入:s = "bbbab"
輸出:4
解釋:一個(gè)可能的最長(zhǎng)回文子序列為 "bbbb" 但绕。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-palindromic-subsequence
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有救崔。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處捏顺。
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n=len(s)
dp=[[0]*n for _ in range(n)]
for i in range(n-1,-1,-1):#需要記憶
dp[i][i]=1
for j in range(i+1,n):
if s[i]==s[j]:
dp[i][j]=dp[i+1][j-1]+2
else:
dp[i][j]=max(dp[i][j-1],dp[i+1][j])
return dp[0][n-1]
'''
ans=1
#純暴力解法O(2^N*N^2)
for i in range(len(s)):
s1,s2='',''
for j in s[i:]:
s1+=j
s2=j+s2
if s1==s2:
ans=max(ans,len(s1))
return ans
'''
順序無所謂帚豪,注意規(guī)劃到最外側(cè)時(shí)的結(jié)果,區(qū)間dp從中心向外擴(kuò)展
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n=len(s)
dp=[[0]*n for _ in range(n)]
for i in range(n):#需要記憶
dp[i][i]=1
for j in range(i-1,-1,-1):
if s[i]==s[j]:
dp[i][j]=dp[i-1][j+1]+2
else:
dp[i][j]=max(dp[i][j+1],dp[i-1][j])
return dp[n-1][0]
關(guān)于另一個(gè)二維DP問題:兩個(gè)序列的最大公共子序列
給定兩個(gè)字符串 text1 和 text2草丧,返回這兩個(gè)字符串的最長(zhǎng) 公共子序列 的長(zhǎng)度狸臣。如果不存在 公共子序列 ,返回 0 昌执。
一個(gè)字符串的 子序列 是指這樣一個(gè)新的字符串:它是由原字符串在不改變字符的相對(duì)順序的情況下刪除某些字符(也可以不刪除任何字符)后組成的新字符串烛亦。
例如,"ace" 是 "abcde" 的子序列懂拾,但 "aec" 不是 "abcde" 的子序列煤禽。
兩個(gè)字符串的 公共子序列 是這兩個(gè)字符串所共同擁有的子序列。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-common-subsequence
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有岖赋。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán)檬果,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m,n=len(text1),len(text2)
dp=[[0]*(n+1) for _ in range(m+1)]
for i in range(1,m+1):
for j in range(1,n+1):
if text1[i-1]==text2[j-1]:
dp[i][j]=dp[i-1][j-1]+1
else:
try:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
except:
print(i,j)
return dp[m][n]
修改思路+一次過+極限內(nèi)存消耗以及時(shí)間復(fù)雜度
376. 擺動(dòng)序列
難度中等485 收藏 分享 切換為英文 接收動(dòng)態(tài) 反饋
如果連續(xù)數(shù)字之間的差嚴(yán)格地在正數(shù)和負(fù)數(shù)之間交替唐断,則數(shù)字序列稱為** 擺動(dòng)序列 选脊。**第一個(gè)差(如果存在的話)可能是正數(shù)或負(fù)數(shù)。僅有一個(gè)元素或者含兩個(gè)不等元素的序列也視作擺動(dòng)序列脸甘。
- 例如恳啥,
[1, 7, 4, 9, 2, 5]
是一個(gè) 擺動(dòng)序列 ,因?yàn)椴钪?(6, -3, 5, -7, 3)
是正負(fù)交替出現(xiàn)的丹诀。- 相反钝的,
[1, 4, 7, 2, 5]
和[1, 7, 4, 5, 5]
不是擺動(dòng)序列,第一個(gè)序列是因?yàn)樗那皟蓚€(gè)差值都是正數(shù)铆遭,第二個(gè)序列是因?yàn)樗淖詈笠粋€(gè)差值為零硝桩。
子序列 可以通過從原始序列中刪除一些(也可以不刪除)元素來獲得,剩下的元素保持其原始順序枚荣。
給你一個(gè)整數(shù)數(shù)組nums
碗脊,返回nums
中作為 擺動(dòng)序列 的 最長(zhǎng)子序列的長(zhǎng)度 。
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
dp_p,dp_n=1,1
for i in range(1,len(nums)):
if nums[i]-nums[i-1]>0:
dp_p=dp_n+1
elif nums[i]-nums[i-1]<0:
dp_n=dp_p+1
return max(dp_p,dp_n)
約瑟夫環(huán)問題的遞歸方程解法棍弄,當(dāng)只有一個(gè)字的時(shí)候返回位置0
否則設(shè)f(n,k)即n個(gè)字k個(gè)距離最后一個(gè)的答案
易知:
f(n,k)=(f(n-1,k)+k)%k
- 即得到轉(zhuǎn)移方程望薄,使用動(dòng)態(tài)規(guī)劃或者遞歸
class Solution:
def findTheWinner(self, n: int, k: int) -> int:
def transfer_equation(n,k):
return 0 if n==1 else (transfer_equation(n-1,k)+k)%n
return transfer_equation(n,k)+1
設(shè)計(jì)一個(gè)支持 push ,pop 呼畸,top 操作痕支,并能在常數(shù)時(shí)間內(nèi)檢索到最小元素的棧。
push(x) —— 將元素 x 推入棧中蛮原。
pop() —— 刪除棧頂?shù)脑亍?br> top() —— 獲取棧頂元素卧须。
getMin() —— 檢索棧中的最小元素。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/min-stack
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有儒陨。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán)花嘶,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.ds=[]
#使用輔助棻哪或者多用一個(gè)變量,不可以椭员,為了保持刪除同步
self.min_=[math.inf]#math.inf
def push(self, val: int) -> None:
self.ds.append(val)
self.min_.append(min(self.min_[-1],val))
def pop(self) -> None:
self.ds.pop()
self.min_.pop()
def top(self) -> int:
return self.ds[-1]
def getMin(self) -> int:
return self.min_[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
棧的用法精妙示意
給你一個(gè)由 '('、')' 和小寫字母組成的字符串 s笛园。
你需要從字符串中刪除最少數(shù)目的 '(' 或者 ')' (可以刪除任意位置的括號(hào))隘击,使得剩下的「括號(hào)字符串」有效。
請(qǐng)返回任意一個(gè)合法字符串研铆。
有效「括號(hào)字符串」應(yīng)當(dāng)符合以下 任意一條 要求:
空字符串或只包含小寫字母的字符串
可以被寫作 AB(A 連接 B)的字符串埋同,其中 A 和 B 都是有效「括號(hào)字符串」
可以被寫作 (A) 的字符串,其中 A 是一個(gè)有效的「括號(hào)字符串」
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/minimum-remove-to-make-valid-parentheses
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有棵红。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán)凶赁,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
class Solution:
def minRemoveToMakeValid(self, s: str) -> str:
set_remove_idx=set()
stack=[]
for i in range(len(s)):
if s[i] not in '()':
#print('hi')
continue
elif s[i]=='(':
stack.append(i)
elif not stack:
set_remove_idx.add(i)
else:
stack.pop()
set_remove_idx=set_remove_idx.union(set(stack))
#print(set_remove_idx)
ans=[]
for i,x in enumerate(s):
if i not in set_remove_idx:
ans.append(x)
return ''.join(ans)
'''
ans,left_bracket,right_bracket=[],0,0
for i in s:
if i=='(':
left_bracket+=1
ans.append(i)
elif i==')':
if right_bracket<left_bracket:
right_bracket+=1
ans.append(i)
else:
ans.append(i)
print(ans)
if left_bracket>right_bracket:
flag=[True]*len(ans)
for i in range(len(ans)):
if ans[i]=='(':
flag[i]=False
left_bracket-=1
if left_bracket==right_bracket:
break
ans=[ans[i] for i in range(len(ans)) if flag[i]]
return ''.join(ans)
'''