Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions 67 Week 08/id_556/LeetCode_127_556.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from typing import List


class Solution(object):
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
wordSet = set(wordList)
if endWord not in wordSet:
return 0

res = 1
n = len(beginWord)
current = set()
current.add(beginWord)

while current:
next_level = set()
if endWord in current:
return res
for cur in current:
if cur in wordSet:
wordSet.remove(cur)
for i in range(n):
for ch in range(97, 123):
tmp = cur[:i] + chr(ch) + cur[i + 1:]
if tmp in wordSet:
next_level.add(tmp)
res += 1
current = next_level
return 0

def ladderLength2(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
wordSet = set(wordList)
if endWord not in wordSet:
return 0

res = 1
wordDict = {}
for w in wordSet:
for i in range(len(w)):
new_w = w[:i] + "_" + w[i + 1:]
if new_w in wordDict:
wordDict[new_w].append(w)
else:
wordDict[new_w] = [w]

current = [beginWord]
next_level = []
while current:
for w in current:
if w == endWord:
return res
for i in range(len(w)):
new_w = w[:i] + "_" + w[i + 1:]
if new_w in wordDict:
for t in wordDict[new_w]:
if t not in next_level:
next_level.append(t)
del wordDict[new_w]
res += 1
current = next_level
next_level = []
return 0


if __name__ == "__main__":
solution = Solution()
print(solution.ladderLength2("hit", "cog", ["hot", "dot", "dog", "lot", "log", "cog"]))
64 changes: 64 additions & 0 deletions 64 Week 08/id_556/LeetCode_300_556.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from typing import List


# O(n^2)
def lengthOfLIS(nums: List[int]) -> int:
if not nums:
return 0
n = len(nums)
dp = [1] * n
for i in range(n):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
else:
continue
return max(dp)


# O(nlogn)
def lengthOfLIS2(nums):
if not nums:
return 0
n = len(nums)
if n < 2:
return n
# the min tail element in nums[:i+1]
tails = [nums[0]]
for i in range(1, n):
if nums[i] > tails[-1]:
tails.append(nums[i])
continue
# binary search to find the first tail > nums[i]
l, r = 0, len(tails) - 1
while l <= r:
m = l + ((r - l) >> 1)
if tails[m] < nums[i]:
l = m + 1
else:
r = m - 1
tails[l] = nums[i]
return len(tails)


def lengthOfLIS3(nums):
n = len(nums)
tails, res = [0] * n, 0
for num in nums:
i, j = 0, res
while i < j:
m = i + ((j - i) >> 1)
if tails[m] < num:
i = m + 1
else:
j = m
tails[i] = num
if j == res:
res += 1
return res


nums = [10, 9, 2, 5, 3, 7, 101, 18]
print(lengthOfLIS(nums))
print(lengthOfLIS2(nums))
print(lengthOfLIS3(nums))
48 changes: 48 additions & 0 deletions 48 Week 08/id_556/LeetCode_91_556.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# O(n) time/space
def numDecodings(s: str) -> int:
n = len(s)
if not s or s[0] == "0":
return 0
# dp[i] denotes the num of decoding for s[:i]
dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
for i in range(1, n):
if s[i] == "0":
if s[i - 1] == "1" or s[i - 1] == "2":
dp[i + 1] = dp[i - 1]
else:
return 0
else:
if s[i - 1] == "1" or (s[i - 1] == "2" and "1" <= s[i] <= "6"):
dp[i + 1] = dp[i] + dp[i - 1]
else:
dp[i + 1] = dp[i]
return dp[-1]


# O(n) time, O(1) space
def numDecodings2(s):
n = len(s)
if not s or s[0] == "0":
return 0
pre, cur = 1, 1
for i in range(1, n):
if s[i] == "0":
if s[i - 1] == "1" or s[i - 1] == "2":
cur = pre
else:
return 0
else:
if s[i - 1] == "1" or (s[i - 1] == "2" and "1" <= s[i] <= "6"):
tmp = cur
cur += pre
pre = tmp
else:
pre = cur
return cur


print(numDecodings("0"))
print(numDecodings2("226"))
print("226"[:2])
111 changes: 111 additions & 0 deletions 111 Week 08/id_556/NOTE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,114 @@



## Week8-19-动态规划

### 基础DP

大部分动态规划最简化的程序往往是动态递推,利用数学归纳法从之前的DP状态循环递推到最终的解。

1. DP状态的定义
2. 状态转移方程
3. 最终解位置

动态规划和递归或分治没有本质区别,共性为找重复子问题,关键看有无最优子结构,动规中途可以淘汰次优解

dp[i][j] = min(dp[i-1][j], dp[i-1][j] + A[i][j])


### 高级DP

1. 状态拥有更多的维度
2. 状态方程更为复杂
3. 本质考察逻辑思维和数学能力等内功

关键需要确定:

1. 维度(定义、压缩)
2. 状态转移方程
3. 初始化和边界条件

> 面试中状态定义比较重要,竞赛中递归方程会比较难

> 多练多思考,提升数学能力和抽象思维

#### 实例

##### 9. 股票买卖(121)

三维DP搞定股票买卖系列:


##### 10. Edit Distance(72)


BFS或双向BFS

字符串变换:(一般使用)二维数组定义DP状态

> 隐含条件:两个字符串的长度在变换中相互靠近;增加和删除是对等的操作

dp[i][j]: word1[0:i]与word[0:j]之间的编辑距离

w1[-1] == w[-1] ?

Y: dp[i][j] = dp[i-1, j-1]

N: min(dp[i-1, j-1] + 1, dp[i-1][j]+1, dp[i, j-1] + 1)

## 字符串算法

字符串可变语言:

C/C++, Ruby, PHP, Swift

字符串不可变语言:

Java, Python, C#, Javascript, Go

### DP+String

1. 编辑距离

dp[i][j] = dp[i-1][j-1] if w1[i]==w2[j] else min(dp[i-1][j-1], dp[i-1]][j], dp[i][j-1])+1

2. 最长公共子序列

dp[i][j] = dp[i-1][j-1] + 1 if s1[i] == s2[j] else max(dp[i-1][j], dp[i][j-1])

3. 最长公共子串

dp[j][j] = dp[i-1][j-1] + 1 if s1[i] == s2[j] else 0

4. 最长回文子序列

- 暴力枚举起点和终点,判断子串是否回文
- 枚举子串中心的一个字符(奇数长度)或中心两个(偶数长度),判断两边对称的字符长度
- DP:dp[i][j]=(dp[i+1][j-1] || (j-i)<2) if s[i]==s[j]

5. 正则表达式


6. 不同子序列

### 字符串匹配算法 (知道原理可以自己解释即可)

> 给定两个字符串,问其中一个字符串在另一个字符串中出现的起点

1. BrutalForce O(mn)

高级算法都是在暴力枚举的基础上进行优化

2. Rabin-Karp

用hash值先过滤掉不可能相同的子串起点;如果hash值相同,再逐个字符比较

但如果每次都是先取子串再调用系统hash进行计算的话,因hash函数会遍历子串,复杂度其实还是O(mn)

使用滑动窗口进行加速:O(1)来更新hash值,从而整体上平均达到O(n)的复杂度

3. KMP

找已匹配片段最大前缀和最大后缀的最长长度

insight:当知道在某个位置不匹配时,其实已经知道了前面能匹配的子串,可以利用已知匹配往后挪动
Morty Proxy This is a proxified and sanitized view of the page, visit original site.