LeetCode 面试题 16.18. 模式匹配

原题目:https://leetcode-cn.com/problems/pattern-matching-lcci/

 

思路:

假设p的长度为lp.v的长度为lv,在p中,有ca个a,那么对应的就有(lp - ca)个b,又假设a对应的字符串的长度为la,b对应的字符的长度为lb。对此我们可以得到:

ca*la + (lp-ca)*lb = lv

我们可以对la进行枚举(ca的取值范围为[0,lp/ca],左边界对应空串,右边界对应b为空串),在根据上去算出lb的长度(整数),然后在根据pattern和value把对应的a和b找出来,如果前后对应一致,并且ab不相同,就是有效的。

细节,如果a出现的次数为0,我们就无法对la进行枚举,而换一种思路,我们可以对lb进行枚举,那么我们可以根据对称性,如果a出现的次数小于b,就交换ab,这样不改变我们的结果。

 

实现逻辑:

1、保证a是出现的次数多的那个字母(上述的细节分析)

2、如果v为空,那么p为空或者一种字符(空串),匹配成功

3、如果p为空,v为空才可以匹配成功

4、如果pv均不为空,那么我们就根据上述的思路进行枚举

 

代码:

class Solution {
public:
    bool patternMatching(string pattern, string value) {
        int count_a = 0, count_b = 0;
        for (char ch: pattern) {
            if (ch == 'a') {
                ++count_a;
            } else {
                ++count_b;
            }
        }
        //保证a是出现次数多的字母
        if (count_a < count_b) {
            swap(count_a, count_b);
            for (char& ch: pattern) {
                ch = (ch == 'a' ? 'b' : 'a');
            }
        }
        //v是空,那么a为空或者只有a( 等价于  b出现的次数为0),
        if (value.empty()) {
            return count_b == 0;
        }
        //p为空,而v不为空,匹配失败
        if (pattern.empty()) {
            return false;
        }
        for (int len_a = 0; count_a * len_a <= value.size(); ++len_a) {
            int rest = value.size() - count_a * len_a;
            if ((count_b == 0 && rest == 0) || (count_b != 0 && rest % count_b == 0)) {
                int len_b = (count_b == 0 ? 0 : rest / count_b);
                int pos = 0;
                bool correct = true;
                string value_a, value_b;
                for (char ch: pattern) {
                    if (ch == 'a') {
                        string sub = value.substr(pos, len_a);
                        if (!value_a.size()) {
                            value_a = sub;
                        } 
                        // 前后的a不一致
                        else if (value_a != sub) {
                            correct = false;
                            break;
                        }
                        pos += len_a;
                    } 
                    else {
                        string sub = value.substr(pos, len_b);
                        if (!value_b.size()) {
                            value_b = sub;
                        } 
                        //前后的b不一致
                        else if (value_b != sub) {
                            correct = false;
                            break;
                        }
                        pos += len_b;
                    }
                }
                // 匹配成功,并且ab不等
                if (correct && value_a != value_b) {
                    return true;
                }
            }
        }
        return false;
    }
};

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值