面试题 16.18. 模式匹配(解方程)

力扣面试题 16.18. 模式匹配

你有两个字符串,即pattern和value。

pattern字符串由字母"a"和"b"组成,用于描述字符串中的模式。例如,字符串"catcatgocatgo"匹配模式"aabab"(其中"cat"是"a",“go"是"b”),该字符串也匹配像"a"、"ab"和"b"这样的模式。

但需注意"a"和"b"不能同时表示相同的字符串。编写一个方法判断value字符串是否匹配pattern字符串。

示例 1:

输入: pattern = "abba", value = "dogcatcatdog"
输出: true

示例 2:

输入: pattern = "abba", value = "dogcatcatfish"
输出: false

示例 3:

输入: pattern = "aaaa", value = "dogcatcatdog"
输出: false

示例 4:

输入: pattern = "abba", value = "dogdogdogdog"
输出: true
解释: "a"="dogdog",b="",反之也符合规则

提示:

  • 0 <= len(pattern) <= 1000
  • 0 <= len(value) <= 1000
  • 你可以假设pattern只包含字母"a"和"b",value仅包含小写字母。

分析

主方法里就是遍历数字解方程,
x*countA+y*countB = valueLen
找到可行解后就可以根据解来判断是否能匹配。

当然,在解方程之前先把特殊情况解决掉,比如字符串为空、a或者b代表空字符串的情况。排除掉这几种特殊情况后,解方程里a和b的数量肯定是都超过1了。

思路全在注释里了。

代码

class Solution {
    public boolean patternMatching(String pattern, String value) {
        int plen = pattern.length();
        int vlen = value.length();
        
        //两个字符串都是空,能匹配。
        if(vlen == 0 && plen == 0) return true;

        //模式串不为空,需要判断模式串是不是全是一个字母。
        if(vlen == 0 && plen != 0) {
            for(int i = 1; i<plen; i++){
                if(pattern.charAt(i) != pattern.charAt(i-1)) return false;
            }
            return true;
        };

        //模式串为空,无法匹配。
        if(plen == 0) return false;
        

        //计算a和b的数量
        int countA = 0;
        int countB = 0;
        for(char c:pattern.toCharArray()){
            if(c == 'a') countA++;
            else countB++;
        }

        //判断a或者b为0的情况
        if(countA == 0){
            if(check(value,countB)) return true;
            else return false;
        }
        if(countB == 0){
            if(check(value,countA)) return true;
            else return false;
        }


        //先测试能否单独被a或者b分割
        if(check(value, countA) || check(value, countB)) return true;

        //现在不能被单个字符分割
        //x是a代表的字符串的长度,y是b代表的字符串的长度
        int x = 0, y = 0;
        
        //x*countA+y*countB = vLen

        for(y = 1; y<vlen; y++){
            if((vlen-countB*y)%countA == 0 && ((vlen-countB*y)/countA)>0){
                //能整除,说明找到了一个解,验证这个解对不对。
                x = (vlen-countB*y)/countA;
                //System.out.println(x+" "+y);
                if(check(value, pattern, countA, countB, x, y)) return true;
            }
        }

        //没有可行解,返回匹配失败。
        return false;
    }

    public boolean check(String value, int a){
        //判断能否用单个字母分割

        //如果不能整除,匹配失败。
        if(value.length()%a!=0) return false;
        int fenge = value.length()/a;

        //首个子串
        String subvalue = value.substring(0,fenge);

        for(int i = 0; i<a;i++){
            int left = i*fenge;
            int right = (i+1)*fenge;
            
            //判断后面的子串是否和第一个相同。
            if(!value.substring(left, right).equals(subvalue)) return false;
        }
        return true;
    }


    public boolean check(String value, String pattern, int a, int b, int x, int y){
        //判断两个字母均需要匹配的情况。

        //找到a与b在模式串中的位置
        ArrayList<Integer> listA = new ArrayList<>();
        ArrayList<Integer> listB = new ArrayList<>();
        char[] p = pattern.toCharArray();
        for(int i = 0; i<p.length; i++){
            if(p[i] == 'a') listA.add(i);
            else listB.add(i);
        }
        
        //计算a和b的起点。
        int aStart = listA.get(0)*y;
        int bStart = listB.get(0)*x;

        //取出a和b分别代表的子串。
        String subA = value.substring(aStart,aStart+x);
        String subB = value.substring(bStart,bStart+y);

        //a和b如果相同,匹配失败。
        if(subA.equals(subB)) return false;
        
        //开始匹配a
        //判断后面的子串是不是和起始子串一样
        for(int i = 1; i<listA.size(); i++){    
            if(listA.get(i)!=listA.get(i-1)+1){
                //如果两个a不是连续的,说明中间夹了n个B
                aStart = aStart+x+y*(listA.get(i)-listA.get(i-1)-1);
                String tmp = value.substring(aStart,aStart+x);
                if(!tmp.equals(subA)) return false;
            }else{
                //两个a连续,可以直接取子串。
                aStart += x;
                String tmp = value.substring(aStart,aStart+x);
                if(!tmp.equals(subA)) return false;
            }
        }

        //判断b,和a同理,不再写注释。
        for(int i = 1; i<listB.size(); i++){
            if(listB.get(i)!=listB.get(i-1)+1){
                bStart = bStart+y+x*(listB.get(i)-listB.get(i-1)-1);
                String tmp = value.substring(bStart,bStart+y);
                if(!tmp.equals(subB)) return false;
            }else{
                bStart += y;
                String tmp = value.substring(bStart,bStart+y);
                if(!tmp.equals(subB)) return false;
            }
        }
        
        //此解匹配成功。
        return true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值