剑指 Offer 19. 正则表达式匹配
从暴力递归:
到动态规划:
递归代码:
class Solution {
public boolean isMatch(String s, String p) {
return match(s,p,0,0,s.length(),p.length());
}
private boolean match(String s, String p,int i,int j,int sl,int pl){
//判断结束
if(i==sl&&j==pl){//同时结束
return true;
}else if(j==pl){//正则串结束
return false;
}else if(i==sl){//主串结束正则还有
//正则剩奇数个一定不匹配
if((pl-j)%2!=0)return false;
//剩下的必须隔一个字符有一个*才可匹配
int t=j+1;
while(t<pl){
if(p.charAt(t)!='*'){
return false;
}
t+=2;
}
return true;
}
char tmp='A';
if(j+1<pl){
tmp=p.charAt(j+1);//如果p.charAt(j+1)=='*' 需要考虑匹配多少次
}
if(tmp!='*'){
if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='.'){
return match(s,p,i+1,j+1,sl,pl);//继续匹配
}else{
return false;
}
}else{
if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='.'){
return match(s,p,i+1,j,sl,pl)||match(s,p,i,j+2,sl,pl);//匹配和不匹配两种情况
}else{
return match(s,p,i,j+2,sl,pl);//只能不匹配
}
}
}
}
动态规划:这里通过一个二维数组dp[i][j]来记录s的前i个字符和p的前j个字符是否匹配
当遇到*的时候我们的n次匹配就直接找前面的就行了。
这里对着我们暴力递归的代码优化即可:
可得状态转移方程:
初始化dp数组:
两个空串匹配为true,所以dp[0][0]=true;
正则串q为空,s不为空为false,所以dp[i][0]=false;
其余不动
动态规划代码:
class Solution {
public boolean isMatch(String s, String p) {
return match2(s,p);
}
//动态规划
private boolean match2(String s, String p){
boolean dp[][]=new boolean[s.length()+1][p.length()+1];
dp[0][0]=true;
for(int i=0;i<=s.length();i++){
for(int j=1;j<=p.length();j++){//dp[i][0]全false 直接从1开始即可
if(p.charAt(j-1)=='*'){
if(i>=1&&j>=2&&(s.charAt(i-1)==p.charAt(j-2)||p.charAt(j-2)=='.')){
dp[i][j]=dp[i-1][j];
}
if(j>=2){
dp[i][j]|=dp[i][j-2];
}
}else{
if(i>=1&&(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='.')){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=false;
}
}
}
}
return dp[s.length()][p.length()];
}
}
剑指 Offer 20. 表示数值的字符串
代码实现
class Solution {
public boolean isNumber(String s) {
s=s.trim();
System.out.println(s);
boolean isNum=false;//是否出现过数字
boolean isPoint=false;//是否出现过小数点
boolean isE=false;//是否出现过E,e
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
//代表出现过数字了
if(Character.isDigit(c)){
isNum=true;
}else if(c=='+'||c=='-'){//出现了+-号,判断是不是在第一位或在e后面
if(i!=0&&(s.charAt(i-1)!='E'&&s.charAt(i-1)!='e')){
return false;
}
}else if(c=='.'){//出现了. 判断有没有出现过e 或 在e前面且出现过数字
if(isE||isPoint){//1 e不能在.前面 2 .只能出现一次
return false;
}
isPoint=true;
isNum|=isNum;//这时isNum用于判断.前面后面任一位置有没有出现数字,只要有就是true
}else if(c=='e'||c=='E'){//出现了e,找到e出现的所有错误情况
//1 e出现了不止一次 2 e和.同时出现 非2.e .2e 2.2e 的形式 也就是必须前面要有数字 3 e前面必须要有数字 可以发现2 3两点可以结和成 鹅、前面必须有数字
if(isE||!isNum){
return false;
}
isE=true;
isNum=false;//这时isNum用于判断e后面有没有出现数字
}else{
return false;
}
}
return isNum;
}
}
剑指 Offer 29. 顺时针打印矩阵
代码实现:
class Solution {
public int[] spiralOrder(int[][] matrix) {
int m=matrix.length;
//特殊情况处理
if(m==0)return new int[0];
int n=matrix[0].length;
if(n==0)return new int[0];
int[] nums=new int[m*n];
boolean[][] isPrint=new boolean[m][n];
int t=0;//每打印一次t++一次
int i=0,j=0;
while(t<m*n){
//右
while(j<n){
if(isPrint[i][j]!=true){
nums[t++]=matrix[i][j];
isPrint[i][j++]=true;
}else{
break;
}
}
j--;
i++;
//下
while(i<m){
if(isPrint[i][j]!=true){
nums[t++]=matrix[i][j];
isPrint[i++][j]=true;
}else{
break;
}
}
i--;
j--;
//左
while(j>=0){
if(isPrint[i][j]!=true){
nums[t++]=matrix[i][j];
isPrint[i][j--]=true;
}else{
break;
}
}
j++;
i--;
//上
while(i>=0){
if(isPrint[i][j]!=true){
nums[t++]=matrix[i][j];
isPrint[i--][j]=true;
}else{
break;
}
}
i++;
j++;
}
return nums;
}
}
共勉