正则表达式匹配
来源:力扣(LeetCode) 链接:leetcode.cn/problems/re…
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1:
输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
提示:
- 1 <= s.length <= 20
- 1 <= p.length <= 20
- s 只包含从 a-z 的小写字母。
- p 只包含从 a-z 的小写字母,以及字符 . 和 *。
- 保证每次出现字符 * 时,前面都匹配到有效的字符
代码
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
// 初始化第一行,处理"*"
for (int j = 1; j <= n; j++) {
if (p.charAt(j - 1) == '*') {
dp[0][j] = dp[0][j - 2];
}
}
// 动态规划
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
char sc = s.charAt(i - 1);
char pc = p.charAt(j - 1);
if (sc == pc || pc == '.') {
dp[i][j] = dp[i - 1][j - 1];
} else if (pc == '*') {
char prevPc = p.charAt(j - 2);
if (prevPc == sc || prevPc == '.') {
dp[i][j] = dp[i - 1][j] || dp[i][j - 2];
} else {
dp[i][j] = dp[i][j - 2];
}
}
}
}
return dp[m][n];
}
}
思路分析
-
定义一个二维布尔数组
dp,其中dp[i][j]表示字符串s的前i个字符与模式串p的前j个字符是否匹配。 -
初始化
dp[0][0]为true,表示空字符串与空模式串匹配。 -
初始化第一行,处理模式串以
*开头的情况。如果当前字符为*,则可以将该*和前面的字符一起移除,所以dp[0][j]的值与dp[0][j-2]的值相同。 -
使用动态规划递推公式填充剩余的
dp数组。 -
对于每个位置
(i, j),判断当前字符和模式串的当前字符是否匹配。如果匹配,则dp[i][j]的值与dp[i-1][j-1]的值相同。
整数转罗马数字
来源:力扣(LeetCode) 链接:leetcode.cn/problems/in…
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
- I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
- X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
- C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给你一个整数,将其转为罗马数字。
示例 1:
输入: num = 3
输出: "III"
示例 2:
输入: num = 4
输出: "IV"
示例 3:
输入: num = 9
输出: "IX"
示例 4:
输入: num = 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.
示例 5:
输入: num = 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
- 1 <= num <= 3999
代码
class Solution {
public String intToRoman(int num) {
int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] symbols = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
StringBuilder sb = new StringBuilder();
int index = 0;
while (num > 0) {
int count = num / values[index];
num %= values[index];
for (int i = 0; i < count; i++) {
sb.append(symbols[index]);
}
index++;
}
return sb.toString();
}
}
思路分析
-
定义一个数组
values和一个数组symbols,分别存储罗马数字的对应整数值和符号。 -
创建一个StringBuilder对象
sb,用于存储转换后的罗马数字。 -
初始化变量
index为0,用于表示当前处理的罗马数字的索引。 -
使用循环,当给定的整数
num大于0时,进行以下操作:- 计算
num除以values[index]的商,即表示当前罗马数字出现的次数。 - 将
num对values[index]取余,得到剩余的数值。 - 将当前罗马数字的符号根据出现次数添加到StringBuilder对象
sb中。 - 将
index加1,转换到下一个罗马数字。
- 计算
-
返回StringBuilder对象
sb转换为字符串的结果。