Leetcode剑指offer(二)

11、机器人的运动范围(13、Medium)

1)题目要求

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入:m = 2, n = 3, k = 1
输出:3
示例 2:

输入:m = 3, n = 1, k = 0
输出:1
提示:

1 <= n,m <= 100
0 <= k <= 20

2)我的解法

1、DFS

class Solution {
    private boolean[][] visited;
    public int compute(int i){
        if(i==100)return 1;
        return i/10+i%10;
    }

    public int dfs(int i,int j,int m,int n,int k){
        if(i<0||i>=m||j<0||j>=n||compute(i)+compute(j)>k||visited[i][j])return 0;

        visited[i][j]=true;

        int l=dfs(i,j-1,m,n,k);
        int r=dfs(i,j+1,m,n,k);
        int u=dfs(i-1,j,m,n,k);
        int d=dfs(i+1,j,m,n,k);
        return l+r+u+d+1;
    }
    public int movingCount(int m, int n, int k) {
        visited=new boolean[m][n];
        return dfs(0,0,m,n,k);
    }
}

2、BFS

class Solution {
    private boolean[][] visited;
    public int compute(int i){
        if(i==100)return 1;
        return i/10+i%10;
    }

    public int movingCount(int m, int n, int k) {
        visited=new boolean[m][n];
        Queue<int[]> q=new LinkedList<>();
        q.offer(new int[2]);
        visited[0][0]=true;
        int result=1;

        int x=0,y=0;

        int[][] tool=new int[][]{{0,-1},{0,1},{-1,0},{1,0}};

        while(!q.isEmpty()){
            int[] front=q.poll();
            for(int i=0;i<4;i++){
                x=front[0]+tool[i][0];y=front[1]+tool[i][1];
                if(x<0||x>=m||y<0||y>=n||compute(x)+compute(y)>k||visited[x][y])continue;
                visited[x][y]=true;
                q.offer(new int[]{x,y});
                result++;
            }
            
        }
        return result;
    }
}

3)其他解法

在这里插入图片描述

1、DFS

class Solution {
    int m, n, k;
    boolean[][] visited;
    public int movingCount(int m, int n, int k) {
        this.m = m; this.n = n; this.k = k;
        this.visited = new boolean[m][n];
        return dfs(0, 0, 0, 0);
    }
    public int dfs(int i, int j, int si, int sj) {
        if(i >= m || j >= n || k < si + sj || visited[i][j]) return 0;
        visited[i][j] = true;
        return 1 + dfs(i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj) + dfs(i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8);
    }
}

2、BFS

class Solution {
    public int movingCount(int m, int n, int k) {
        boolean[][] visited = new boolean[m][n];
        int res = 0;
        Queue<int[]> queue= new LinkedList<int[]>();
        queue.add(new int[] { 0, 0, 0, 0 });
        while(queue.size() > 0) {
            int[] x = queue.poll();
            int i = x[0], j = x[1], si = x[2], sj = x[3];
            if(i >= m || j >= n || k < si + sj || visited[i][j]) continue;
            visited[i][j] = true;
            res ++;
            queue.add(new int[] { i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj });
            queue.add(new int[] { i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8 });
        }
        return res;
    }
}

作者:jyd
链接: link
来源:力扣(LeetCode)

4)自己的优化代码

class Solution {
    private boolean[][] visited;

    public int movingCount(int m, int n, int k) {
        visited=new boolean[m][n];
        Queue<int[]> q=new LinkedList<>();
        q.offer(new int[4]);//后两位为数位和,只算增量
        visited[0][0]=true;
        int result=1;

        int x=0,y=0;

        int _x=0,_y=0;//数位和

        int[][] tool=new int[][]{{0,1},{1,0}};//向右和向下两个方向就够了

        while(!q.isEmpty()){
            int[] front=q.poll();

            for(int i=0;i<2;i++){
                x=front[0]+tool[i][0];y=front[1]+tool[i][1];
                _x=(tool[i][0]==1)?((front[0]%10==9)?front[2]-8:front[2]+1):front[2];
                _y=(tool[i][1]==1)?((front[1]%10==9)?front[3]-8:front[3]+1):front[3];
                if(x<0||x>=m||y<0||y>=n||_x+_y>k||visited[x][y])continue;
                visited[x][y]=true;
                q.offer(new int[]{x,y,_x,_y});
                result++;
            }
            
        }
        return result;
    }
}

5)学到的东西

DFS、BFS

剪枝:仅向右和向下即可
只算增量

12、剪绳子(14-1、Meium)

1)题目要求

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:

2 <= n <= 58

2)我的解法

找规律+动态规划

class Solution {
    public int cuttingRope(int n) {
        int[] dp=new int[n+1];
        for(int i=2;i<=n;i++){
            if(i==2||i==3)dp[i]=i-1;
            else dp[i]=Math.max(Math.max(2*dp[i-2],3*dp[i-3]),Math.max(2*(i-2),3*(i-3)));
        }
        return dp[n];
    }
}

3)其他解法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        int a = n / 3, b = n % 3;
        if(b == 0) return (int)Math.pow(3, a);
        if(b == 1) return (int)Math.pow(3, a - 1) * 4;
        return (int)Math.pow(3, a) * 2;
    }
}

在这里插入图片描述

作者:jyd
链接:link
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2、

在这里插入图片描述

public int cuttingRope(int n) {
    int[] dp = new int[n + 1];
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        for (int j = 1; j < i; j++) {
            dp[i] = Math.max(dp[i], (Math.max(j, dp[j])) * (Math.max(i - j, dp[i - j])));
        }
    }
    return dp[n];
}

在这里插入图片描述

作者:sdwwld
链接:link
来源:力扣(LeetCode)

4)自己的优化代码

1、

class Solution {
    public int cuttingRope(int n) {
        int[] dp=new int[n+1];
        for(int i=2;i<=n;i++){
            for(int j=0;j<=i;j++){
                dp[i]=Math.max(dp[i],Math.max(Math.max(j*dp[i-j],(i-j)*dp[j]),Math.max(j*(i-j),dp[i-j]*dp[j])));
            }
        }
        return dp[n];
    }
}

2、

class Solution {
    public int cuttingRope(int n) {
        if(n==2||n==3)return n-1;
        else if(n%3==0)return (int)Math.pow(3,n/3);
        else if(n%3==2)return (int)Math.pow(3,n/3)*2;
        else return (int)Math.pow(3,n/3-1)*4;
    }
}

5)学到的东西

动态规划、找规律

13、剪绳子 II(14-2、Medium)

1)题目要求

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

提示:

2 <= n <= 1000

2)我的解法

class Solution {
    public int Mypow(int mi){
        double result=1;
        while(mi>0){
            result=(result*3)%1000000007;
            mi--;
        }
        return (int)result;
    }
    public int cuttingRope(int n) {//double 转 int 精度丢失,分成多个
        if(n==2||n==3)return n-1;
        double result=0;
        if(n%3==0)result=Mypow(n/3);
        else if(n%3==2)result=Mypow(n/3)*2;
        else result=((Mypow(n/3-1)*2)%1000000007)*2;
        return (int)(result%1000000007);
    }
}

3)其他解法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        int b = n % 3, p = 1000000007;
        long rem = 1, x = 3;
        for(int a = n / 3 - 1; a > 0; a /= 2) {
            if(a % 2 == 1) rem = (rem * x) % p;
            x = (x * x) % p;
        }
        if(b == 0) return (int)(rem * 3 % p);
        if(b == 1) return (int)(rem * 4 % p);
        return (int)(rem * 6 % p);
    }
}

作者:jyd
链接: link
来源:力扣(LeetCode)

2、

在这里插入图片描述

class Solution {
    public int cuttingRope(int n) {
        if(n == 2) {
            return 1;
        }
        if(n == 3){
            return 2;
        }
        int mod = (int)1e9 + 7;
        long res = 1;
        while(n > 4) {
            res *= 3;
            res %= mod;
            n -= 3;
        }
        return (int)(res * n % mod);
    }
}

3、快速幂

class Solution {

    private int mod = (int)1e9 + 7;

    public int cuttingRope(int n) {
        if(n < 4){
            return n-1;
        }
        int cnt3 = n / 3;
        if(n % 3 == 0){
            return (int)pow(3, cnt3);
        } else if(n % 3 == 1){
            return (int)((pow(3, cnt3 - 1) * 4) % mod);
        } else {
            return (int)((pow(3, cnt3) * 2) % mod);
        }
    }

    private long pow(long base, int num){
        long res = 1;
        while(num > 0){
            if((num & 1) == 1){
                res *= base;
                res %= mod;
            }
            base *= base;
            base %= mod;
            num >>= 1;
        }
        return res;
    }
}

作者:HenryLee4
链接:link
来源:力扣(LeetCode)

4)自己的优化代码

1、

class Solution {

    public int cuttingRope(int n) {//double 转 int 精度丢失,分成多个
        if(n==2||n==3)return n-1;
        double result=1;

        while(n>4){
            result=(result*3)%1000000007;
            n=n-3;
        }

        return (int)((result*n)%1000000007);
    }
}

2、

class Solution {
    public long Mypow(int mi){
        long result=1;//两个必须为long
        long base=3;
        while(mi>0){
            if(mi%2==1){
                result*=base;
                result%=1000000007;
            }
            base=(base*base)%1000000007;
            mi/=2;
        }
        return result;
    }
    public int cuttingRope(int n) {//double 转 int 精度丢失,分成多个
        if(n==2||n==3)return n-1;
        long result=0;
        if(n%3==0)result=Mypow(n/3);
        else if(n%3==2)result=Mypow(n/3)*2;
        else result=Mypow(n/3-1)*4;
        return (int)(result%1000000007);
    }
}

5)学到的东西

贪心法

大数求余:循环求余;二分求余

14、二进制中1的个数(15、Easy)

1)题目要求

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:

输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。

2)我的解法

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int result=0,temp=0;
        while(n!=0){
            temp=n>>>1;
            temp=temp<<1;
            if((n-temp)==1)result++;

            n=n>>>1;//必须用无符号右移
        }
        return result;
    }
}

3)其他解法

1、 Java中的Integer.bitCount(n);

2、

在这里插入图片描述

public class Solution {
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res += n & 1;
            n >>>= 1;
        }
        return res;
    }
}

3、

在这里插入图片描述

public class Solution {
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res++;
            n &= n - 1;
        }
        return res;
    }
}


作者:jyd
链接:link
来源:力扣(LeetCode)

4)自己的优化代码

1、

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int result=0,temp=0;
        while(n!=0){
            result++;
            n=n&(n-1);
        }
        return result;
    }
}

2、

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int result=0,temp=0;
        while(n!=0){
            result+=n&1;
            n=n>>>1;
        }
        return result;
    }
}

5)学到的东西

位运算

n&1,检测最低位是否为1

在这里插入图片描述

在这里插入图片描述

15、 数值的整数次方(16、Medium)

1)题目要求

实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。

示例 1:

输入: 2.00000, 10
输出: 1024.00000
示例 2:

输入: 2.10000, 3
输出: 9.26100
示例 3:

输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25

说明:

-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。

2)我的解法

class Solution {
    public double myPow(double x, int n) {
        double result=1;
        while(n!=0){
            if(n%2!=0){
                if(n>0)result*=x;
                else result/=x;
            }
            x*=x;
            n/=2;
        }
        return result;
    }
}

3)其他解法

class Solution {
    public double myPow(double x, int n) {
        if(x == 0) return 0;
        long b = n;
        double res = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) res *= x;
            x *= x;
            b >>= 1;
        }
        return res;
    }
}

作者:jyd
链接:link
来源:力扣(LeetCode)

4)自己的优化代码

class Solution {
    public double myPow(double x, int n) {
        double result=1;
        while(n!=0){
            if((n&1)==1){
                if(n>0)result*=x;
                else result/=x;
            }
            x*=x;
            n/=2;
        }
        return result;
    }
}

5)学到的东西

位运算

if((n&1)==1)等价于if(n%2!=0)

16、打印从1到最大的n位数(17、Easy)

1)题目要求

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

示例 1:

输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]

说明:

用返回一个整数列表来代替打印
n 为正整数

2)我的解法

1、不考虑大数:

class Solution {
    public int[] printNumbers(int n) {
        int[] result=new int[(int)(Math.pow(10,n))-1];
        for(int i=0;i<result.length;i++)result[i]=i+1;
        return result;
    }
}

2、考虑大数

class Solution {
    public String[] printNumbers(int n) {
    	char[] r=new char[n];
    	String[] result=new String[(int)Math.pow(10, n)-1];
    	for(int i=0;i<result.length;i++){
    		int j=0;
    		int temp=i;
    		while(true){
    			j++;
    			if(j==1)r[n-j]=(char)(temp%10+'1');
    			else r[n-j]=(char)(temp%10+'0');
    			
    			if(j>1&&r[n-j+1]==':'){
    				r[n-j+1]='0';
    				r[n-j]=(char)(temp%10+'1');
    			}
    			
    			temp=temp/10;
    			
    			if(temp==0)break;
    		}
    		if(r[n-j]==':'){
				r[n-j]='0';
				j++;
				r[n-j]=(char)(temp%10+'1');
			}
    		result[i]=new String(r,n-j,j);//第三个参数为长度
    	}
        return result;
    }
}

3)其他解法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

class Solution {
    StringBuilder res;
    int nine = 0, count = 0, start, n;
    char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    public String printNumbers(int n) {
        this.n = n;
        res = new StringBuilder();
        num = new char[n];
        start = n - 1;
        dfs(0);
        res.deleteCharAt(res.length() - 1);
        return res.toString();
    }
    void dfs(int x) {
        if(x == n) {
            String s = String.valueOf(num).substring(start);
            if(!s.equals("0")) res.append(s + ",");
            if(n - start == nine) start--;
            return;
        }
        for(char i : loop) {
            if(i == '9') nine++;
            num[x] = i;
            dfs(x + 1);
        }
        nine--;
    }
}

本题要求输出 int 类型数组。为 运行通过 ,可在添加数字字符串 ss 前,将其转化为 int 类型。代码如下所示:

class Solution {
    int[] res;
    int nine = 0, count = 0, start, n;
    char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    public int[] printNumbers(int n) {
        this.n = n;
        res = new int[(int)Math.pow(10, n) - 1];
        num = new char[n];
        start = n - 1;
        dfs(0);
        return res;
    }
    void dfs(int x) {
        if(x == n) {
            String s = String.valueOf(num).substring(start);
            if(!s.equals("0")) res[count++] = Integer.parseInt(s);
            if(n - start == nine) start--;
            return;
        }
        for(char i : loop) {
            if(i == '9') nine++;
            num[x] = i;
            dfs(x + 1);
        }
        nine--;
    }
}

作者:jyd
链接:link
来源:力扣(LeetCode)

4)自己的优化代码


class Solution {
    public int[] printNumbers(int n) {
    	char[] r=new char[n];
    	int[] result=new int[(int)Math.pow(10, n)-1];
    	for(int i=0;i<result.length;i++){
    		int j=0;
    		int temp=i;
    		while(true){
    			j++;//倒数第j位
    			if(j==1)r[n-j]=(char)(temp%10+'1');//从1开始
    			else r[n-j]=(char)(temp%10+'0');
    			
    			if(j>1&&r[n-j+1]==':'){//后一位为:,即'9'后面那个字符时,要进位
    				r[n-j+1]='0';
    				r[n-j]=(char)(temp%10+'1');
    			}
    			
    			temp=temp/10;
    			
    			if(temp==0)break;
    		}
    		if(r[n-j]==':'){//最高位为:
				r[n-j]='0';
				j++;
				r[n-j]=(char)(temp%10+'1');
			}
    		result[i]=Integer.parseInt(new String(r,n-j,j));//第三个参数为长度
    	}
        return result;
    }
}

5)学到的东西

new String(char[],int start,int len)最后一个参数为长度

大数字符串拼接

17、删除链表的节点(18、Easy)

1)题目要求

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

注意:此题对比原题有改动

示例 1:

输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

说明:

题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点

2)我的解法

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        ListNode cur=head;
        if(head==null)return null;
        if(head.val==val){head=head.next;return head;}
        while(cur.next!=null&&cur.next.val!=val){
            cur=cur.next;
        }
        cur.next=cur.next.next;

        return head;

    }
}

3)其他解法

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        if(head.val == val) return head.next;
        ListNode pre = head, cur = head.next;
        while(cur != null && cur.val != val) {
            pre = cur;
            cur = cur.next;
        }
        if(cur != null) pre.next = cur.next;
        return head;
    }
}


作者:jyd
链接: link
来源:力扣(LeetCode)

4)自己的优化代码

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        ListNode cur=head;

        if(head.val==val){return head.next;}
        while(cur.next!=null&&cur.next.val!=val){
            cur=cur.next;
        }
        cur.next=cur.next.next;

        return head;

    }
}

5)学到的东西

链表

18、正则表达式匹配(19、Hard)

1)题目要求

请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

示例 1:

输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:

输入:
s = “aa”
p = “a*”
输出: true
解释: 因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:

输入:
s = “ab”
p = “."
输出: true
解释: ".
” 表示可匹配零个或多个(’*’)任意字符(’.’)。
示例 4:

输入:
s = “aab”
p = “cab”
输出: true
解释: 因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:

输入:
s = “mississippi”
p = “misisp*.”
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 ,无连续的 '’。

2)我的解法

尽力了。。

“baabbbaccbccacacc”
“c*…baa.*a…*c”

倒在了上面的例子上

class Solution {
    public boolean CanDelete(String s,int i,String p,int j){
        //若最终s遍历完成,p还剩下东西,判断剩下的东西可否抹去,比如剩个a*就可以抹去
        if(j>0&&p.charAt(j)=='*'&&p.charAt(j-1)=='.'&&j<p.length()-1){
            int k=s.length()-1;
            while(k>=0){
                if(isMatch(s.substring(k),p.substring(j+1)))return true;
                k--;
            }
            return false;
        }
        else if(p.charAt(j)=='*'){
            int k=j+1;
            while(k<p.length()){
                if(p.charAt(k)==s.charAt(s.length()-1))k++;
                else if(k<p.length()-1&&p.charAt(k+1)=='*')k=k+2;
                else return false;
            }
        }
        else {
            if(j+1>=p.length()||p.charAt(j+1)!='*')return false;
            if(j+2<p.length())return CanDelete(s,i,p,j+2);
        }
        return true;
    }
    public boolean isMatch(String s, String p) {
        int i=0,j=0;

        if(s.length()!=p.length()&&!p.contains("*"))return false;

        char sc,pc;
        while(i<s.length()&&j<p.length()){

            sc=s.charAt(i);
            pc=p.charAt(j);
            if(pc=='.'){
                i++;j++;
            }
            else if(pc=='*'){
                if(i>0&&sc!=s.charAt(i-1)&&p.charAt(j-1)!='.')j++;
                else {
                    if(!isMatch(s.substring(i-1),p.substring(j+1)))i++;//如果后面的匹配不上,这里就多分配一个
                    else return true;
                }
            }
            else{
                if(j<p.length()-1&&p.charAt(j+1)=='*'&&sc!=pc){j++;j++;continue;}
                else if(sc!=pc)return false;
                i++;j++;
            }
        }
        if((j<p.length()&&!CanDelete(s,i,p,j))||i<s.length())return false;

        return true;
    }
}

3)其他解法

在这里插入图片描述

class Solution {
public:
    bool isMatch(string s, string p) {
        int sLen = s.length(), pLen = p.length();
        vector<vector<bool> > dp(sLen + 1, vector<bool>(pLen + 1, false));
        dp[0][0] = true;
        for(int i=1; i<=pLen; ++i)
        {
            if(i >= 2 && p[i - 1] == '*' && dp[0][i - 2] == true) // 记得加 i >= 2的判断 
                dp[0][i] = true;
        }
        for(int i=1; i<=sLen; ++i)
        {
            for(int j=1; j<=pLen; ++j)
            {
                if(s[i - 1] == p[j - 1] || p[j - 1] == '.')
                    dp[i][j] = dp[i - 1][j - 1];
                else if(p[j - 1] == '*' && j >= 2) // 记得加 j >= 2的判断,否则 s = aa, p = *a 过不去测试
                {
                    if(p[j - 2] != s[i - 1] && p[j - 2] != '.')
                        dp[i][j] = dp[i][j - 2];
                    else 
                        dp[i][j] = dp[i][j - 2] || dp[i][j - 1] || dp[i - 1][j];
                }
                else dp[i][j] = false;
            }
        }
        return dp[sLen][pLen];
    }
};


作者:superkakayong
链接: link
来源:力扣(LeetCode)

4)自己的优化代码

class Solution {
    public boolean isMatch(String s, String p) {
        int n=s.length(),m=p.length();
        boolean[][] dp=new boolean[n+1][m+1];
        dp[0][0]=true;
        for(int k=1;k<m+1;k++){//初始化dp(当s为空时)
            if(p.charAt(k-1)=='*')dp[0][k]=dp[0][k-1];//当前为'*'时
            else if(k<p.length()&&p.charAt(k)=='*')dp[0][k]=dp[0][k-1];//当前不为'*'但它的下一个为'*'
            else dp[0][k]=false;
        }
        for(int i=1;i<n+1;i++){
            for(int j=1;j<m+1;j++){
                //j==0时,dp[i][j]为false
                if(p.charAt(j-1)=='*'&&j>=2){//为'*'时
                    if(p.charAt(j-2)!=s.charAt(i-1)&&p.charAt(j-2)!='.'){
                        //*前面字符那个与i-1匹配不上,则这两个字符(比如a*)不要了
                        dp[i][j]=dp[i][j-2];
                    }
                    else {//*前面字符那个与i-1匹配上了
                        //dp[i][j-2]代表a*取0个,dp[i-1][j]代表取多个
                        dp[i][j]=dp[i-1][j]||dp[i][j-2];//比如aa*和a,即使匹配上了,后面的a*也不能要
                    }

                }
                else if(p.charAt(j-1)=='.')dp[i][j]=dp[i-1][j-1];
                else{ //正常字符
                    if(p.charAt(j-1)==s.charAt(i-1)&&i>0)dp[i][j]=dp[i-1][j-1];
                    //不等的时候为false
                }
            }
        }
        return dp[n][m];
    }
}

5)学到的东西

动态规划

与前面结果的关系

(此题多刷几次)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值