Leetcode -- Regular Expression Matching

★leetcode10_Regular Expression Matching[附动态规划] 一.问题描述 Implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover the ent 阅读详情

问题链接:https://oj.leetcode.com/problems/regular-expression-matching/

问题描述:Implement regular expression matching with support for '.' and '*'.

'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true

API : public boolean isMatch(String s, String p)

这题其实有点绕和难。leetcode归类为hard应该是没有错的,除非我太水了。。。

先介绍第一种做法:Brute Force.

毕竟怎么看都是要记录当前扫的s和p的位置的,那么helper函数的长相应该是这样的:public boolean helper(String s, String p, int i, int j)

i表示扫到s哪个位置,j表示扫到了p哪个位置。

而根据题意,根据条件case有很多,譬如s[i] == p[j], p[j] == '.', p[j] == '*' 等等

但大致上可以基本上可以分类为两个case:

1. s[i] == p[j] 或者p[j] == ','。 在这种情况下,以i + 1和j + 1的前提往下递归一层即可。

2. p[j + 1] == '*',之所以这里用j + 1做判断是因为'*'的内容是根据p[j]来的。这个时候'*'表示的是0~无限多个p[j]。所以s[i], s[i + 1]....s[s.length() - 1]都有可以和p[j + 1]匹配的可能。只要满足以下两个条件的其中之一即可p[j] == '.' 或者 p[j] ==s[i + k] (0 <= k <= s.length() - 1 - i)。 所以这个时候需要不停循环并递归s[i + 1]下一层直到不满足上述两个条件之一。

3. 上述两个case都不满足的就很简单了, return false即可。

4. 这个递归的终结点base case是if(j == p.length()) return i == s.length()。 之所以用p作为先决条件很大程度上是因为'*'的存在可以表示任意个字符(包括0个),随意性很强。这样比较容易判断。所以用if(j == p.length() && i == s.length()) 或者if(i == s.length) return j == p.length()都是不恰当的。

下面是代码:

    public boolean isMatch(String s, String p) {
        return helper(s, p, 0, 0);
    }
    
    public boolean helper(String s, String p, int l, int r) {
    //2017-10-17
    //还是补充一下这里,重新回顾的时候发现先判断r == p.length()还是有意义的
    //我想了一会儿为什么当年写的时候不用 if(l == s.length() && r == p.length()) return true 去判断
    //后来发现这个条件是必要不充分的,也就是即使l == s.length() && r != p.length()的时候,也是可以返回true的
    //就是在l == s.length()的时候,如果r在p的位置的后方全是带有*的组合。
    // ex. s = "abcd", p = "abcc*d*d*"之类的,helper(s, p, 4, 4)也是会返回true的
    // 所以用上面的if去判断,会错误的返回false。
        if (r == p.length()) return l == s.length();
        if (r + 1 < p.length() && p.charAt(r + 1) == '*') {
            while(l < s.length() && (p.charAt(r) == '.' || p.charAt(r) == s.charAt(l))) { 
                // 2023-03-21
                // 每次回看都觉得l这里应该需要加1。今天仔细想了一下,发现其实这里的递归不加才是对的
                // 理由是因为这里其实往下递归的是我们这里在s这里选择不取Match,也就是不消耗
                // s.charAt(l)去和p.charAt(r)进行配对
                // 这是因为在while loop之后的那个return helper(s, p, l, r + 2)
                // 会把s.charAt(l)和p.charAt(r)匹对的情况涵括进去。
                if(helper(s, p, l, r + 2)) return true;
                l++;
            }
            
            return helper(s, p, l, r + 2);
        } else if (l < s.length() && (p.charAt(r) == '.' || p.charAt(r) == s.charAt(l))) {
            return helper(s, p, l + 1, r + 1);
        } else return false;
    }

上述算法的复杂度是指数级别的,但是也能过leetcode测试,说明本题leetcode的检测并没有很严格。

接下来将要介绍dp的算法,其实所有的dp算法大都可以从brute force算法中看出端倪所在。dp推导式的条件随后放送。

来撸dp推导式了,dp最重要的就是推导式,有了推导式代码其实也就成型了。

然而dp的推导式基本都是可以从brute force得到的。

首先定义dp函数f(i,j)的定义,f(i,j)在这里表示的就是s[1...i]到p[1...j]是否一个可行的regular expression match

那么根据之前在brute force那样,我们可以继续分出类似的case来得到推导式:

Case 1 : 就是当p[j + 1] != '*'的情况,

这个情况比较简单,推导式就是:f(i + 1, j + 1) = f(i, j) && (s[i] == s[j] || p[j] == ".")

Case 2 : 当p[j + 1] == "*"的情况

这个情况就和之前brute force有点不一样了,还需要分两个sub case来分析。

Case 2.a : p[i] == '.'

这种情况比较好解决,其实就和brute force可以循环i到底一样,f(i + k, j + 1) = f(i + 1, j) || f(i + 1, j - 1)   (i + 1 <= i + k <= s.length())

Case 2.b : p[i] != '.'

这种情况下,以下三个条件任意一个成立都可以:

1.f(i + 1, j) 成立, 这个情况表示星号之前的那个可以match到s[i],也就是星号至少可以取一个之前的字符。

2.f(i + 1, j - 1)成立, 这种情况表示星号的前面第二个可以match到s[i], 也就是星号和之前的字符就当成不存在处理,也就是子串"x*"(x在这里表示任意一个字符)部分当成空字符串处理。

3.f(i, j + 1) && s[i] == s[i] && s[i - 1] == p[j - 1]成立,这种情况比较难理解。其实就是s里前一个字符和星号之前的字符相符,然后相同的字符在s[i - 1, i .... i + k]里循环下去。

根据以上的case分析。给出代码如下:

    public boolean isMatch(String s, String p) {
        if(s.length() == 0 && p.length() == 0)
            return true;
        if(p.length() == 0)
            return false;
        boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
        dp[0][0] = true;
        for(int j = 0; j < p.length(); j++){
            if(p.charAt(j) == '*'){//case 2
                dp[0][j + 1] |= j > 0 && dp[0][j - 1];
                if(j == 0)continue;
                if(p.charAt(j - 1) != '.'){//case 2b.
                    for(int i = 0; i < s.length(); i++){
                        dp[i + 1][j + 1] |= dp[i + 1][j] || dp[i + 1][j - 1] || (i > 0 && dp[i][j + 1] && s.charAt(i) == s.charAt(i - 1) && s.charAt(i - 1) == p.charAt(j - 1));
                    }
                }else{//case 2.a
                    int i = 0;
                    while(j > 0 && i < s.length() &&!dp[i + 1][j - 1] && !dp[i + 1][j])// 找到第一个匹配条件的,也就是找到第一个为真的
                        i++;
                    for(; i < s.length(); i++){
                        dp[i + 1][j + 1] = true;
                    }
                }
            }else{// case 1
                for(int i = 0; i < s.length(); i++){
                    dp[i + 1][j + 1] = dp[i][j] && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.');
                }
            }
        }
        return dp[s.length()][p.length()];
    }

下面一段code是我另外再写的,附加了很多comments的。

    public boolean isMatch(String s, String p) {
        boolean[][] subResult = new boolean[s.length() + 1][p.length() + 1];
        subResult[0][0] = true;//空集对空集当然是true了
        for(int i = 1; i < p.length(); i += 2){
            if(p.charAt(i) != '*'){
                break;
            }
            subResult[0][i + 1] = true;
        }
        for(int i = 1; i <= p.length(); i++){
            if(p.charAt(i - 1) == '*'){
//                if(i > 1 && subResult[0][i - 2])subResult[0][i] = true;
//                if(i == 1)continue;
                //这个算是一个base case,还是很有考究的。
                //基本上是可以这么理解的。
                //subResult第一维如果是0,就表示s取子集的时候取了空集
                //而这个时候,事实上就是当p[1], p[3], p[5]...p[2 * i - 1]
                //subResult[0][2 * i]都为true
                //而当其中一环断节的时候,接下来的都不为true了。
                //另外,事实上有效的输入里,i都是除以2余1的,如果全部为真的话
                if(p.charAt(i - 2) != '.'){
                    for(int j = 1; j <= s.length(); j++){
                        if(subResult[j][i - 1] || subResult[j][i - 2]){
                            subResult[j][i] = true;
                            //subResult[j + 1][i] 表示前面只取一个的时候为true
                            //也就是星号前面的字符是可以匹配当前s.charAt(j)的
                            //subResult[j + 1][i - 1]表示星号前面的字符一个都不取
                            //这种情况下就有好几种可能了。
                            //包括星号前面的前面的字符匹配
                            //星号前面的前面的字符还是星号,然后还能对当前
                            //s.charAt(j)匹配等等情况。
                        }
                        if(j > 1 && s.charAt(j - 1) == s.charAt(j - 2) && s.charAt(j - 2) == p.charAt(i - 2) && subResult[j - 1][i]){
                            subResult[j][i] = true;
                            //这个case是一个特殊的case。
                            //这个表示源字符串的某一个字符在不停重复
                            //然后这个字符和星号之前的字符是相同的
                        }
                    }
                }else{
                    //这个case就简单的多了
                    //星号前面是点号,就表示这两个字符组合可以匹配任何字符串
                    //所以就要找到第一个匹配到p字符串当前长度 - 1为真的情况
                    //因为点星组合可以匹配接下来的所有字符,所以剩下的都为真了
                    //在p到当前位置的子串的情况下
                    int j = 1;
                    while(i > 1 && j <= s.length() && !subResult[j][i - 1] && !subResult[j][i - 2])
                        j++;
                    for(; j <= s.length(); j++){
                        subResult[j][i] = true;
                    }
                }
            }else{
                //这种情况就比较好理解了,
                //只有三种情况,p.charAt(i - 1) == '.' 和 p.charAt(i - 1) == s.charAt(j - 1)是一样的,只要p.charAt(i - 2)和s.charAt(j - 2)对的上号,这里也是真
                //否则为假
                for(int j = 1; j <= s.length(); j++){
                    subResult[j][i] = subResult[j - 1][i - 1] && (p.charAt(i - 1) == s.charAt(j - 1) || p.charAt(i - 1) == '.');
                }
            }
        }
        return subResult[s.length()][p.length()];
    }


事实上上面这个算法并不能匹配brute force那边。所以我另外写了一个dp算法,跟上面那个有点相近但细节上不太一样,而且可以匹配brute force case的代码:

    public boolean isMatch(String s, String p) {
        boolean[][] subResult = new boolean[s.length() + 1][p.length() + 1];
        subResult[0][0] = true;//空集对空集当然是true了
        //这是基于空集原理更直观的base case的处理方式。
        //跟下面屏蔽掉的两行if代码是同样原理但逻辑更清晰。
        for(int i = 1; i < p.length(); i += 2){
            if(p.charAt(i) != '*'){
                break;
            }
            subResult[0][i + 1] = true;
        }
        for(int i = 1; i <= p.length(); i++){
            if(i != p.length() && p.charAt(i) == '*'){
                for(int j = 1; j <= s.length(); j++){
                    //这里实际上处理的是星号之前的字符的匹配情况
                    if(s.charAt(j - 1) == p.charAt(i - 1) || p.charAt(i - 1) == '.'){
                        subResult[j][i] |= subResult[j - 1][i - 1];
                    }
                    //这个是星号把当前字符省略的情况
                    subResult[j][i + 1] |= subResult[j][i - 1];
                    //这里是星号之前字符只取一次的情况
                    subResult[j][i + 1] |= subResult[j][i];
                    //这里其实包含了两种情况。
                    //第一个,星号之前的字符不为点,那么就只有s出现连续相同而且匹配星号之前的字符的情况,这符合了题目关于星号的描述,
                    //第二种,星号之前的字符为点,那麽就无敌了,这表示可以匹配任何字符串,所以只要出现了一个真,接下来的都是真了。
                    if(j > 1 && s.charAt(j - 1) == s.charAt(j - 2) && s.charAt(j - 1) == p.charAt(i - 1) || p.charAt(i - 1) == '.')
                        subResult[j][i + 1] |= subResult[j - 1][i + 1];
                }
                i++;
            }
            else{
                //这种情况就比较好理解了,
                //只有三种情况,p.charAt(i - 1) == '.' 和 p.charAt(i - 1) == s.charAt(j - 1)是一样的,只要p.charAt(i - 2)和s.charAt(j - 2)对的上号,这里也是真
                //否则为假
                for(int j = 1; j <= s.length(); j++){
                    subResult[j][i] = subResult[j - 1][i - 1] && (p.charAt(i - 1) == s.charAt(j - 1) || p.charAt(i - 1) == '.');
                }
            }
        }
        return subResult[s.length()][p.length()];
    }

全球半导体设备氧化钇熔射服务行业规模预测:预计未来六年CAGR为7.8% 本文将对“半导体设备氧化钇熔射服务”行业进行深度分析,探讨市场趋势的演变、核心竞争者的战略布局、供应链结构的内外特点、研发创新的最新进展、法规政策环境的适应性调整以及投资机会与风险评估。这一稳健的增长趋势表明半导体设备氧化钇熔射服务在电子行业中的重要性逐渐增强。由于全球对于高效、高精度和可靠的电子解决方案的需求增加,对能够提供这些功能的半导体设备氧化钇熔射服务的需求日益增长。由于半导体设备氧化钇熔射服务主要为就地服务型,其“配送”主要依赖于专业团队和技术设备的及时调配,强调服务的时效性和高质量。 阅读详情

相关推荐

TMS320F280049C 学习笔记11 控制率加速器 CLA 例程

总结了TI官方在C2000Ware_3_01_00_00版本中提供的7个与CLA相关的例程。

whyorwhnt的专栏 1万+

10. 正则表达式匹配(Regular Expression Matching)

10. 正则表达式匹配(Regular Expression Matching)题解递归复杂度分析PythonJava(待完成)动态规划法复杂度分析PythonJava(待完成) 题解 递归 递归函数isMatch(s,p)isMatch(s,p)isMatch(s,p),sss表示待匹配字符,ppp表示字符规律 若ppp为空,此时返回sss是否为空。表示若字符规律已经为空,若sss还不为空,此...

朱师傅的博客 528

用Proteus8.9自带STM32F401VE的Controller仿真STM32F407ZGT6,F429IGT6

@用Proteus8.9自带STM32F401VE的Controller仿真STM32F407ZGT6,F429IGT6 一, 目前得到的 Proteus8.9版本软件能够支持的Cortex-M4固件库项目,只能到达STM32F401VE (如下图1所示)。 (图1) 作为ST公司Cortex-M4更为广泛应用的F407,F429系列芯片;现在的Proteus8.9版本软件还没有固件库支持,不能...

kaillen的博客 3万+

QRegularExpression、QRegularExpressionMatch、QRegularExpressionMatchIterator

正则表达式

友善啊,朋友的博客 5088

WSL中使用VMD图形化界面

【代码】WSL中使用VMD图形化界面。

handsome213的博客 840

matinal:SAP 采购中形成的差异

如果库存足够会影响到物料。

matinal 當冬夜漸暖 。公众号:matinal 820

Tex中的正则表达式替换

本人在用Tex写论文时,碰到要将\textbf{NumEQ},\textbf{NumBC},\textbf{Err[k]}这样的字符串全部相应地转换成\verb|NumEQ|, \verb|NumBC|, \verb|Err[k]|。因为文章中有大量地方需要修改,手动修改机耗时又可能漏掉,最终采用正则表达式替换修改。 对被替换的字符换描述为: \\textbf\{\(*\)\}

不积跬步,无以至千里;不积小流,无以成江海 7073

ASPICE1-配置管理

SUP.8配置管理 BP1:开发配置管理策略 BP2:识别配置项 BP3:建立配置项管理系统 BP4:建立分支管理 BP5:控制变更和发布 BP6: 建立基线 BP7:报告配置项状态 BP8:验证配置项信息 BP9:管理配置项和基线的存储 1.配置管理概念 配置管理(Configuration Management,CM)是通过使用技术或行政手段对软件产品进行控制,以实现对软件开发过程和生命周期进行控制、规范的一系列措施。 完整性、一致性、可控性。 2.配置管理的主要活动: 1.

HDZQ2005的专栏 3687

[LeetCode]10. Regular Expression Matching(自学留存)

Implement regular expression matching with support for '.' and '*'.'.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover the entire input stri...

鲲之大,一锅炖不下 188

AI应用架构师干货:智能财务分析AI平台可视化模块设计(附最佳实践)

智能财务分析的价值,从来不是“AI模型有多准”,而是“财务人员能用上AI的结果”。可视化模块的设计,本质是**“站在业务用户的角度,重新定义技术的价值”**——它不需要复杂的动画,不需要华丽的特效,只需要“把AI的结果翻译成财务人员能看懂的语言”。作为AI应用架构师,我们的使命不是“打造最先进的技术”,而是“打造最有用的技术”。而可视化,就是连接技术与业务的那座“桥”。附录:实战项目GitHub仓库(注:此处可放置实际项目的GitHub链接,包含完整代码、数据样例、部署文档)作者简介。

SuperAGI2025 1156

YOLOv8改进,YOLOv8主干网络替换为ShuffleNetV2

ShuffleNet V2的设计原则:1.减少内存访问成本:通过优化数据传输路径,减少内存访问延迟,提高整体运算速度。2.考虑平台特性:针对不同硬件平台的特性进行优化设计,确保在目标平台上的高效运行。3.结构简洁高效:采用简洁而高效的模块设计,降低计算复杂度,同时保持或提升模型的预测准确性。下图,以四种不同计算复杂度水平下的准确性(在ImageNet验证集上的分类),速度和FLOPs的测量结果。(a, c) 为GPU结果,批量大小为8。(b, d) 为ARM结果,批量大小为1。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1565

LeetCode(Regular Expression Matching & Wildcard Matching)

【代码】LeetCode(Regular Expression Matching & Wildcard Matching)

Jiajun Zhu 277

2 硬件工程师笔面试高频知识考点真题解析——电容

本文全面解析了电容在电子电路中的关键应用与技术要点。主要内容包括:1. 电容选型核心要素:介质材质(陶瓷/电解/钽电容等)、容值精度、耐压等级、温度特性、ESR参数等,不同应用场景(滤波/去耦/谐振等)的选型策略。2. 典型电路应用原理:详细阐述去耦电容布局规则、晶振负载电容作用、共射放大电路旁路电容功能,以及RC电路的滤波/定时等应用。3. 特殊问题解决方案:MLCC啸叫机理与对策、寄生电容影响与消除、高速信号线电容使用禁忌等工程实践难题。4. 安全规范要点:X/Y电容的区别与选用、电解/钽电容防反接措施

XU157303764的博客 1559

LeetCode Regular Expression Matching

简易版正则表达式匹配,只有两种通配符,”.”表示任意一个字符,”c*”表示字符c可以有零个或多个。

DRFish 2032

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Leetcode: Regular Expression Matching

Implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover the entire input st

ZkvIA的博客 2万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

leetcode题解:第10题Regular Expression Matching

https://leetcode-cn.com/problems/regular-expression-matching/ 分析 这道题的难点在于存在a*这样的组合,如何处理与这种组合匹配的字符数是很棘手的问题,例如: s = "aaa", p = "aa*" s = "baaa", p = "ba*" 第一个例子中a*匹配2个字符,第二个例子中a*匹配3个字符。可以看出,匹配的字符数不仅与s有关,还与p中组合前面的字符有关(后面也有可能)。如果是.*这样的组合,会更加麻烦。 我一开始的想法是用双指针分别

chenf1999的博客 313

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Leetcode——Regular Expression Matching

题目描述 Given an input string (s) and a pattern §, implement regular expression matching with support for ‘.’ and ‘*’. 给定一个字符串s和匹配的模板p,使用“.”和“*”,实施正则表达式的匹配 ‘.’ Matches any single character. ‘*’ Matches zero or more of the preceding element. The matching shoul

Blackoutdragon的博客 465

[LeetCode]Regular Expression Matching、Wildcard Matching

Regular Expression Matching: Implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. The matchin

a83610312的专栏 5750

leetcode 第10题 Regular Expression Matching

周末也没有做leetcode,感觉有点罪恶啊,这个第10题好难啊,涉及到递归了,看的我是头晕眼花啊。我看着看着还是有点收获的,我发现题目仍然没有我想象中的那么的简单,如果s = 'a b c d e',p = '. * e',这样匹配出的结果也是正确的,我就很纳闷儿啊,' . '是匹配任意一个字符,可是我以为只能匹配一个字符,但是从这个算例上看,当它和' * '在一起时,' . '可以多次匹配不同

paofuhemakalong的博客 988

Leetcode Regular Expression Matching

Implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover the entire input st

每天都要有进步 323

【Leetcode】10. Regular Expression Matching

考虑初始条件,空字符串可以和空模式匹配,而非空字符串无法和空模式匹配,所以。不合法,我们也应该返回false。一下子是看不出来的,需要在递推的过程中算出来。,只是为了将不合法的情形包含进去);出现,也就是那个整体匹配的一部分是。末字符匹配完之后,前面有可能还有。是个合法的模式串,应该有如果。如果这个整体按照出现大于等于。,这个整体匹配完之后,还需要。,因为那个整体是匹配大于等于。可以匹配其之前的字符重复。次来匹配,那么就要求或者。可以匹配任何单个字符,次来匹配,那么结果就是。如果这个整体按照出现。

数学、算法爱好者的博客 357

[leetcode] Regular Expression Matching

题意:让我们实现正则表达式的isMatching函数,判断包含正则表达式的p是否能匹配上字符串s。其中p只包含两种特殊字符。.和*,前者也可以匹配任意字符,后者可以重复前一个字符0~多次。 解法: 解法1,递归,分情况讨论 s,p长度都为0,则返回true s长度不为0,p长度为0,则返回false s长度为0,p长度不为0,这种情况下只有p的格式是cc才可以匹配,否则都为false。 两者...

nwpuxhld 672

LeetCode——regular expression matching

题目描述: 请实现支持’.‘and’’.的通配符模式匹配 ‘.’ 可以匹配任何单个字符。↵’’ 可以匹配任何字符序列(包括空序列)。↵↵匹配应该覆盖整个输入字符串(而不是部分)。 ↵函数声明为:↵bool isMatch(const char s, const char p)↵↵下面给出一些样例:↵isMatch(“aa”,“a”) → false↵isMatch(“aa”,“aa”) → true↵isMatch(“aaa”,“aa”) → false↵isMatch(“aa”, "a") → true↵

qq_38977019的博客 320

leetcode10 Regular Expression Matching @python

leetcode里一道hard难度的题(第10题), 题主已经栽死在里面,借鉴了别人优秀的思想用python实现了,经典的东西要保留。 感谢@Vosky

nadizhong4136的博客 406

LeetCode (力扣) 10. Regular Expression Matching ( C ) - Hard - 递归法

同步发于JuzerTech网站,里面有我软、硬件学习的纪录与科技产品开箱,欢迎进去观看。

JuzerTech的博客 737
上一篇: Leetcode -- Palindrome Number
下一篇: Leetcode -- Container With Most Water
Daisy么么哒
博客等级 码龄12年 10粉丝 310原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值