【LeetCode分享】寻找公共最长前缀

题目14. 寻找公共最长前缀

题目描述

要求: 编写一个函数来查找字符串数组中的最长公共前缀。

            如果不存在公共前缀,返回空字符串 `""`。
示例
输入:strs = ["flower","flow","flight"]
输出:"fl"

思路1. 横向搜索

我们可以遍历字符串数组,字符串两两进行比较,找出其中的公共前缀,在比较过程中,公共前缀长度不会增加,只会保持不变或者递减,当变为0时,说明没有公共前缀,此时返回”“。若字符串数组长度为1,则直接返回第一个元素即可。

例如
寻找strs = ['flower','flow','flight','flat']的最长前缀。

1. 比较flower和flow这两个字符串,找出公共前缀flow
2. 将上一次的公共前缀flow与flight进行比较,找出公共前缀fl
3. 将上一次的公共前缀fl与flat进行比较,找出公共前缀fl
4. 遍历结束,返回公共前缀fl

下面是JavaScript实现

/**
 * 思路:
 * 两两比较,找出最长的公共前缀,然后这个公共前缀和下一个词比较
 * 只要公共前缀不为空,且没有到最后一个词,就继续比较,否则停止,并返回前缀
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function (strs) {
    let commonPrefix = ''
    let count = strs.length 
    let prefixPerTime = strs[0]
    for (let i = 1; i < count; i++) {
        let a = prefixPerTime
        let b = strs[i]
        prefixPerTime = findCommonPrefix(a, b)
        if (prefixPerTime.length === 0) {
            return ''
        }
    }
    commonPrefix = prefixPerTime
    return commonPrefix
}

/**
 * 找出公共前缀
 * @param {string} a
 * @param {string} b
 * @return {string}
 */
function findCommonPrefix(a, b) {
    let len = Math.min(a.length, b.length)
    let subStr = a.substring(0, len)
    for (let i = 0; i < len; i++) {
        if (a[i] !== b[i]) {
            return a.substr(0, i)
        }
    }
    return subStr.substring(0, len)
}

思路2 纵向搜索

我们可以将所有字符串纵向排列,从下标0开始遍历每个字符,假设索引为index,当我们发现index为某个值的时候,字符不唯一,则停止遍历,返回公共前缀。

例如
寻找strs = ['flower','flow','flight','flat']的最长前缀。

1. 将所有字符串纵向排列,并用最短的字符串长度为基准,进行截断。
flow
flow
flig
flat
2.从左到右遍历每个字符,找到出现不同字符的那一列的下标index。
3.公共前缀就是下标从0到index-1的子串

下面是JavaScript实现

/**
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function (strs) {
    let count = strs.length
    let commonPrefix = []
    let len = strs[0].length
    for(let i = 0 ; i < len ; i++) {
        let c = strs[0][i]
        for(let k = 1 ; k <count;k++) {
            let c_ = strs[k][i]
            if(c !== c_) {
                return commonPrefix.join('')
            }
        }
        commonPrefix.push(c)
    }
    return commonPrefix.join('')
}

思路3 二分搜索

同纵向搜索,我们首先也是将所有字符串纵向排列,不过在搜索最长公共前缀右边界的时候,可以不用依次遍历的方式,而采用二分搜索的方法。找到一个中心点,左侧如果字符串相同则右边界在右侧,反之在左侧。确定一侧后再次进行二分搜索,不断找下去,即可找到右边界。

例如
寻找strs = ['flower','flow','flight','flat']的最长前缀。
  1. 统一字符串长度,即取最小的字符串的长度为统一长度(公共前缀长度必然小等于该值),此处minLen=4

  2. 将所有字符串按照统一长度截断后,纵向排列,即

    ['flow','flow','flig','flat']
    
  3. 进行二分搜索,确定中心点 mid = (high - low) / 2 + low = 1,并确定low <= high

  4. 验证字符串的子串[0,1]是否相同,此处都为fl

  5. low = mid + 1=2重新回到步骤3(若不相同则取high = mid - 1重新回到步骤3)

  6. 此时验证子串[2,3]发现不同,停止。

  7. 返回公共前缀,索引为[0,2)[0,low)
    下面是JavaScript实现

/**
 * 采用二分法找到最长公共前缀
 * 1. 首先确定所有字符串的最小长度minLen
 * 2. 在0~minLen区间上二分查找,如果0~mid相同,则前缀在mid右边,反之在左
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function (strs) {
    if (strs == null || strs.length === 0) {
        return ''
    }
    if (strs.length === 1) return strs[0]
    let minLen = strs[0].length
    for (let str of strs) {
        minLen = Math.min(str.length, minLen)
    }
    // 进行二分查找
    let low = 0,
        high = minLen - 1
    while (low <= high) {
        let mid = Math.floor((high - low) / 2) + low
        if (isEqual(strs, low, mid)) {
            low = mid + 1
        } else {
            high = mid - 1
        }
    }
    return strs[0].substring(0, low)
}

/**
 * 判断字符数组中所有字符是否相同
 * @param {string[]} strs
 * @param {number} low
 * @param {number} high
 * @return {boolean}
 */
function isEqual(strs, low, high) {
    let prefix = strs[0].substring(low, high + 1)
    for (let i = 1; i < strs.length; i++) {
        if (prefix !== strs[i].substring(low, high + 1)) {
            return false
        }
    }
    return true
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容