默认格式:
class Solution {
public boolean isMatch(String s, String p) {
}
}
解题思路:
这道题看起来不难,看完题目之后有的想法就是通过逻辑来循环判断是否符合,比如:
s=mississippi
p = mis*is*p*.
字符的话直接比较,相等继续,不相等的话直接返回false
然后是一个*,*的话长度不能确定,所以我们要先确定他的长度,如何确定他的长度,我们这里使用贪心算法,我直接找*后面的那个字符,在原字符串中查找在连续的该元素后是否存在字符i,如果存在,那么继续判断,如果不存在,那么返回false
后面这个*也是这么做判断,他找到自己的后一个元素是p而在上面连续寻找s之后得到的是i,不匹配,所以是错误的。
.的话就认为是一个通配符,匹配所有的字符。
这里有一个坑的点,就是在*后面继续跟原来的字符,比如这几种情况
坑1:
abcd*d
这种情况还是比较容易鉴别的,只需要判断前后加起来的长度是否超过上面的s中的长度就可以了,如果超过了,说明不匹配,如果没超过,那就和上面一样继续。
坑2:
abc.*d
如果出现了.*怎么办,貌似唯一的办法就是判断这个.*后面的字符串是否能和原字符串的末尾的一部分完全匹配。
最终的想法:
从p中循环读出字符,根据读出字符的不同进行不同的处理。当出现多种可能的时候,对字符串的所有可能进行递归处理。因为我找不到能够对可能出现的情况进行筛选的办法,任何试图对可能性进行删减的操作都有可能漏掉某一种正确可能性。
ps:
上面存在一个理解上的错误,a*b可以匹配ab,aab或者b,因为这个*表示的是前面那个字符的个数,可以是0个。
代码部分:
没能做出来,因为实在没能想到有什么能判别,.*.,这个格式方式,暴力破解也破解不了
没做出来,实在不行了,由于一开始的构思没构思好,做到后面整个算法过于复杂没办法修改,改一个地方就有另一个位置出错,最后实在是没有精力去改了,代码也写了很厚很厚,今天答案也不看了,太累了。
public boolean isMatch(String s, String p) {
//字符串变成数组便于操作,可以使用getchar但是那个更消耗时间
char[] charP=p.toCharArray();
char[] charS=s.toCharArray();
//indexP是当前处理P的字符的位置
int indexP=0;
//indexS是当前处理原数组S的位置
int indexS=0;
//主要循环
for (;indexP<p.length()&&indexS<s.length();indexP++){
//如果是点,表示是所有字符,此时会产生几种可能呢?
if (charP[indexP]=='.'){
//如果不是*,处理就很简单,直接让indexS++就可以了
if (indexP+1<charP.length&&charP[indexP+1]!='*')
{
indexS++;
}
//如果是*,那么就麻烦了,它可能代表了0-n个字符(n是charS剩余的长度-p的理论最小剩余长度),而且和*后面的一个字符一样
else if (indexP+1<charP.length)
{
//.*也分为两种,.*.和.*a这两种
//如果是.*a这种格式的
if(indexP+2<charP.length&&charP[indexP]!='.'){
//在原字符串中寻找和.*后的那个字符相同的字符
for(int i=indexS;i<s.length();i++){
//如果相同的,那么递归一下判断是否完全一致
if (charS[i]==charP[indexP+2]){
String s1=new String(charS,i,s.length()-i);
String p1=new String(charP,indexP+2,p.length()-indexP-2);
//如果通过了,返回true
if(isMatch(s1,p1)){
return true;
}
}
}
//如果所有可能都判断完了,那么就不可能相等了
return false;
}
else if(indexP+2<charP.length){
//如果是.,那么就不用判断是否相等了,因为.代表了所有的字符
for(int i=indexS;i<s.length();i++){
String s1=new String(charS,i,s.length()-i);
String p1=new String(charP,indexP+2,p.length()-indexP-2);
//如果通过了,返回true
if(isMatch(s1,p1)){
return true;
}
}
//如果所有可能都判断完了,那么就不可能相等了
return false;
}
//如果长度不够,说明以.*结尾,直接输出true
else
return true;
}
else
indexS++;
}
//如果是*,那么是和前一个字符相关的,先获取前一个字符
else if (charP[indexP]=='*'){
//可以直接获取上一个的值,因为规定了不会在首位出现*,而且经过我的处理,前面一个不会是.,所以可以直接认为是一个字符
char previous=charP[indexP-1];
//只要是a*这种格式的,原式中每一个a就会产生一个递归判断
for (;((indexS-1)<s.length()&&charS[indexS-1]==previous);indexS++){
String s1=new String(charS,indexS-1,s.length()-indexS+1);
String p1=new String(charP,indexP+1,p.length()-indexP-1);
if(isMatch(s1,p1)){
return true;
}
}
String s1=new String(charS,indexS-1,s.length()-indexS+1);
String p1=new String(charP,indexP+1,p.length()-indexP-1);
if(isMatch(s1,p1)){
return true;
}
return false;
}
else {
//单纯字符的话直接比较字符是否相等
if (charP[indexP]==charS[indexS])
{
indexS++;
}
//如果不相等但是下一个字符是*,则表示*=0不存在该字符的,此时p的下标需要移动两格
else if(indexP+1<charP.length&&charP[indexP+1]=='*'){
indexP++;
}
else
//不相等返回false
return false;
}
}
//循环结束没有问题,判断普通字符串是否到达末尾,这是必要条件
if (indexS==s.length()){
//两个都到达末尾,表示真正的结束
if (indexP==p.length())
return true;
//如果正则的没到到末尾,判断一下剩下的部分是否实际长度为0,如果为0,也是到达了末尾
else {
int num = 0;
for (int i=indexP; i < p.length(); i++) {
//如果有一个*,则最小长度-1,否则+1
if (charP[i] == '*')
num--;
else
num++;
}
if (num>0)
return false;
if (charP[p.length()-1]=='*'&&num <= 0) {
//查看p的剩余长度是否小于等于0
return true;
}
else if (charP[p.length()-1]==charP[indexP-1]&&num <= 0){
return true;
}
else
return false;
}
}
return false;
}
感觉写出来也是很慢的样子,直接贴官方答案吧
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] f = new boolean[m + 1][n + 1];
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '*') {
f[i][j] = f[i][j - 2];
if (matches(s, p, i, j - 1)) {
f[i][j] = f[i][j] || f[i - 1][j];
}
}
else {
if (matches(s, p, i, j)) {
f[i][j] = f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
public boolean matches(String s, String p, int i, int j) {
if (i == 0) {
return false;
}
if (p.charAt(j - 1) == '.') {
return true;
}
return s.charAt(i - 1) == p.charAt(j - 1);
}
}