• LeetCode --- 字符串系列 --- 字符串的最大公因子


    字符串的最大公因子

    题目

    对于字符串 S 和 T,只有在 S = T + ... + T(T 与自身连接 1 次或多次)时,我们才认定 “T 能除尽 S”。

    返回最长字符串 X,要求满足 X 能除尽 str1 且 X 能除尽 str2。

    提示:

    1 <= str1.length <= 1000

    1 <= str2.length <= 1000

    str1[i] 和 str2[i] 为大写英文字母


    示例

    示例 1:
    
    输入:str1 = "ABCABC", str2 = "ABC"
    输出:"ABC"
    
    示例 2:
    
    输入:str1 = "ABABAB", str2 = "ABAB"
    输出:"AB"
    
    示例 3:
    
    输入:str1 = "LEET", str2 = "CODE"
    输出:""
    

    来源:力扣(LeetCode)

    链接:https://leetcode-cn.com/problems/greatest-common-divisor-of-strings/

    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


    解题思路

    渐进题解 1

    1、比较获得 `较短字符串`
    
    2、循环 `较短字符串` , 逐个累加字符作为 `测试字符串`
    
    3、
    若 `较长字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较长字符串` 不可能被 `测试字符串` 整除
    若 `较短字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较短字符串` 不可能被 `测试字符串` 整除
    
    4、若长度能被整除,整除得到的倍数称之为 `times1` `times2`
    使 `测试字符串长度` 复制 `times1` `次、times1` 次
    若分别能等于 `较长字符串` 、 `较短字符串` 则满足 `公因数字符串` ,将该 `公因数字符串` 存起来,继续循环
    
    5、最后一个 `公因数字符串` 既是 `最大公因数字符串`
    

    渐进题解 2

    1、比较获得 `较短字符串`
    
    2、循环 `较短字符串` ,
    根据题目 `S = N * T`
    使用 `较短字符串` 截取 `自身` 、 `自身一半` `、自身四分之一` ... 得到 `测试字符串`
    
    3、
    若 `较长字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较长字符串` 不可能被 `测试字符串` 整除
    若 `较短字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较短字符串` 不可能被 `测试字符串` 整除
    
    4、若长度能被整除,整除得到的倍数称之为 `times1` `times2`
    使 `测试字符串长度` 复制 `times1` `次、times1` 次
    若分别能等于 `较长字符串` 、 `较短字符串` 则满足 `公因数字符串` 
    
    5、因为是使用 `尽可能取最大公因数字符串` 的方法去测试验证的,所以只要满足条件,就是 `最大公因数字符串`
    此时的 `公因数字符串` 就是 `最大公因数字符串` 
    

    力扣教好题解

    1、若满足都能被 `X` 除尽,那么这两个字符串 `正序相加` 与 `反序相加` 之后的的结果应该相等
    
    2、`辗转相除法` 求得 `最大公因数长度` ,对随便一个字符串进行截取`(0, 最大公因数长度)`即可得到 `X`
    定理:gcd(a, b) = gcd(b, a % b)
    而任何数与0的最大公约数是它本身 (递归终止条件)
    
    

    题解

    渐进题解 1

    // 用时一般,内存消耗一般
    执行用时: 68 ms
    内存消耗: 37.8 MB
    let gcdOfStrings = function(str1, str2) {
        // 使得 str2 是较短字符串
        if (str1.length < str2.length) {
            [str1, str2] = [str2, str1]
        }
        let cfstr = '' // 测试字符串
        let list = [] // 公因数字符串数组
        let s1len = str1.length
        let s2len = str2.length
        for (const s of str2) {
            // 累加得到 测试字符串
            cfstr += s
            // 若 `较长字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较长字符串` 不可能被 `测试字符串` 整除
            // 若 `较短字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较短字符串` 不可能被 `测试字符串` 整除
            // 若长度能被整除,整除得到的倍数称之为 `times1` `times2`
            // 使 `测试字符串长度` 复制 `times1` `次、times1` 次
            // 若分别能等于 `较长字符串` 、 `较短字符串` 则满足 `公因数字符串` ,将该 `公因数字符串` 存起来,继续循环
            if (cfstr.repeat(s1len / cfstr.length) === str1 && cfstr.repeat(s2len / cfstr.length) === str2)  list.push(cfstr)
        }
        // 最后一个 `公因数字符串` 既是 `最大公因数字符串`
        return list.pop() || ''
    }
    

    渐进题解 2

    // 用时一般,内存消耗一般
    执行用时: 52 ms
    内存消耗: 33.9 MB
    let gcdOfStrings = function(str1, str2) {
        // 使得 str2 是较短字符串
        if (str1.length < str2.length) {
            [str1, str2] = [str2, str1]
        }
        let s1len = str1.length
        let s2len = str2.length
        let cfstr = '' // 测试字符串
        let cflen = s2len // 测试字符串长度
        let times = 1 // 倍数
        while(times < s2len) {
            // 根据题目 S = N * T
            // 使用较短字符串截取 自身 、 自身一半 、自身四分之一 ...
            // 得到 `测试字符串`
            cfstr = str2.slice(0, cflen / times)
    
            // 若 `较长字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较长字符串` 不可能被 `测试字符串` 整除
            // 若 `较短字符串的长度` 不能被 `测试字符串长度` 整除,那这个 `较短字符串` 不可能被 `测试字符串` 整除
            // 若长度能被整除,整除得到的倍数称之为 `times1` `times2`
            // 使 `测试字符串长度` 复制 `times1` `次、times1` 次
            // 若分别能等于 `较长字符串` 、 `较短字符串` 则满足 `公因数字符串`
            // 因为是使用 `尽可能取最大公因数字符串` 的方法去测试验证的,所以只要满足条件,就是 `最大公因数字符串`
            // 此时的 `公因数字符串` 就是 `最大公因数字符串` 
            if (cfstr.repeat(s1len / cfstr.length) === str1 && cfstr.repeat(s2len / cfstr.length) === str2)  return cfstr
            times++
        }
        return ''
    }
    

    力扣教好题解

    // 用时一般,内存消耗一般
    执行用时: 64 ms
    内存消耗: 33.8 MB
    
    // 辗转相除法
    // 定理:gcd(a, b) = gcd(b, a % b)
    // 而任何数与0的最大公约数是它本身 (递归终止条件)
    
    // 更相减损术
    // 原理:gcd(a, b) = gcd(b, a - b)
    // 两个正整数 a 和 b(a > b),它们的最大公约数等于 a - b 的差值c和较小数b的最大公约数
    const gcd = (a, b) => {
        return b === 0 ? a : gcd(b, a % b)
    }
    let gcdOfStrings = function(str1, str2) {
        // 若满足都能被 X 除尽,那么这两个字符串 正序与反序相加的结果应该相等
        if (str1 + str2 !== str2 + str1) return ''
        // 使用辗转相除法得到最大公因数,对随便一个字符串进行截取即可得到 X
        return str1.slice(0, gcd(str1.length, str2.length)) 
    }
    

  • 相关阅读:
    阿里云(一)云存储OSS的命令行osscmd的安装和使用
    Zephir入门教程一
    【转载】视频CDN技术原理与流程说明
    博客园页面css样式
    Linux使用imagemagick的convert命令压缩图片、节省服务器空间
    WebSockets Tutorial(教程一)WebSockets简介
    ngx_lua_API 指令详解(四)ngx.exec指令
    Git与GitHub学习笔记(二)提交的一些笔记
    这些万能的文献检索工具,你用了几个?
    干货||科研收藏夹必备35个学术网址
  • 原文地址:https://www.cnblogs.com/linjunfu/p/12785948.html
Copyright © 2020-2023  润新知