题目
示例 1:
输入: ["flower","flow","flight"]
输出: "fl"
示例 2:
输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
解法一:暴力解法
思路
(1)找到字符串数组中字符串最短的长度
(2)循环截取每个字符串放到数组中,循环(1)获取的最短长度,在对每个list去重
(3)如果list去完重以后的长度为1,则说明是公共字符串,否者退出循环,返回
代码
/**
* 解法一:
* (1)找到字符串数组中字符串最短的长度
* (2)循环截取每个字符串放到数组中,循环(1)获取的最短长度,在对每个list去重
* (3)如果list去完重以后的长度为1,则说明是公共字符串,否者退出循环,返回
* @param strs
* @return
*/
public static String longestCommonPrefix_1(String[] strs) {
if(strs.length == 0){
return "";
}
//获取最短长度
int min_length = strs[0].length();
for (int i = 1; i < strs.length; i++) {
if(strs[i].length() < min_length){
min_length = strs[i].length();
}
}
//计算公共数组
List ll = new ArrayList();
for(int i = 0;i<min_length;i++){
List ss = new ArrayList<>();
for(int j = 0;j < strs.length;j++) {
String str = strs[j];
ss.add(str.charAt(i));
}
//java8新特性去重, ss--> ['f','f','f'] --> ['f'] -->公共前缀
ll.add(ss.stream().distinct().collect(Collectors.toList()));
}
//拼接公共字符串
String same_str= "";
for(int i = 0;i < ll.size();i++){
if(((List)ll.get(i)).size() == 1){
same_str += ((List)ll.get(i)).get(0);
}else{
break;
}
}
return same_str;
}
结果
解法二:横向扫描
思路
(1)初始化same_str为字符串数组的第一个字符串
(2)从下标1开始依次遍历字符串数组中的字符串,每次遍历和最长公共前缀same_str比较,找出他们之间的公共前缀放置到temporary_str中, 如果比较不相等把零时字符串赋值给same_str,退出循环
(3)遍历完same_str为最长的公共字符串
代码
/**
* 解法二:
* 横向扫描
* (1)初始化same_str为字符串数组的第一个字符串
* (2)从下标1开始依次遍历字符串数组中的字符串,每次遍历和最长公共前缀same_str比较,找出他们之间的公共前缀放置到temporary_str中,
* 如果比较不相等把零时字符串赋值给same_str,退出循环
* (3)遍历完same_str为最长的公共字符串
* @param strs
* @return
*/
public static String longestCommonPrefix_2(String[] strs){
if(strs.length == 0){
return "";
}
//默认初始的最长公共前缀为字符串数组的第一个
String same_str = strs[0];
for (int i = 1; i < strs.length ; i++) {
int min_length = same_str.length() < strs[i].length() ? same_str.length():strs[i].length();
//定义零时字符串,放置公共前缀
String temporary_str = "";
for (int j = 0; j < min_length ; j++) {
if(same_str.charAt(j) == strs[i].charAt(j)){
temporary_str += same_str.charAt(j);
}else{
break;
}
}
same_str = temporary_str;
}
return same_str;
}
结果
解法三:纵向扫描
思路
(1)获取字符串数组中最短字符串的长度,这个长度就是纵向扫描的次数,及i列
(2)纵向扫描第一轮:遍历字符串数组,两两的字符串的第i列比较,如果相等赋值给ch,一轮下来都相等,则是公共字符串,如果不相等,返回当前的最长公共前缀
代码
/**
*解法三:
* 纵向扫描
* (1)获取字符串数组中最短字符串的长度,这个长度就是纵向扫描的次数,及i列
*(2)纵向扫描第一轮:遍历字符串数组,两两的字符串的第i列比较,如果相等赋值给ch,一轮下来都相等,则是公共字符串
* 如果不相等,返回当前的最长公共前缀
* @param strs
* @return
*/
public static String longestCommonPrefix_3(String[] strs){
if(strs.length == 0){
return "";
}
//如果数组只有一个字符串
if(strs.length == 1){
return strs[0];
}
//获取最短长度
int min_length = strs[0].length();
for (int i = 1; i < strs.length; i++) {
if(strs[i].length() < min_length){
min_length = strs[i].length();
}
}
String same_str = "";
//纵向扫描
for (int i = 0; i < min_length ; i++) {
char ch = ' ';
for (int j = 0; j < strs.length - 1; j++) {
//第j行第i列,两两比较
if(strs[j].charAt(i) == strs[j+1].charAt(i)){
ch = strs[j].charAt(i);
}else{
//如果纵向扫描有不相等的,就返回当前的最长公共前缀
return same_str;
}
}
same_str += ch;
}
return same_str;
}
结果
解法四:分治法
思路
(1)把问题分解为两个子问题,先求出两个子问题的最长公共前缀
(2)最后求把两个子问题得到的最长公共前缀即为最长公共前缀
代码
/**
* 解法4:
* 分治思想
* (1)把问题分解为两个子问题,先求出两个子问题的最长公共前缀
* (2)最后求把两个子问题得到的最长公共前缀即为最长公共前缀
* @param strs
* @return
*/
public static String longestCommonPrefix_4(String[] strs){
if(strs == null || strs.length == 0){
return "";
}else{
return longestCommonPrefix_4(strs,0,strs.length - 1);
}
}
public static String longestCommonPrefix_4(String[] strs,int start,int end){
if(start == end){
return strs[start];
}else{
//计算mid
int mid = (end - start)/2 + start;
//递归调用
String left = longestCommonPrefix_4(strs,start,mid);
String right = longestCommonPrefix_4(strs,mid+1,end);
return commonPrefix_4(left,right);
}
}
//取两个字符串公共前缀
public static String commonPrefix_4(String left,String right){
int min_length = Math.min(left.length(),right.length());
for (int i = 0; i < min_length; i++) {
if(left.charAt(i) != right.charAt(i)){
return left.substring(0,i);
}
}
return left.substring(0,min_length);
}
结果
总结
要善于发散思维,学会用不同思维方式想问题,从而让问题越来越简单化。