n = len(nums) # memo[i][j] 表示第i次决策,长度为j的lis的 最小的 末尾元素数值 # 每次决策都根据上次决策的所有可能转化,空间上可以类似背包优化为O(n) memo = [[-1] * (n+1) for _ in range(n)]
# 第一列全赋值为0,表示每次决策都不选任何数 for i in range(n): memo[i][0] = 0 # 第一次决策选数组中的第一个数 memo[0][1] = nums[0]
for i in range(1, n): for j in range(1, n+1): # case 1: 长度为j的lis在上次决策后存在,nums[i]比长度为j-1的lis末尾元素大 if memo[i-1][j] != -1 and nums[i] > memo[i-1][j-1]: memo[i][j] = min(nums[i], memo[i-1][j])
# case 2: 长度为j的lis在上次决策后存在,nums[i]比长度为j-1的lis末尾元素小/等 if memo[i-1][j] != -1 and nums[i] <= memo[i-1][j-1]: memo[i][j] = memo[i-1][j]
if memo[i-1][j] == -1: # case 3: 长度为j的lis不存在,nums[i]比长度为j-1的lis末尾元素大 if nums[i] > memo[i-1][j-1]: memo[i][j] = nums[i] # case 4: 长度为j的lis不存在,nums[i]比长度为j-1的lis末尾元素小/等 break
for i in range(n, -1, -1): if memo[-1][i] != -1: return i
def bag(items_info: List[int], capacity: int) -> int: """ 固定容量的背包,计算能装进背包的物品组合的最大重量 :param items_info: 每个物品的重量 :param capacity: 背包容量 :return: 最大装载重量 """ n = len(items_info) memo = [[-1]*(capacity+1) for i in range(n)] memo[0][0] = 1 if items_info[0] <= capacity: memo[0][items_info[0]] = 1
for i in range(1, n): for cur_weight in range(capacity+1): if memo[i-1][cur_weight] != -1: memo[i][cur_weight] = memo[i-1][cur_weight] # 不选 if cur_weight + items_info[i] <= capacity: # 选 memo[i][cur_weight + items_info[i]] = 1
for w in range(capacity, -1, -1): if memo[-1][w] != -1: return w
def bag_with_max_value(items_info: List[Tuple[int, int]], capacity: int) -> int: """ 固定容量的背包,计算能装进背包的物品组合的最大价值 :param items_info: 物品的重量和价值 :param capacity: 背包容量 :return: 最大装载价值 """ n = len(items_info) memo = [[-1]*(capacity+1) for i in range(n)] memo[0][0] = 0 if items_info[0][0] <= capacity: memo[0][items_info[0][0]] = items_info[0][1]
for i in range(1, n): for cur_weight in range(capacity+1): if memo[i-1][cur_weight] != -1: memo[i][cur_weight] = memo[i-1][cur_weight] if cur_weight + items_info[i][0] <= capacity: memo[i][cur_weight + items_info[i][0]] = max(memo[i][cur_weight + items_info[i][0]], memo[i-1][cur_weight] + items_info[i][1]) return max(memo[-1])
class TrieNode: def __init__(self, data: str): self._data = data self._children = [None] * 26 self._is_ending_char = False
class Trie: def __init__(self): self._root = TrieNode("/")
def insert(self, text: str) -> None: node = self._root for index, char in map(lambda x: (ord(x) - ord("a"), x), text): if not node._children[index]: node._children[index] = TrieNode(char) node = node._children[index] node._is_ending_char = True def find(self, pattern: str) -> bool: node = self._root for index in map(lambda x: ord(x) - ord("a"), pattern): if not node._children[index]: return False node = node._children[index] return node._is_ending_char
if __name__ == "__main__":
strs = ["how", "hi", "her", "hello", "so", "see"] trie = Trie() for s in strs: trie.insert(s) for s in strs: print(trie.find(s)) print(trie.find("swift"))
def kmp(s: int, pattern: int) -> int: m = len(pattern) partial_match_table = _get_partial_match_table(pattern) j = 0 for i in range(len(s)): while j >= 0 and s[i] != pattern[j]: j = partial_match_table[j] j += 1 if j == m: return i - m + 1 return -1
def _get_partial_match_table(pattern: int) -> List[int]: # Denote πᵏ(i) as π applied to i for k times, # i.e., π²(i) = π(π(i)). # Then we have the result: # π(i) = πᵏ(i-1) + 1, # where k is the smallest integer such that # pattern[πᵏ(i-1)+1] == pattern[i].
# The value of π means the maximum length # of proper prefix/suffix. # The index of π means the length of the prefix # considered for pattern. # For example, π[2] means we are considering the first 2 characters # of the pattern. # If π[2] == 1, it means for the prefix of the pattern, P[0]P[1], # it has a maximum length proper prefix of 1, which is also the # suffix of P[0]P[1]. # We also add a π[0] == -1 for easier handling of boundary # condition. m = len(pattern) π = [0] * (m + 1) π[0] = k = -1 # We use k here to represent πᵏ(i) for i in range(1, m + 1): while k >= 0 and pattern[k] != pattern[i - 1]: k = π[k] k += 1 π[i] = k return π