【每日一题】LeetCode. 面试题16.18. 模式匹配

每日一题,防止痴呆 = =

一、题目大意

你有两个字符串,即pattern和value。 pattern字符串由字母"a"和"b"组成,用于描述字符串中的模式。例如,字符串"catcatgocatgo"匹配模式"aabab"(其中"cat"是"a",“go"是"b”),该字符串也匹配像"a"、"ab"和"b"这样的模式。但需注意"a"和"b"不能同时表示相同的字符串。编写一个方法判断value字符串是否匹配pattern字符串。
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pattern-matching-lcci

二、题目思路以及AC代码

思路

一开始我以为会是DP的题,想设dp[i][j]表示pattern前i个字符和value前j个字符是否匹配来着,后来发现好像并没有递推关系 = =。

其实这道题说起来就是一个枚举的题目,但是直接在源字符串上找匹配并不好处理,我们可以枚举pattern中a和b可能表示的字符串长度。我们设a表示的字符串长度为len_a,b表示的字符串长度为len_b,a在pattern中的个数为count_a,b在pattern中的个数为count_b,那么如果模式匹配的话,则一定满足:

len_a * count_a + len_b * count_b = v_size
其中v_size是value字符串的长度。这样的话,我们只需要对 len_a 进行枚举,就可以计算出len_b,从而去遍历检查是否是模式匹配的。

当然这道题还有许多边界情况。

  • len_a 和 len_b 一定都是大于等于0的
  • 如果value是空,那么pattern只有为空,或者pattern中只包含一种字符时,才会匹配
  • 如果pattern为空,那么只有value为空才会匹配
  • 如果value和pattern都是非空的,那么我们就要对pattern中出现的那个字符进行枚举(如果都出现可以枚举任意一个)。

这样的话,我们可以预先把 a 和 b 设定好角色,也就是让其中一个总是pattern中出现次数较多的那个元素,这样我们就可以将上述一些边界情况简化了。

AC代码
class Solution {
public:
    bool patternMatching(string pattern, string value) {
    	// 用来记录pattern中出现a和b的次数
        int count_a = 0, count_b = 0;

		// 统计pattern中的a和b
        for (char ch: pattern) {
            if (ch == 'a') count_a++;
            else count_b++;
        }
		
		// 保证a始终是pattern中出现次数较多的那个
		// 这样并不会影响结果
        if (count_a < count_b) {
            swap(count_a, count_b);
            for (char& ch: pattern) {
                if (ch == 'a') ch = 'b';
                else ch = 'a';
            }
        }

		// 如果value是空,要么pattern是空,要么pattern中只有一种元素
		// 由于上面保证a是出现次数较多的了,这里count_b == 0就包含了上述两种情况
        if (value.empty()) return count_b == 0;
        // 如果value非空,pattern为空,那么直接返回false
        if (pattern.empty()) return false;

		// 下面就是针对len_a进行遍历
        int v_size = value.size();
        for (int len_a = 0;len_a * count_a <= v_size;len_a++) {
            int rest = v_size - len_a * count_a;
			// 如果count_b是0,那么rest也得是0,不然无法匹配
			// 如果count_b不是0,那么rest必须可以整除count_b,计算b的长度
            if ((count_b == 0 && rest == 0) || (count_b && rest % count_b == 0)) {
                string value_a, value_b;
                int pos = 0;
                bool correct = true;
                for (char ch: pattern) {
                    if (ch == 'a') {
                        string temp = value.substr(pos, len_a);
                        if (value_a.empty()) value_a = temp;
                        else if (value_a != temp) {
                            correct = false;
                            break;
                        }
                        pos += len_a;
                    }
                    else {
                        string temp = value.substr(pos, rest / count_b);
                        if (value_b.empty()) value_b = temp;
                        else if (value_b != temp) {
                            correct = false;
                            break;
                        }
                        pos += rest / count_b;
                    }
                }
                // 这里我觉得可能测试数据有些不全
                // 我一开始是忘了加value_a != value_b的,但是也通过了
                // 不过按照题目要求,结果的a和b是不能表示相同的字符串的
                // 可以试一下 value = "dogdogdogdogdog", pattern = "abbba"
                if (correct && value_a != value_b) return true;
            }
        }

        return false;
    }
};

如果有问题,欢迎大家指正!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值