Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
查找字符串数组中的最长公共前缀
输入: strs = ["flower","flow","flight"]
输出: "fl"
二、思路分析:
我们要计算公共前缀,可以用第一个字符串作为参数物,挨个和其他字符串进行比较。当发现第一个字符串的某个字符和其他字符不相等时,说明这个位置就是分界线了。
function longestCommonPrefix(strs) {
if (strs == null || strs.length == 0) {
return ''
}
for (let i = 0; i < strs[0].length; i++) {
let c = strs[0][i]
for (let j = 1; j < strs.length; j++) {
if (i === strs[j].length || strs[j][i] !== c) {
return strs[0].substring(0, i)
}
}
}
return strs[0]
}
该算法的时间复杂度:O(mn)
除了使用挨个字符扫描的形式,我们还可以使用二分查找的方法。
function longestCommonPrefix(strs) {
if (strs == null || strs.length == 0) {
return ''
}
// 最短字符串的长度
let minLength = Number.MAX_VALUE
for (let i = 0; i < strs.length; i++) {
minLength = Math.min(minLength, strs[i].length)
}
// 二分查找
let low = 0;
let high = minLength
while (low < high) {
let mid = (high + low) >> 1
if (isCommonPrefix(strs, mid)) {
low = mid + 1
} else {
high = mid - 1
}
}
return strs[0].substring(0, low)
}
function isCommonPrefix(strs, length) {
let str0 = strs[0].substring(0, length)
let count = strs.length
for (let i = 1; i < count; i++) {
let str = strs[i]
for (let j = 0; j < length; j++) {
if (str0[j] !== str[j]) {
return false
}
}
}
return true
}
最长公共字符会在0到最短字符串长度之间[0, minLength],所以我们可以根据[0, minLength]做二分查找。时间复杂度:O(mnlogm)
每次取查找范围的中间值mid,判断每个字符串的长度为mid的前缀是否相同,如果相同则最长公共前缀的长度一定大于或等于mid,如果不相同则最长公共前缀的长度一定小于 mid
四、总结:
二分查找是面试中最容易出现的题目,所以大家一定要提前掌握。二分查找法虽然简单,但写好它并没有那么容易,比如不能很好的判断边界条件,可能出现错误的结果或者出现死循环。
var searchInsert = function (arr, x) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
let mid = (left + right) >> 1
if (arr[mid] === x) { // x=a[n/2]
return mid
}else if (x < arr[mid]) { // x<a[n/2]
right = mid - 1
} else { // x>a[n/2]
left = mid + 1
}
}
return -1
}
上面代码用来查找一个数字在有序数组中的索引位置。