diff --git a/LeetCode/src/main/java/leetcode/editor/cn/DecodeWays.java b/LeetCode/src/main/java/leetcode/editor/cn/DecodeWays.java new file mode 100644 index 0000000..ee11974 --- /dev/null +++ b/LeetCode/src/main/java/leetcode/editor/cn/DecodeWays.java @@ -0,0 +1,156 @@ +//一条包含字母 A-Z 的消息通过以下映射进行了 编码 : +// +// +//'A' -> 1 +//'B' -> 2 +//... +//'Z' -> 26 +// +// +// 要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为: +// +// +// "AAJF" ,将消息分组为 (1 1 10 6) +// "KJF" ,将消息分组为 (11 10 6) +// +// +// 注意,消息不能分组为 (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6" 和 "06" 在映射中并不等价。 +// +// 给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。 +// +// 题目数据保证答案肯定是一个 32 位 的整数。 +// +// +// +// 示例 1: +// +// +//输入:s = "12" +//输出:2 +//解释:它可以解码为 "AB"(1 2)或者 "L"(12)。 +// +// +// 示例 2: +// +// +//输入:s = "226" +//输出:3 +//解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 +// +// +// 示例 3: +// +// +//输入:s = "0" +//输出:0 +//解释:没有字符映射到以 0 开头的数字。 +//含有 0 的有效映射是 'J' -> "10" 和 'T'-> "20" 。 +//由于没有字符,因此没有有效的方法对此进行解码,因为所有数字都需要映射。 +// +// +// 示例 4: +// +// +//输入:s = "06" +//输出:0 +//解释:"06" 不能映射到 "F" ,因为字符串含有前导 0("6" 和 "06" 在映射中并不等价)。 +// +// +// +// 提示: +// +// +// 1 <= s.length <= 100 +// s 只包含数字,并且可能包含前导零。 +// +// Related Topics 字符串 动态规划 +// 👍 696 👎 0 + +package leetcode.editor.cn; + +//91:解码方法 +public class DecodeWays { + public static void main(String[] args) { + //测试代码 + Solution solution = new DecodeWays().new Solution(); + //2 + System.out.println(solution.numDecodings("12")); + //3 + System.out.println(solution.numDecodings("226")); + //0 + System.out.println(solution.numDecodings("0")); + //0 + System.out.println(solution.numDecodings("06")); + //1 + System.out.println(solution.numDecodings("10")); + //1 + System.out.println(solution.numDecodings("2101")); + //2 + System.out.println(solution.numDecodings("2011")); + //3 + System.out.println(solution.numDecodings("1201234")); + //0 + System.out.println(solution.numDecodings("10011")); + } + + //力扣代码 + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + public int numDecodings(String s) { +// int length = s.length(); +// if (is) { +// for (int i = 0; i < length - 1; i++) { +// if (s.charAt(i) == '0' && s.charAt(i + 1) == '0') { +// return 0; +// } +// } +// is = false; +// } +// if (s.startsWith("0")) { +// return 0; +// } +// if (length == 1) { +// return 1; +// } +// if (length == 2) { +// if ((s.charAt(0) - '0') * 10 + (s.charAt(1) - '0') <= 26 && s.charAt(1) != '0') { +// return 2; +// } else { +// return 1; +// } +// } +// if (s.charAt(length - 1) == '0') { +// return numDecodings(s.substring(0, length - 2)); +// } +// if (s.charAt(length - 2) == '0') { +// return length > 3 ? numDecodings(s.substring(0, length - 3)) : 1; +// } +// if ((s.charAt(length - 2) - '0') * 10 + (s.charAt(length - 1) - '0') <= 26) { +// return numDecodings(s.substring(0, length - 2)) + numDecodings(s.substring(0, length - 1)); +// } else { +// return numDecodings(s.substring(0, length - 1)); +// } + if (s.startsWith("0")) { + return 0; + } + int length = s.length(); + int[] nums = new int[length + 1]; + nums[0] = 1; + for (int i = 1; i <= length; i++) { + if (i < length && s.charAt(i) == '0' && s.charAt(i - 1) == '0') { + return 0; + } + if (s.charAt(i - 1) != '0') { + nums[i] += nums[i - 1]; + } + if (i > 1 && s.charAt(i - 2) != '0' && ((s.charAt(i - 2) - '0') * 10 + (s.charAt(i - 1) - '0') <= 26)) { + nums[i] += nums[i - 2]; + } + } + return nums[length]; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/LeetCode/src/main/java/leetcode/editor/cn/DecodeWays.md b/LeetCode/src/main/java/leetcode/editor/cn/DecodeWays.md new file mode 100644 index 0000000..3a34632 --- /dev/null +++ b/LeetCode/src/main/java/leetcode/editor/cn/DecodeWays.md @@ -0,0 +1,66 @@ +

一条包含字母 A-Z 的消息通过以下映射进行了 编码

+ +
+'A' -> 1
+'B' -> 2
+...
+'Z' -> 26
+
+ +

解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:

+ + + +

注意,消息不能分组为  (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6""06" 在映射中并不等价。

+ +

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数

+ +

题目数据保证答案肯定是一个 32 位 的整数。

+ +

 

+ +

示例 1:

+ +
+输入:s = "12"
+输出:2
+解释:它可以解码为 "AB"(1 2)或者 "L"(12)。
+
+ +

示例 2:

+ +
+输入:s = "226"
+输出:3
+解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
+
+ +

示例 3:

+ +
+输入:s = "0"
+输出:0
+解释:没有字符映射到以 0 开头的数字。
+含有 0 的有效映射是 'J' -> "10" 和 'T'-> "20" 。
+由于没有字符,因此没有有效的方法对此进行解码,因为所有数字都需要映射。
+
+ +

示例 4:

+ +
+输入:s = "06"
+输出:0
+解释:"06" 不能映射到 "F" ,因为字符串含有前导 0("6""06" 在映射中并不等价)。
+ +

 

+ +

提示:

+ + +
Related Topics
  • 字符串
  • 动态规划
  • \n
  • 👍 696
  • 👎 0
  • \ No newline at end of file diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/jie-ma-fang-fa-by-leetcode-solution-p8np.md b/LeetCode/src/main/java/leetcode/editor/cn/doc/jie-ma-fang-fa-by-leetcode-solution-p8np.md new file mode 100644 index 0000000..f70c15c --- /dev/null +++ b/LeetCode/src/main/java/leetcode/editor/cn/doc/jie-ma-fang-fa-by-leetcode-solution-p8np.md @@ -0,0 +1,263 @@ +#### 方法一:动态规划 + +**思路与算法** + +对于给定的字符串 *s*,设它的长度为 *n*,其中的字符从左到右依次为 ![s\[1\],s\[2\],\cdots,s\[n\] ](./p__s_1_,_s_2_,_cdots,_s_n__.png) 。我们可以使用动态规划的方法计算出字符串 *s* 的解码方法数。 + +具体地,设 *f_i* 表示字符串 *s* 的前 *i* 个字符 *s[1..i]* 的解码方法数。在进行状态转移时,我们可以考虑最后一次解码使用了 *s* 中的哪些字符,那么会有下面的两种情况: + +- 第一种情况是我们使用了一个字符,即 *s[i]* 进行解码,那么只要 ![s\[i\]\neq0 ](./p__s_i__neq_0_.png) ,它就可以被解码成 ![\text{A}\sim\text{I} ](./p__text{A}_sim_text{I}_.png) 中的某个字母。由于剩余的前 *i-1* 个字符的解码方法数为 *f_{i-1}*,因此我们可以写出状态转移方程: + + ![f_i=f_{i-1},\quad其中~s\[i\]\neq0 ](./p_______f_i_=_f_{i-1},_quad_其中_~_s_i__neq_0______.png) + +- 第二种情况是我们使用了两个字符,即 *s[i-1]* 和 *s[i]* 进行编码。与第一种情况类似,*s[i-1]* 不能等于 *0*,并且 *s[i-1]* 和 *s[i]* 组成的整数必须小于等于 *26*,这样它们就可以被解码成 ![\text{J}\sim\text{Z} ](./p__text{J}_sim_text{Z}_.png) 中的某个字母。由于剩余的前 *i-2* 个字符的解码方法数为 *f_{i-2}*,因此我们可以写出状态转移方程: + + ![f_i=f_{i-2},\quad其中~s\[i-1\]\neq0~并且~10\cdots\[i-1\]+s\[i\]\leq26 ](./p_______f_i_=_f_{i-2},_quad_其中_~_s_i-1__neq_0_~并且~_10cdot_s_i-1_+s_i__leq_26______.png) + + 需要注意的是,只有当 *i>1* 时才能进行转移,否则 *s[i-1]* 不存在。 + +将上面的两种状态转移方程在对应的条件满足时进行累加,即可得到 *f_i* 的值。在动态规划完成后,最终的答案即为 *f_n*。 + +**细节** + +动态规划的边界条件为: + +* +f_0 = 1 +* + +即**空字符串可以有 *1* 种解码方法,解码出一个空字符串**。 + +同时,由于在大部分语言中,字符串的下标是从 *0* 而不是 *1* 开始的,因此在代码的编写过程中,我们需要将所有字符串的下标减去 *1*,与使用的语言保持一致。 + +**代码** + +```C++ [sol11-C++] +class Solution { +public: + int numDecodings(string s) { + int n = s.size(); + vector f(n + 1); + f[0] = 1; + for (int i = 1; i <= n; ++i) { + if (s[i - 1] != '0') { + f[i] += f[i - 1]; + } + if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) { + f[i] += f[i - 2]; + } + } + return f[n]; + } +}; +``` + +```Java [sol11-Java] +class Solution { + public int numDecodings(String s) { + int n = s.length(); + int[] f = new int[n + 1]; + f[0] = 1; + for (int i = 1; i <= n; ++i) { + if (s.charAt(i - 1) != '0') { + f[i] += f[i - 1]; + } + if (i > 1 && s.charAt(i - 2) != '0' && ((s.charAt(i - 2) - '0') * 10 + (s.charAt(i - 1) - '0') <= 26)) { + f[i] += f[i - 2]; + } + } + return f[n]; + } +} +``` + +```Python [sol11-Python3] +class Solution: + def numDecodings(self, s: str) -> int: + n = len(s) + f = [1] + [0] * n + for i in range(1, n + 1): + if s[i - 1] != '0': + f[i] += f[i - 1] + if i > 1 and s[i - 2] != '0' and int(s[i-2:i]) <= 26: + f[i] += f[i - 2] + return f[n] +``` + +```JavaScript [sol11-JavaScript] +var numDecodings = function(s) { + const n = s.length; + const f = new Array(n + 1).fill(0); + f[0] = 1; + for (let i = 1; i <= n; ++i) { + if (s[i - 1] !== '0') { + f[i] += f[i - 1]; + } + if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) { + f[i] += f[i - 2]; + } + } + return f[n]; +}; +``` + +```go [sol11-Golang] +func numDecodings(s string) int { + n := len(s) + f := make([]int, n+1) + f[0] = 1 + for i := 1; i <= n; i++ { + if s[i-1] != '0' { + f[i] += f[i-1] + } + if i > 1 && s[i-2] != '0' && ((s[i-2]-'0')*10+(s[i-1]-'0') <= 26) { + f[i] += f[i-2] + } + } + return f[n] +} +``` + +```C [sol11-C] +int numDecodings(char* s) { + int n = strlen(s); + int f[n + 1]; + memset(f, 0, sizeof(f)); + f[0] = 1; + for (int i = 1; i <= n; ++i) { + if (s[i - 1] != '0') { + f[i] += f[i - 1]; + } + if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) { + f[i] += f[i - 2]; + } + } + return f[n]; +} +``` + +注意到在状态转移方程中,*f_i* 的值仅与 *f_{i-1}* 和 *f_{i-2}* 有关,因此我们可以使用三个变量进行状态转移,省去数组的空间。 + +```C++ [sol12-C++] +class Solution { +public: + int numDecodings(string s) { + int n = s.size(); + // a = f[i-2], b = f[i-1], c = f[i] + int a = 0, b = 1, c; + for (int i = 1; i <= n; ++i) { + c = 0; + if (s[i - 1] != '0') { + c += b; + } + if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) { + c += a; + } + tie(a, b) = {b, c}; + } + return c; + } +}; +``` + +```Java [sol12-Java] +class Solution { + public int numDecodings(String s) { + int n = s.length(); + // a = f[i-2], b = f[i-1], c=f[i] + int a = 0, b = 1, c = 0; + for (int i = 1; i <= n; ++i) { + c = 0; + if (s.charAt(i - 1) != '0') { + c += b; + } + if (i > 1 && s.charAt(i - 2) != '0' && ((s.charAt(i - 2) - '0') * 10 + (s.charAt(i - 1) - '0') <= 26)) { + c += a; + } + a = b; + b = c; + } + return c; + } +} +``` + +```Python [sol12-Python3] +class Solution: + def numDecodings(self, s: str) -> int: + n = len(s) + # a = f[i-2], b = f[i-1], c = f[i] + a, b, c = 0, 1, 0 + for i in range(1, n + 1): + c = 0 + if s[i - 1] != '0': + c += b + if i > 1 and s[i - 2] != '0' and int(s[i-2:i]) <= 26: + c += a + a, b = b, c + return c +``` + +```JavaScript [sol12-JavaScript] +var numDecodings = function(s) { + const n = s.length; + // a = f[i-2], b = f[i-1], c = f[i] + let a = 0, b = 1, c = 0; + for (let i = 1; i <= n; ++i) { + c = 0; + if (s[i - 1] !== '0') { + c += b; + } + if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) { + c += a; + } + a = b; + b = c; + } + return c; +}; +``` + +```go [sol12-Golang] +func numDecodings(s string) int { + n := len(s) + // a = f[i-2], b = f[i-1], c = f[i] + a, b, c := 0, 1, 0 + for i := 1; i <= n; i++ { + c = 0 + if s[i-1] != '0' { + c += b + } + if i > 1 && s[i-2] != '0' && ((s[i-2]-'0')*10+(s[i-1]-'0') <= 26) { + c += a + } + a, b = b, c + } + return c +} +``` + +```C [sol12-C] +int numDecodings(char* s) { + int n = strlen(s); + // a = f[i-2], b = f[i-1], c = f[i] + int a = 0, b = 1, c; + for (int i = 1; i <= n; ++i) { + c = 0; + if (s[i - 1] != '0') { + c += b; + } + if (i > 1 && s[i - 2] != '0' && ((s[i - 2] - '0') * 10 + (s[i - 1] - '0') <= 26)) { + c += a; + } + a = b, b = c; + } + return c; +} +``` + +**复杂度分析** + +- 时间复杂度:*O(n)*,其中 *n* 是字符串 *s* 的长度。 + +- 空间复杂度:*O(n)* 或 *O(1)*。如果使用数组进行状态转移,空间复杂度为 *O(n)*;如果仅使用三个变量,空间复杂度为 *O(1)*。 \ No newline at end of file diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p_______f_i_=_f_{i-1},_quad_其中_~_s_i__neq_0______.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p_______f_i_=_f_{i-1},_quad_其中_~_s_i__neq_0______.png new file mode 100644 index 0000000..7c18fd9 Binary files /dev/null and b/LeetCode/src/main/java/leetcode/editor/cn/doc/p_______f_i_=_f_{i-1},_quad_其中_~_s_i__neq_0______.png differ diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p_______f_i_=_f_{i-2},_quad_其中_~_s_i-1__neq_0_~并且~_10cdot_s_i-1_+s_i__leq_26______.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p_______f_i_=_f_{i-2},_quad_其中_~_s_i-1__neq_0_~并且~_10cdot_s_i-1_+s_i__leq_26______.png new file mode 100644 index 0000000..f1390c0 Binary files /dev/null and b/LeetCode/src/main/java/leetcode/editor/cn/doc/p_______f_i_=_f_{i-2},_quad_其中_~_s_i-1__neq_0_~并且~_10cdot_s_i-1_+s_i__leq_26______.png differ diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__s_1_,_s_2_,_cdots,_s_n__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__s_1_,_s_2_,_cdots,_s_n__.png new file mode 100644 index 0000000..2e74fad Binary files /dev/null and b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__s_1_,_s_2_,_cdots,_s_n__.png differ diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__s_i__neq_0_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__s_i__neq_0_.png new file mode 100644 index 0000000..08b0854 Binary files /dev/null and b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__s_i__neq_0_.png differ diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{A}_sim_text{I}_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{A}_sim_text{I}_.png new file mode 100644 index 0000000..2dcff03 Binary files /dev/null and b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{A}_sim_text{I}_.png differ diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{J}_sim_text{Z}_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{J}_sim_text{Z}_.png new file mode 100644 index 0000000..3dfd07d Binary files /dev/null and b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{J}_sim_text{Z}_.png differ