一天一大 leet(模式匹配)难度:中等 DAY-22

20200622

img

题目(难度:中等):

你有两个字符串,即 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 仅包含小写字母。

抛砖引玉

img

特殊情况

  1. 字符串为空且规则也为空 true
  2. 字符串为空且规则包含一种字母(代表空)则 true,否则 false
  3. 规则为空 字符串不为空 false

匹配
选规则中至少出现一次的字符进行逐位匹配;
匹配 a,
其包含匹配的字符数递增(记录 a 匹配的字符 value_a 和 b 匹配的字符 value_b)
如果 ab 匹配后字符数满足与 value 相同则返回 true,不然默认返回 false

/**
 * @param {string} pattern
 * @param {string} value
 * @return {boolean}
 */
var patternMatching = function (pattern, value) {
  let pLen = pattern.length,
    vLen = value.length,
    count_a = 0, // 字符串中a的数量
    count_b = 0 // 字符串中b的数量
  // 如果字符串为空
  // 1. 规则也为空 true
  // 2. 规则不为空,只包含一种字母(代表空)则true,否则false
  if (vLen === 0) {
    if (pLen == 0) return true
    if (pattern.includes('a') && pattern.includes('b')) {
      return false
    } else {
      return true
    }
  }
  // 规则为空 字符串不为空  false
  if (pLen == 0 && vLen !== 0) return false

  // 优化循环使用规则中较多的字符匹配,保证主动匹配的字符至少出现一次,统计字符数量
  for (let i = 0; i < pLen; i++) {
    if (pattern[i] === 'a') {
      count_a++
    } else {
      count_b++
    }
  }

  // 使用指定字符a进行主动匹配,如果a少于b那主动把a、b字符对调,
  if (count_a < count_b) {
    const t = count_a
    count_a = count_b
    count_b = t
    let s = ''
    for (let i = 0; i < vLen; i++) {
      if (pattern[i] === 'a') {
        s += 'b'
      } else {
        s += 'a'
      }
    }
    pattern = s
  }

  // a表示匹配字符a在字符串中代表的字符数,
  // n是剩余需要d匹配的字符
  // pos记录a字母在字符串中匹配的位置
  // value_a a匹配的字符串组
  // value_b b匹配的字符串组
  for (let a = 0; count_a * a <= vLen; a++) {
    const n = vLen - count_a * a
    if ((count_b === 0 && n === 0) || (count_b !== 0 && n % count_b === 0)) {
      const b_len = count_b === 0 ? 0 : Math.floor(n / count_b)
      let pos = 0
      let sign = true
      let value_a = ''
      let value_b = ''
      for (let i = 0; i < pLen; i++) {
        if (pattern[i] === 'a') {
          const sub = value.substr(pos, a)
          if (!value_a.length) {
            value_a = sub
          } else if (value_a !== sub) {
            sign = false
            break
          }
          pos += a
        } else {
          const sub = value.substr(pos, b_len)
          if (!value_b.length) {
            value_b = sub
          } else if (value_b !== sub) {
            sign = false
            break
          }
          pos += b_len
        }
      }
      if (sign && value_a !== value_b) {
        return true
      }
    }
  }
  return false
}

其他解法

\1 和 \2 表示对前面分组的反向引用

  • aabb -> (\w*)\1(\w*)\2
  • abba -> (\w*)(\w*)\2\1
//**
 * @param {string} pattern
 * @param {string} value
 * @return {boolean}
 */
var patternMatching = function (pattern, value) {
      if (pattern === "") {
    return value === "";
  }
  let group = 1;
  let a = '';
  let b = '';
  let reg = '';
  for (const char of pattern.split('')) {
    if (char === 'a') {
      if (a) {
        reg += a;
      }
      else {
        reg += '(\\w*)';
        a = '\\' + group++;
      }
    }
    else if (char === 'b') {
      if (b) {
        reg += b;
      }
      else {
        reg += '(\\w*)';
        b = '\\' + group++;
      }
    }
  }
  const match = new RegExp('^' + reg + '$').exec(value);
  return Boolean(match) && match[1] !== match[2];
}

博客: 小书童博客(http://gaowenju.com)

公号: 坑人的小书童
坑人的小书童

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探险家小扣的行动轨迹,都将保存在记录仪中。expeditions[i] 表示小扣第 i 次探险记录,用一个字符串数组表示。其中的每个「营地」由大小写字母组成,通过子串 -> 连接。例:"Leet->code->Campsite",表示到访了 "Leet"、"code"、"Campsite" 三个营地。expeditions[0] 包含了初始小扣已知的所有营地;对于之后的第 i 次探险(即 expeditions[i] 且 i > 0),如果记录中包含了之前均没出现的营地,则表示小扣 新发现 的营地。 请你找出小扣发现新营地最多且索引最小的那次探险,并返回对应的记录索引。如果所有探险记录都没有发现新的营地,返回 -1。注意: 大小写不同的营地视为不同的营地; 营地的名称长度均大于 0。用python实现。给你几个例子:示例 1: 输入:expeditions = ["leet->code","leet->code->Campsite->Leet","leet->code->leet->courier"] 输出:1 解释: 初始已知的所有营地为 "leet" 和 "code" 第 1 次,到访了 "leet"、"code"、"Campsite"、"Leet",新发现营地 2 处:"Campsite"、"Leet" 第 2 次,到访了 "leet"、"code"、"courier",新发现营地 1 处:"courier" 第 1 次探险发现的新营地数量最多,因此返回 1。示例 2: 输入:expeditions = ["Alice->Dex","","Dex"] 输出:-1 解释: 初始已知的所有营地为 "Alice" 和 "Dex" 第 1 次,未到访任何营地; 第 2 次,到访了 "Dex",未新发现营地; 因为两次探险均未发现新的营地,返回 -1
04-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值