14. 最长公共前缀
思路:
这题是找最长的公共前缀。
既然是公共前缀,那长度最大也就是这个字符串列表中最短的那个字符串的长度。
一个朴素的思路就是先假定这个最大长度是1,然后不断的增加长度,求出来最长的公共前缀。但是这样算法复杂度太高了。是O(n2)的.
另外一个思路就是二分。下标是有序的,且会出现一个临界值,使得str.substring(0, i)是最大公共前缀,而str.substring(0, i+1)不是最大公共前缀,所以可以用二分来解决。
关于这种寻找范围的二分(非传统二分),我们怎么判定边界条件,怎么判断下标移动的方向呢?
我们需要考虑两点:
1. 我们要找的点在不在当前区间,不在的话直接丢弃掉。
2. 我们要找的点,当left==right==mid时,命中了if还是else?所以后续满足条件的是哪个值?
想清楚这两点,二分算法就好写多了。
1 /** 2 * @param {string[]} strs 3 * @return {string} 4 * 5 * 6 */ 7 var longestCommonPrefix = function(strs) { 8 let res = ''; 9 let min_length = 300; 10 strs.forEach(function (value, index, array) { 11 min_length = Math.min(min_length, value.length); 12 }); 13 let realIdx = binarySearch(min_length, strs[0].substring(0, min_length+1), strs); 14 res = strs[0].substring(0, realIdx+1); 15 return res; 16 }; 17 function binarySearch(length, temp_str, strs) { 18 // 二分加快查找速度 19 let left = 0, right = length-1, mid; 20 while(left <= right){ 21 mid = Math.floor(Math.floor((left+right)/2)); 22 // console.log(mid); 23 let tmp_prefix = temp_str.substring(0, mid+1); 24 // console.log(tmp_prefix); 25 if(is_right(strs, tmp_prefix)){ 26 left = mid + 1; 27 }else{ 28 right = mid - 1; 29 } 30 } 31 return right; 32 } 33 function is_right(strs, str) { 34 // 把判定逻辑单独抽出来提高代码可读性 35 let flag = true; 36 strs.forEach(function (value) { 37 if(!value.startsWith(str)){ 38 flag = false; 39 } 40 }); 41 return flag; 42 }