diff --git a/README.md b/README.md index 9a76f49..5c08aea 100644 --- a/README.md +++ b/README.md @@ -117,10 +117,12 @@ ### 贪心算法 1. [返回k次交换后最大的序列](https://github.com/dengshasha/algorithm-study/blob/master/greedy/largestPermutation.js) || [Geeks地址](https://www.geeksforgeeks.org/largest-permutation-k-swaps/) +2. ### 找不到分类 1. [实现一个最近最少使用的缓存结构](https://github.com/dengshasha/algorithm-study/blob/master/others/LRUCache.js) || [leetcode地址](https://leetcode.com/problems/lru-cache/) 2. [设计一个不包含重复数据,可以插入,删除,随机获取值的类](https://github.com/dengshasha/algorithm-study/blob/master/others/randomizedSet.js) || [leetcode地址](https://leetcode.com/problems/insert-delete-getrandom-o1/) 3. [设计一个将嵌套数组转换为扁平化数组的类](https://github.com/dengshasha/algorithm-study/blob/master/others/flattenNestedListIterator.js) || [leetcode地址](https://leetcode.com/problems/flatten-nested-list-iterator/) +4. [计算n!的末尾0的个数](https://github.com/dengshasha/algorithm-study/blob/master/others/factorialTrailingZeroes.js) || [leetcode地址](https://leetcode.com/problems/factorial-trailing-zeroes/) ### 分治法 1. [Merge k Sorted Lists](https://github.com/dengshasha/algorithm-study/blob/master/mergeKSortedLists.js) diff --git a/dynamicProgramming/climbStairs.js b/dynamicProgramming/climbStairs.js index 6f3920d..81a0eae 100644 --- a/dynamicProgramming/climbStairs.js +++ b/dynamicProgramming/climbStairs.js @@ -5,7 +5,24 @@ * @param {number} n * @return {number} * leetcode address: https://leetcode.com/problems/climbing-stairs/ + * 1. edge case: + * n = 1, there is only 1 way to climb to the top + * n = 2, there are 2 ways to climb to the top, climb 1 step each time as twice or climb 2 steps. + * 2. state transition equation: + * dp[i] = dp[i-2] + dp[i-1] (i >= 3) */ +var climbStairs_dfs = function(n) { + + let dp = [] + function recursive(k) { + + if(k < 0) return 0; + if(k === 0) return 1; + if(dp[k] !== undefined) return dp[k] + return dp[k] = recursive(k-1) + recursive(k-2) + } + return recursive(n) +} var climbStairs = function(n) { let dp = [0,1,2] if(n <= 2) return dp[n] @@ -15,4 +32,4 @@ var climbStairs = function(n) { return dp[n] }; -console.log(climbStairs(44)) \ No newline at end of file +console.log(climbStairs_dfs(4)) \ No newline at end of file diff --git a/dynamicProgramming/decodeWays.js b/dynamicProgramming/decodeWays.js new file mode 100644 index 0000000..d3fb643 --- /dev/null +++ b/dynamicProgramming/decodeWays.js @@ -0,0 +1,52 @@ +/** + * Created by dengxuelian on 2023/03/24 + * leetcode link: https://leetcode.com/problems/decode-ways/description/ + */ + +/** + * @param {string} s + * @return {number} + * 先不考虑 < 1和 >26是不合法的情况来推导通用公式 + * s=‘1‘, way[1] = 1 + * s=’12‘, 组合情况是(1,2) 和(12) way[2] = 2 + * s=’123‘, 组合情况是(1,2,3), (12,3) 和(1, 23) way[3] = 3 + * 观察这个规律可以得出way[i] = way[i-1] + way[i-2] + * 在这些组合情况中,需要排除一些不合法的组合情况 + * 情况一:s='0*'s是0开头的任意长度的数字,way=0 + * 情况二:当前位置的数字是0,且前一个位置也是0,或者是大于2,比如s='100', s='130', 则也不能组成字母,way=0 + * 情况三:当前位置的数字是0,且前一个位置的数字是1或者2,比如s='120', 那么当前位置必须要绑定前一个位置的数字组成字母,此时必须要牺牲前一个位置和当前位置的可能性, + * 那么i位置的组合方式=i-2位置的组合方式(重点理解!!!!因为i-1位置已经被固定使用了) + * 情况四:当前位置非0,前一个位置是0,则当前位置加入后不会增加组合的可能性,则组合方式不变,way[i] = way[i-1] + * 情况五:当前+前一个位置大于26,则和情况四一样,way[i] = way[i-1] + */ +var numDecodings = function(s) { + // 0开头的字符是不合法的情况 + if(s[0] === '0') return 0; + let dp = [] + // 初始状态,排除了0开头以后,如果s.length=1, 则仅有一个字母。 + dp[0] = 1, dp[1] = 1 + + for(let i = 1; i < s.length; i++) { + // 当前字符为0,有两种情况导致整个字符串无法形成合法的字母组合 + // 1. 前一个数字>2 + // 2. 前一个数字是0 + if(s[i] === '0' && (s[i-1] > 2 || s[i-1] === '0')) { + return 0; + } + if(s[i] === '0') { + //当前字符为0,但是可以和前一个数字组成一个字母,意味着前一个数字必须和当前数字一起使用,则前一个数字位置的 + //可能性不需要考虑,此时当前位置的组成方式=前2个位置的组成方式 + dp[i+1] = dp[i-1] + } else if(s[i-1] === '0' || s[i-1]+s[i] > 26) { + //前一个字符为0,当前数字加入后不会增加可能性,所以等于前一个位置的组成方式 + //当前+前一个数字超出了最大值后,当前数字加入后也不会增加可能性 + dp[i+1] = dp[i] + } else { + //通用方程 + dp[i+1] = dp[i] + dp[i-1] + } + } + return dp[s.length] +}; + +console.log(numDecodings('27')) \ No newline at end of file diff --git a/index.html b/index.html index cfea61f..1fdcc73 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,6 @@