【算法刷题日记之本手篇】统计每个月兔子的总数与字符串通配符

举报
未见花闻 发表于 2022/08/31 21:38:15 2022/08/31
【摘要】 本篇文章介绍来自牛客试题广场的两道题题解,分别为【统计每个月兔子的总数】和【字符串通配符】,展示语言java。

⭐️前面的话⭐️

本篇文章介绍来自牛客试题广场的两道题题解,分别为【统计每个月兔子的总数】和【字符串通配符】,展示语言java。

📒博客主页:未见花闻的博客主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文由未见花闻原创!
📆首发时间:🌴2022年8月31日🌴
✉️坚持和努力一定能换来诗与远方!
💭参考书籍:📚《算法》,📚《算法导论》
💬参考在线编程网站:🌐牛客网🌐力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!

⭐️统计每个月兔子的总数⭐️

🔐题目详情

有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。

例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。

一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?

数据范围:输入满足 1≤n≤31

输入描述:

输入一个int型整数表示第n个月

输出描述:

输出对应的兔子总数

示例1

输入:

3

输出:

2

题目链接:统计每个月兔子的总数

💡解题思路

基本思路: 斐波拉契数列,动态规划
解题思路:
tz
根据题意,我们不难发现,3+个月的兔子数为两个月前兔子数。
毕竟到第三月的兔子至少得经过两个月的成长。
状态定义: 不妨设第i个月的兔子为f[i],则上个月的兔子为f[i-1],满三月的兔子数为f[i-2]。
状态转移方程: 不难得知f[i]=f[i-1]+f[i-2],其中i>2
初始状态: f[1]=1,f[2]=1。

其实就是一个斐波拉契数列,由于很熟悉了,就直接采用优化版的解法吧,直接取a为f[i-2],b为f[i-1],f为f[i],f[i]=a+b,每轮一次更新a,b值即可。

🔑源代码

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int n = sc.nextInt();
        if (n <= 2) {
            System.out.println(n);
            return;
        }
        int a = 1;
        int b = 1;
        int f = 1;
        while (n - 2 > 0) {
            f = a + b;
            a = b;
            b = f;
            --n;
        }
        System.out.println(f);
    }
}

🌱总结

本题为斐波拉契数列构造题,递推,动态规划都可以解决,不过递归会有很多次的重复计算。

⭐️字符串通配符⭐️

🔐题目详情

问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。
要求:
实现如下2个通配符:
*:匹配0个或以上的字符(注:能被*和?匹配的字符仅由英文字母和数字0到9组成,下同)
?:匹配1个字符

注意:匹配时不区分大小写。

输入:
通配符表达式;
一组字符串。

输出:

返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false

数据范围:字符串长度:1≤s≤100

进阶:时间复杂度:O(n^2^) ,空间复杂度:O(n)

输入描述:

先输入一个带有通配符的字符串,再输入一个需要匹配的字符串

输出描述:

返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false

示例1

输入:

te?t*.*
txt12.xls

输出:

false

示例2

输入:

z
zz

输出:

false

示例3

输入:

pq
pppq

输出:

false

示例4

输入:

**Z
0QZz

输出:

true

示例5

输入:

?*Bc*?
abcd

输出:

true

示例6

输入:

h*?*a
h#a

输出:

false

说明:

根据题目描述可知能被*?匹配的字符仅由英文字母和数字09组成,所以?不能匹配#,故输出false      

示例7

输入:

p*p*qp**pq*p**p***ppq
pppppppqppqqppqppppqqqppqppqpqqqppqpqpppqpppqpqqqpqqp

输出:

false

题目链接:字符串通配符

💡解题思路

基本思路: 动态规划
1

解题思路:

状态定义: 定义dp[i][j]为str1j个字符是否与str2i个字符是否匹配。
确定初始状态: dp[0][0]=true如果str1[i]=='*',dp[0][j]=dp[0][j-1]
状态转移方程: 以下比较均为不区分大小写比较。
情况1:str1[j] 为除了*,?以外的字符或str1[j]*,?str2[i]为数字字母以外的字符。
如果str1[j]==str2[i] ,取决于str1j-1个字符是否与str2i-1个字符是否匹配,则dp[i][j]=dp[i-1][j-1]
如果str1[j]!=str2[i] ,dp[i][j]=false
1

情况2:str1[j]*str2[i]为数字或字母。
如果str1j-1个字符与str2i个字符匹配,str1加上一个*仍与str2i个字符匹配,即dp[i][j]=dp[i][j-1]
如果str1j个字符与str2前i-1个字符匹配,str2加上一个字母或数字字符仍与str1i个字符匹配,即dp[i][j]=dp[i-1][j]
如果str1j-1个字符与str2i-1个字符匹配,str1加上一个*仍与str2加上一个字母或数字匹配,即dp[i][j]=dp[i-1][j-1]
综合,取三种情况的并集,即dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i-1][j-1]
3

情况3:str1[j]?str2[i]为数字或字母。
能表示任意一个字母或数字,所以取决于str1j-1个字符是否与str2i-1个字符是否匹配,则dp[i][j]=dp[i-1][j-1]

4

🔑源代码

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str1 = sc.nextLine();
            String str2 = sc.nextLine();
            str1 = str1.toLowerCase();
            str2 = str2.toLowerCase();
            int n = str1.length();
            int m = str2.length();
            char[] cs1 = str1.toCharArray();
            char[] cs2 = str2.toCharArray();
            boolean[][] dp = new boolean[m + 1][n + 1];
            //初始化dp[0][0] = true,如果cs1中的第一个字符为*,那dp[0][1]=true,
            //后面如果还是*,dp[0][j]=dp[0][j-1],综合dp[0][j]=dp[j-1]
            dp[0][0] = true;
            for (int j = 1; j <= n; j++) {
                if (cs1[j - 1] == '*'){
                    dp[0][j] = dp[0][j-1];
                }
            }
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= n; j++) {
                    if (cs1[j - 1] == cs2[i - 1]) {
                        //dp[i][j] = dp[i-1][j-1]
                        dp[i][j] = dp[i - 1][j - 1];
                    } else if (cs1[j - 1] == '?' && isDigitOrAlphabet(cs2[i - 1])) {
                        //注:能被*和?匹配的字符仅由英文字母和数字0到9组成
                        dp[i][j] = dp[i - 1][j - 1];
                    } else if (cs1[j - 1] == '*' && isDigitOrAlphabet(cs2[i - 1])) {
                        //dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i-1][j-1]
                        dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i - 1][j - 1];
                    }
                    //其他情况dp[i][j]就是false,数组的值默认false,所以不用改了
                }
            } 
            System.out.println(dp[m][n]);
        }
        
    }
    private static boolean isDigitOrAlphabet(char c) {
        return c >= '0' && c <= '9' || c >= 'a' && c <= 'z';
    }
}

🌱总结

本题为字符串匹配题,也是二维是态规划问题,难点在于问题的抽象与状态定义以及状态转移方程的推导。

类似题:
【难度:hard44. 通配符匹配
【难度::hard10. 正则表达式匹配

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。