diff --git a/Dynamic Program/Merlin/.keep b/Dynamic Program/Merlin/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Dynamic Program/Merlin/300_LongestIncreasingSubsequence.py b/Dynamic Program/Merlin/300_LongestIncreasingSubsequence.py new file mode 100644 index 0000000000000000000000000000000000000000..641e96943039301a6e305bfc5aab515ffed3c00c --- /dev/null +++ b/Dynamic Program/Merlin/300_LongestIncreasingSubsequence.py @@ -0,0 +1,43 @@ +from typing import List + + +""" + @author: Merlin 2019.06.02 + 300.Longest Increasing Subsequence + 思路: + 1.tails[i]的作用: 存储所有长度为i+1的递增子序列中,最小的序列尾数 + 以nums = [4, 5, 6, 3]为例子: + length = 1 : [4], [5], [6], [3] => tails[0] = 3 + length = 2 : [4, 5], [5, 6] => tails[1] = 5 + length = 3 : [4, 5, 6] => tails[2] = 6 + 以这种方式存储的tails是一个递增的数组,因为tails数组是有序的,所以可以用二分查找去找到要更新的元素 + 2.更新的情况有两种: + _1.当前遍历的元素大于tails数组里的所有元素,将该元素append进去并将数组容量加1(这点上Python是自动扩容,也可以像代码里手动创建具体大小的数组) + _2.如果当前遍历的元素x处于这种情况: tails[i-1] < x <= tails[i],就要更新tails[i], 把tails[i]的值改为x + 3.以上述方式维护的tails的数组长度就是最长上升子序列(代码里用size来替代数组大小) + time: O(nlogn) 遍历nums的每个元素为O(n),嵌套二分查找去更新元素为O(logn),所以时间复杂度为O(nlogn) + space: O(n) 算法里用创建时tails指定了和nums一样的大小,所以空间复杂度为O(n) + + https://leetcode.com/problems/longest-increasing-subsequence/discuss/74824/JavaPython-Binary-search-O(nlogn)-time-with-explanation +""" +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + tails = [0] * len(nums) + size = 0 + for x in nums: + i, j = 0, size + while i != j: + m = (i + j) // 2 + if tails[m] < x: + i = m + 1 + else: + j = m + tails[i] = x + size = max(i + 1, size) + return size + + +if __name__ == "__main__": + nums = [10,9,2,5,3,7,101,18] + test = Solution() + res = test.lengthOfLIS(nums) \ No newline at end of file diff --git a/Dynamic Program/Merlin/322_CoinChange.py b/Dynamic Program/Merlin/322_CoinChange.py new file mode 100644 index 0000000000000000000000000000000000000000..faab559c2cf0cdc4a39006dbc36c368fc0d96e93 --- /dev/null +++ b/Dynamic Program/Merlin/322_CoinChange.py @@ -0,0 +1,37 @@ +from typing import List + + +""" + @author: Merlin 2019.06.02 + 322.Coin Change + 思路: + 1.首先声明一个大小为amount+1的数组dp,用dp[i]存储"对于金额i最少用的硬币数" + _1.首先解释为什么大小是amount+1,比如amount是11块,dp要从0元开始存储到11块,所以数组的大小要amount+1 + _2.对于初始化数组dp的索引i=0的元素值为0,是因为0块要的硬币数为0,所以初始化为0 + 2.根据数组dp的定义,得到方程: dp[i] = min(dp[i-coin]+1) + _1.注意这里的dp[i-coin]的coin是针对每一种硬币(在代码里遍历了coins数组) + 3.返回值的解释 + _1.dp[amount]返回dp数组的最后一个元素,dp[amount] == float("inf")返回dp数组最后的元素是否为inf(无穷大) + _2.这里用一个例子解释[3, -1][True]返回的是索引为1的元素,[3, -1][False]返回索引为0的元素 + _3.所以dp[amount]不等于inf则返回dp[amount],等于inf则返回-1,意味着任何一种硬币组合能组成总金额 + time: O(amount*len(coins) 第一层循环遍历了amount次,第二层循环遍历了数组coins的每个元素 + space: O(amount) 算法用一个大小为amount+1的数组来存储值 + + https://leetcode.com/problems/coin-change/discuss/77372/Clean-dp-python-code +""" +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + dp = [0] + [float("inf")] * amount + + for i in range(1, amount + 1): + dp[i] = min([dp[i - c] if i - c >= 0 else float("inf") for c in coins]) + 1 + + return [dp[amount], -1][dp[amount] == float('inf')] + + + +if __name__ == "__main__": + coins = [1, 2, 5] + amount = 11 + test = Solution() + res = test.coinChange(coins, amount) \ No newline at end of file diff --git a/Recursion/Merlin/.keep b/Recursion/Merlin/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391