使用二分搜索的最长公共前缀
给定一组字符串,找出最长的公共前缀。
Input : {“geeksforgeeks”, “geeks”, “geek”, “geezer”}
Output : "gee"
Input : {"apple", "ape", "april"}
Output : "ap"
Input : {"abcd"}
Output : "abcd"
以前的方法——字符字符、分而治之
在本文中,讨论了一种使用二分搜索的方法。
脚步:
- 找到具有最小长度的字符串。设此长度为L 。
- 对任何一个字符串(从字符串的输入数组)执行二进制搜索。让我们取第一个字符串并对索引中的字符进行二进制搜索 - 0 到 L-1 。
- 最初,取low = 0 和 high = L-1并将字符串分成两半——左(低到中)和右(中+1到高) 。
- 检查左半部分的所有字符是否存在于所有字符串的相应索引(低到中)处。如果它存在,那么我们将这一半附加到我们的前缀字符串中,我们查看右半部分以希望找到更长的前缀。(保证有一个公共前缀字符串。)
- 否则,如果左半部分的所有字符都不存在于所有字符串的相应索引处(从低到中),那么我们不需要查看右半部分,因为左半部分本身存在一些字符不是最长前缀字符串的一部分。所以我们确实看了一下左半部分,希望能找到一个共同的前缀字符串。 (我们可能没有找到任何公共前缀字符串)
考虑字符串的算法插图 - “geeksforgeeks”,“geeks”,“geek”,“geezer”
下面是上述方法的实现。
C++
// A C++ Program to find the longest common prefix
#include
using namespace std;
// A Function to find the string having the minimum
// length and returns that length
int findMinLength(string arr[], int n)
{
int min = INT_MAX;
for (int i=0; i<=n-1; i++)
if (arr[i].length() < min)
min = arr[i].length();
return(min);
}
bool allContainsPrefix(string arr[], int n, string str,
int start, int end)
{
for (int i=0; i<=n-1; i++)
for (int j=start; j<=end; j++)
if (arr[i][j] != str[j])
return (false);
return (true);
}
// A Function that returns the longest common prefix
// from the array of strings
string commonPrefix(string arr[], int n)
{
int index = findMinLength(arr, n);
string prefix; // Our resultant string
// We will do an in-place binary search on the
// first string of the array in the range 0 to
// index
int low = 0, high = index;
while (low <= high)
{
// Same as (low + high)/2, but avoids overflow
// for large low and high
int mid = low + (high - low) / 2;
if (allContainsPrefix (arr, n, arr[0], low, mid))
{
// If all the strings in the input array contains
// this prefix then append this substring to
// our answer
prefix = prefix + arr[0].substr(low, mid-low+1);
// And then go for the right part
low = mid + 1;
}
else // Go for the left part
high = mid - 1;
}
return (prefix);
}
// Driver program to test above function
int main()
{
string arr[] = {"geeksforgeeks", "geeks",
"geek", "geezer"};
int n = sizeof (arr) / sizeof (arr[0]);
string ans = commonPrefix(arr, n);
if (ans.length())
cout << "The longest common prefix is "
<< ans;
else
cout << "There is no common prefix";
return (0);
}
Java
// A Java Program to find the longest common prefix
class GFG {
// A Function to find the string having the
// minimum length and returns that length
static int findMinLength(String arr[], int n)
{
int min = Integer.MAX_VALUE;
for (int i = 0; i <= (n - 1); i++)
{
if (arr[i].length() < min) {
min = arr[i].length();
}
}
return min;
}
static boolean allContainsPrefix(String arr[], int n,
String str, int start, int end)
{
for (int i = 0; i <= (n - 1); i++)
{
String arr_i = arr[i];
for (int j = start; j <= end; j++)
if (arr_i.charAt(j) != str.charAt(j))
return false;
}
return true;
}
// A Function that returns the longest common prefix
// from the array of strings
static String commonPrefix(String arr[], int n)
{
int index = findMinLength(arr, n);
String prefix = ""; // Our resultant string
// We will do an in-place binary search on the
// first string of the array in the range 0 to
// index
int low = 0, high = index-1;
while (low <= high) {
// Same as (low + high)/2, but avoids
// overflow for large low and high
int mid = low + (high - low) / 2;
if (allContainsPrefix(arr, n, arr[0], low,
mid))
{
// If all the strings in the input array
// contains this prefix then append this
// substring to our answer
prefix = prefix + arr[0].substring(low,
mid + 1);
// And then go for the right part
low = mid + 1;
}
else // Go for the left part
{
high = mid - 1;
}
}
return prefix;
}
// Driver program to test above function
public static void main(String args[])
{
String arr[] = {"geeksforgeeks", "geeks",
"geek", "geezer"};
int n = arr.length;
String ans = commonPrefix(arr, n);
if (ans.length() > 0)
System.out.println("The longest common"
+ " prefix is " + ans);
else
System.out.println("There is no common"
+ " prefix");
}
}
// This code is contributed by Indrajit Sinha.
Python3
# A Python3 Program to find
# the longest common prefix
# A Function to find the string having the
# minimum length and returns that length
def findMinLength(strList):
return len(min(arr, key = len))
def allContainsPrefix(strList, str,
start, end):
for i in range(0, len(strList)):
word = strList[i]
for j in range(start, end + 1):
if word[j] != str[j]:
return False
return True
# A Function that returns the longest
# common prefix from the array of strings
def CommonPrefix(strList):
index = findMinLength(strList)
prefix = "" # Our resultant string
# We will do an in-place binary search
# on the first string of the array
# in the range 0 to index
low, high = 0, index - 1
while low <= high:
# Same as (low + high)/2, but avoids
# overflow for large low and high
mid = int(low + (high - low) / 2)
if allContainsPrefix(strList,
strList[0], low, mid):
# If all the strings in the input array
# contains this prefix then append this
# substring to our answer
prefix = prefix + strList[0][low:mid + 1]
# And then go for the right part
low = mid + 1
else:
# Go for the left part
high = mid - 1
return prefix
# Driver Code
arr = ["geeksforgeeks", "geeks",
"geek", "geezer"]
lcp = CommonPrefix(arr)
if len(lcp) > 0:
print ("The longest common prefix is " +
str(lcp))
else:
print ("There is no common prefix")
# This code is contributed by garychan8523
C#
// C# Program to find the longest common prefix using System;
using System;
public class GFG {
// A Function to find the string having the
// minimum length and returns that length
static int findMinLength(string []arr, int n)
{
int min = int.MaxValue;
for (int i = 0; i <= (n - 1); i++)
{
if (arr[i].Length < min) {
min = arr[i].Length;
}
}
return min;
}
static bool allContainsPrefix(string []arr, int n,
string str, int start, int end)
{
for (int i = 0; i <= (n - 1); i++)
{
string arr_i = arr[i];
for (int j = start; j <= end; j++)
if (arr_i[j] != str[j])
return false;
}
return true;
}
// A Function that returns the longest common prefix
// from the array of strings
static string commonPrefix(string []arr, int n)
{
int index = findMinLength(arr, n);
string prefix = ""; // Our resultant string
// We will do an in-place binary search on the
// first string of the array in the range 0 to
// index
int low = 0, high = index;
while (low <= high) {
// Same as (low + high)/2, but avoids
// overflow for large low and high
int mid = low + (high - low) / 2;
if (allContainsPrefix(arr, n, arr[0], low,
mid))
{
// If all the strings in the input array
// contains this prefix then append this
// substring to our answer
prefix = prefix + arr[0].Substring(low,
mid + 1);
// And then go for the right part
low = mid + 1;
}
else // Go for the left part
{
high = mid - 1;
}
}
return prefix;
}
// Driver program to test above function
public static void Main()
{
string []arr = {"geeksforgeeks", "geeks",
"geek", "geezer"};
int n = arr.Length;
string ans = commonPrefix(arr, n);
if (ans.Length > 0)
Console.WriteLine("The longest common"
+ " prefix is - " + ans);
else
Console.WriteLine("There is no common"
+ " prefix");
}
}
// This code is contributed by PrinciRaj1992
Javascript
输出 :
The longest common prefix is - gee
时间复杂度:
递归关系为
T(M) = T(M/2) + O(MN)
在哪里
N = Number of strings
M = Length of the largest string