【经典算法】LeetCode14:最长公共前缀(Java/C/Python3实现含注释说明)

news2025/1/17 23:01:17

最长公共前缀

  • 题目
  • 思路及实现
    • 方式一:横向扫描
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
      • 复杂度分析
    • 方式二:纵向扫描
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
      • 复杂度分析
    • 方式三:分治
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
      • 复杂度分析
    • 方式四:二分查找
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
      • 复杂度分析
  • 总结
  • 相似题目

  • 标签:字符串处理、前缀判断

题目

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

如果不存在公共前缀,返回空字符串 ""。

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
提示:

1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i] 仅由小写英文字母组成

原题:LeetCode 14

思路及实现

方式一:横向扫描

思路

在这里插入图片描述

在这里插入图片描述

代码实现

Java版本
class Solution {
    public String longestCommonPrefix(String[] strs) {
        // 如果字符串数组为空或者长度为0,则返回空字符串
        if (strs == null || strs.length == 0) {
            return "";
        }

        // 将第一个字符串作为前缀进行初始化
        String prefix = strs[0];

        // 数组中字符串的数量
        int count = strs.length;

        // 遍历字符串数组,依次求取最长公共前缀
        for (int i = 1; i < count; i++) {
            prefix = longestCommonPrefix(prefix, strs[i]);

            // 如果最长公共前缀为空,则可以提前结束循环
            if (prefix.length() == 0) {
                break;
            }
        }

        // 返回最长公共前缀
        return prefix;
    }

    // 求取两个字符串的最长公共前缀
    public String longestCommonPrefix(String str1, String str2) {
        // 获取两个字符串的最小长度
        int length = Math.min(str1.length(), str2.length());

        // 初始化索引
        int index = 0;

        // 遍历两个字符串,找到最长公共前缀的结束索引
        while (index < length && str1.charAt(index) == str2.charAt(index)) {
            index++;
        }

        // 返回最长公共前缀
        return str1.substring(0, index);
    }
}

说明:
首先,通过判断字符串数组strs是否为空或长度为0,来确定是否存在最长公共前缀。如果数组为空或长度为0,则直接返回空字符串。
将字符串数组中的第一个字符串作为初始化的最长公共前缀prefix。
使用一个循环遍历剩余的字符串,依次计算最长公共前缀。在每次循环中,调用longestCommonPrefix()方法,将当前最长公共前缀prefix和当前遍历的字符串进行比较,更新最长公共前缀。
如果最长公共前缀为空字符串,则说明不存在公共前缀,无需继续循环,直接跳出。 最后,返回最长公共前缀prefix。
longestCommonPrefix()方法是一个内部方法,用于找到两个字符串str1和str2的最长公共前缀。
首先,获取两个字符串的最小长度length。 初始化索引index为0。
遍历两个字符串,比较对应位置的字符是否相等,直到遇到不相等的字符或到达较短字符串的末尾。
最后,返回前缀部分的字符串,即str1中的前index个字符。

C语言版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* longestCommonPrefix(char** strs, int strsSize) {
    // 如果字符串数组为空或者长度为0,则返回空字符串
    if (strs == NULL || strsSize == 0)
        return "";

    // 将第一个字符串作为初始的最长公共前缀
    char* prefix = strs[0];

    // 遍历数组剩余的字符串,更新最长公共前缀
    for (int i = 1; i < strsSize; i++) {
        prefix = lcp(prefix, strs[i]);
        
        // 如果最长公共前缀为空,则跳出循环
        if (prefix[0] == '\0')
            break;
    }
    
    return prefix;
}

说明:
longestCommonPrefix() 函数用于找到字符串数组 strs 中的最长公共前缀。
首先,判断字符串数组是否为空或长度为0,如果是,则直接返回空字符串。 将数组的第一个字符串作为初始的最长公共前缀 prefix。
遍历数组剩余的字符串,调用 lcp() 函数计算当前字符串与当前最长公共前缀的公共前缀,并更新最长公共前缀 prefix。
如果最长公共前缀为空字符串,则无需继续遍历,跳出循环。 返回最长公共前缀 prefix。 lcp() 函数用于找到两个字符串 str1 和str2 的最长公共前缀。 获取两个字符串的最小长度 length。 初始化索引 index 为0。
遍历两个字符串,比较对应位置的字符是否相等,直到遇到不相等的字符或到达较短字符串的末尾。 创建一个新的字符串来存储最长公共前缀commonPrefix。
使用 strncpy() 函数从 str1 复制 index 个字符到 commonPrefix 中。 在
commonPrefix 的末尾添加字符串结束符 ‘\0’。 返回最长公共前缀 commonPrefix。

Python3版本
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        # 如果字符串数组为空,则返回空字符串
        if not strs:
            return ""
        
        # 将数组的第一个字符串作为初始的最长公共前缀
        prefix, count = strs[0], len(strs)
        
        # 遍历数组剩余的字符串,更新最长公共前缀
        for i in range(1, count):
            prefix = self.lcp(prefix, strs[i])
            
            # 如果最长公共前缀为空,则跳出循环
            if not prefix:
                break
        
        return prefix
    
    # 求取两个字符串的最长公共前缀
    def lcp(self, str1, str2):
        # 获取两个字符串的最小长度
        length, index = min(len(str1), len(str2)), 0
        
        # 遍历两个字符串,找到最长公共前缀的结束索引
        while index < length and str1[index] == str2[index]:
            index += 1
        
        # 返回最长公共前缀
        return str1[:index]

说明:
longestCommonPrefix()方法是一个类方法,用于找到字符串数组strs中的最长公共前缀。
首先,判断字符串数组是否为空,如果为空,则直接返回空字符串。 将数组的第一个字符串作为初始的最长公共前缀 prefix。
获取数组中的字符串数量 count。 使用一个循环遍历剩余的字符串,调用 lcp()
方法来计算当前字符串与当前最长公共前缀的公共前缀,并更新最长公共前缀 prefix。 如果最长公共前缀为空字符串,则无需继续遍历,跳出循环。
返回最长公共前缀 prefix。 lcp() 方法是一个类方法,用于找到两个字符串 str1 和 str2 的最长公共前缀。
获取两个字符串的最小长度 length。 初始化索引 index 为0。
遍历两个字符串,比较对应位置的字符是否相等,直到遇到不相等的字符或到达较短字符串的末尾。 返回前缀部分的字符串,即 str1 中的前
index 个字符。

复杂度分析

  • 时间复杂度:O(mn),其中 m 是字符串数组中的字符串的平均长度,n 是字符串的数量。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。
  • 空间复杂度:O(1)。使用的额外空间复杂度为常数。

方式二:纵向扫描

思路

方法一是横向扫描,依次遍历每个字符串,更新最长公共前缀。另一种方法是纵向扫描。纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,如果不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。
在这里插入图片描述

代码实现

Java版本
class Solution {
    public String longestCommonPrefix(String[] strs) {
        // 如果字符串数组为空或者长度为0,直接返回空字符串
        if (strs == null || strs.length == 0) {
            return "";
        }

        // 获取第一个字符串的长度和数组的长度
        int length = strs[0].length();
        int count = strs.length;

        // 遍历第一个字符串的每个字符
        for (int i = 0; i < length; i++) {
            char c = strs[0].charAt(i);

            // 遍历剩余的字符串进行比较
            for (int j = 1; j < count; j++) {
                // 如果当前字符已经超过了某个字符串的长度,或者当前字符不等于其他字符串对应位置的字符,返回前缀部分
                if (i == strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);
                }
            }
        }

        // 返回第一个字符串作为最长公共前缀
        return strs[0];
    }
}

说明:
longestCommonPrefix() 方法用于寻找字符串数组 strs 中的最长公共前缀。
如果字符串数组为空或长度为0,直接返回空字符串。 获取第一个字符串的长度和字符串数组的长度。 遍历第一个字符串的每个字符。 获取当前字符
c,用来与其他字符串的对应位置字符进行比较。 遍历剩余的字符串,依次比较当前字符和其他字符串对应位置的字符。
如果当前字符已经超过了某个字符串的长度,或者当前字符不等于其他字符串对应位置的字符,返回前缀部分,即第一个字符串的从索引0到当前位置的子串。
返回第一个字符串作为最长公共前缀,因为该字符串是其他字符串的公共前缀。

C语言版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 函数声明
char* longestCommonPrefix(char** strs, int strsSize);
char* commonPrefix(char* str1, char* str2);

/**
int main() {
    char* strs[] = {"flower", "flow", "flight"};
    int strsSize = 3;

    char* result = longestCommonPrefix(strs, strsSize);
    printf("Longest Common Prefix: %s\n", result);

    // 释放内存
    free(result);

    return 0;
}
**/
/*
 * 获取字符串数组中的最长公共前缀
 * 参数: strs - 字符串数组, strsSize - 字符串数组的大小
 * 返回值: 最长公共前缀的指针
 */
char* longestCommonPrefix(char** strs, int strsSize) {
    // 如果字符串数组为空或者大小为0,直接返回空字符串
    if (strs == NULL || strsSize == 0) {
        return "";
    }

    // 字符串数组的第一个字符串
    char* firstStr = strs[0];

    // 获取第一个字符串的长度
    int length = strlen(firstStr);

    // 遍历第一个字符串的每个字符
    for (int i = 0; i < length; i++) {
        char c = firstStr[i];
        
        // 遍历剩余的字符串进行比较
        for (int j = 1; j < strsSize; j++) {
            // 如果当前字符已经超过了某个字符串的长度,或者当前字符不等于其他字符串对应位置的字符,返回前缀部分
            if (i >= strlen(strs[j]) || strs[j][i] != c) {
                char* prefix = (char*)malloc((i + 1) * sizeof(char));
                strncpy(prefix, firstStr, i);
                prefix[i] = '\0';
                return prefix;
            }
        }
    }

    // 返回第一个字符串作为最长公共前缀
    return strdup(firstStr);
}

/*
 * 获取两个字符串的最长公共前缀的公共前缀
 * 参数: str1 - 字符串1, str2 - 字符串2
 * 返回值: 最长公共前缀的指针
 */
char* commonPrefix(char* str1, char* str2) {
    int length1 = strlen(str1);
    int length2 = strlen(str2);

    int index = 0;
    // 比较两个字符串对应位置的字符
    while (index < length1 && index < length2 && str1[index] == str2[index]) {
        index++;
    }

    // 创建新的字符串,存储公共前缀
    char* result = (char*)malloc((index + 1) * sizeof(char));
    strncpy(result, str1, index);
    result[index] = '\0';

    return result;
}

说明
longestCommonPrefix() 函数用于找到字符串数组中的最长公共前缀。
首先判断字符串数组是否为空或大小为0。如果是,则直接返回空字符串。 获取字符串数组的第一个字符串 firstStr,并保存它的长度
length。 遍历第一个字符串的每个字符,并与剩余字符串的对应位置的字符进行比较,找到最长公共前缀。
如果当前字符已经超过了某个字符串的长度,或者当前字符不等于其他字符串对应位置的字符,就返回前缀部分。使用malloc()
函数动态分配内存,使用strncpy() 函数复制字符串,并在末尾添加结束符 ‘\0’,然后返回前缀字符串的指针。
如果遍历后没有找到不相等的字符,说明第一个字符串是最长公共前缀,返回第一个字符串的拷贝,使用strdup() 函数实现。
commonPrefix() 函数用于获取两个字符串的最长公共前缀的公共前缀。
在循环中,比较两个字符串对应位置的字符,找到不相等的位置,返回前缀部分。这里使用了与之前相同的逻辑和函数。 main() 函数中调用了
longestCommonPrefix() 函数,并打印结果最长公共前缀。余下的是释放内存的代码,避免内存泄漏。

Python3版本
def longestCommonPrefix(strs):
    # 如果字符串数组为空或长度为0,直接返回空字符串
    if not strs:
        return ""

    # 字符串数组的第一个字符串
    firstStr = strs[0]

    # 遍历第一个字符串的每个字符
    for i in range(len(firstStr)):
        c = firstStr[i]

        # 遍历剩余的字符串进行比较
        for j in range(1, len(strs)):
            # 如果当前字符已经超过了某个字符串的长度,或者当前字符不等于其他字符串对应位置的字符,返回前缀部分
            if i >= len(strs[j]) or strs[j][i] != c:
                return firstStr[:i]
    
    # 返回第一个字符串作为最长公共前缀
    return firstStr

# 调用函数并打印结果
#strs = ["flower", "flow", "flight"]
#result = longestCommonPrefix(strs)
#print("Longest Common Prefix:", result)

说明: longestCommonPrefix() 函数用于找到字符串数组中的最长公共前缀。
首先判断字符串数组是否为空。如果为空,则直接返回空字符串。 获取字符串数组的第一个字符串 firstStr。
遍历第一个字符串的每个字符,并与剩余字符串的对应位置的字符进行比较,找到最长公共前缀。
如果当前字符已经超过了某个字符串的长度,或者当前字符不等于其他字符串对应位置的字符,就返回前缀部分。 返回第一个字符串作为最长公共前缀。 在
main() 函数中,调用 longestCommonPrefix() 函数,并打印结果最长公共前缀。

复杂度分析

  • 时间复杂度:O(mn),其中 m 是字符串数组中的字符串的平均长度,n 是字符串的数量。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。
  • 空间复杂度:O(1)。使用的额外空间复杂度为常数。

方式三:分治

思路

在这里插入图片描述
在这里插入图片描述

代码实现

Java版本
class Solution {
    public String longestCommonPrefix(String[] strs) {
        // 如果字符串数组为空或者长度为0,直接返回空字符串
        if (strs == null || strs.length == 0) {
            return "";
        } else {
            return longestCommonPrefix(strs, 0, strs.length - 1);
        }
    }
    
    // 递归函数,用于求取指定范围内字符串数组的最长公共前缀
    public String longestCommonPrefix(String[] strs, int start, int end) {
        // 如果范围内只有一个字符串,则直接返回该字符串作为最长公共前缀
        if (start == end) {
            return strs[start];
        } else {
            // 计算范围中间索引
            int mid = (end - start) / 2 + start;

            // 求取左半部分和右半部分的最长公共前缀
            String lcpLeft = longestCommonPrefix(strs, start, mid);
            String lcpRight = longestCommonPrefix(strs, mid + 1, end);

            // 返回左半部分和右半部分的最长公共前缀的公共前缀
            return commonPrefix(lcpLeft, lcpRight);
        }
    }
    
    // 求取两个字符串的最长公共前缀的公共前缀
    public String commonPrefix(String lcpLeft, String lcpRight) {
        // 获取最小长度
        int minLength = Math.min(lcpLeft.length(), lcpRight.length());

        // 对比两个字符串的字符,找到不相等的位置,返回前缀部分
        for (int i = 0; i < minLength; i++) {
            if (lcpLeft.charAt(i) != lcpRight.charAt(i)) {
                return lcpLeft.substring(0, i);
            }
        }

        // 返回最小长度范围内的字符串,即最长公共前缀
        return lcpLeft.substring(0, minLength);
    }
}

说明:
longestCommonPrefix() 方法是递归函数,用于求取指定范围内字符串数组 strs 的最长公共前缀。
如果范围内只有一个字符串,则直接返回该字符串作为最长公共前缀。 否则,计算范围中间索引 mid。 调用递归函数
longestCommonPrefix() 分别求取左半部分和右半部分的最长公共前缀:lcpLeft 和 lcpRight。
返回左半部分和右半部分的最长公共前缀的公共前缀,即调用 commonPrefix() 函数。 commonPrefix()
方法用于求取两个字符串 lcpLeft 和 lcpRight 的最长公共前缀的公共前缀。 获取两个字符串的长度的最小值作为最小长度minLength。 逐个字符比较两个字符串的对应位置的字符,找到不相等的位置,返回当前位置前的子串作为最长公共前缀的公共前缀。
如果没有找到不相等的位置,返回最小长度范围内的字符串,即最长公共前缀。

C语言版本
#include <stdio.h>
#include <string.h>

// 函数声明
char* longestCommonPrefix(char** strs, int strsSize);

/*
 * 获取两个字符串的最长公共前缀
 * 参数: str1 - 字符串1, str2 - 字符串2
 * 返回值: 最长公共前缀的指针
 */
char* commonPrefix(char* str1, char* str2);
/*
 * 获取字符串数组中的最长公共前缀
 * 参数: strs - 字符串数组, strsSize - 字符串数组的长度
 * 返回值: 最长公共前缀的指针
 */
char* longestCommonPrefix(char** strs, int strsSize) {
    // 如果字符串数组为空或者长度为0,直接返回空字符串
    if (strs == NULL || strsSize == 0) {
        return "";
    }

    // 将第一个字符串作为初始的最长公共前缀
    char* prefix = strs[0];

    // 遍历剩余的字符串
    for (int i = 1; i < strsSize; i++) {
        // 更新最长公共前缀为当前遍历的字符串与最长公共前缀的公共前缀
        prefix = commonPrefix(prefix, strs[i]);

        // 如果最长公共前缀为空,说明不存在公共前缀,直接跳出循环
        if (strlen(prefix) == 0) {
            break;
        }
    }

    return prefix;
}

/*
 * 获取两个字符串的最长公共前缀的公共前缀
 * 参数: str1 - 字符串1, str2 - 字符串2
 * 返回值: 最长公共前缀的指针
 */
char* commonPrefix(char* str1, char* str2) {
    int length1 = strlen(str1);
    int length2 = strlen(str2);

    int index = 0;
    while (index < length1 && index < length2 && str1[index] == str2[index]) {
        index++;
    }

    // 创建新的字符串,存储公共前缀
    char* result = (char*)malloc((index + 1) * sizeof(char));
    strncpy(result, str1, index);
    result[index] = '\0';  // 末尾添加结束符

    return result;
}

说明:
longestCommonPrefix()函数用于找到字符串数组中的最长公共前缀。
在函数中,首先判断字符串数组是否为空或长度为0。如果是,则直接返回空字符串。 将字符串数组的第一个字符串作为初始的最长公共前缀prefix。
使用一个循环遍历剩余的字符串,分别与当前最长公共前缀进行比较,更新最长公共前缀。 如果最长公共前缀为空字符串,说明不存在公共前缀,跳出循环。
返回最长公共前缀prefix的指针。 commonPrefix()函数用于找到两个字符串的最长公共前缀的公共前缀。
在函数中,通过计算两个字符串的长度,初始化索引index为0。
使用一个循环比较两个字符串的对应位置字符,直到遇到不相等的字符或其中一个字符串的结尾。
创建一个新的字符数组result,用于存储公共前缀部分。 使用strncpy()函数将公共前缀部分复制到result中。
在result末尾添加结束符\0。 返回公共前缀result的指针。
请注意,使用malloc()动态分配了内存空间来存储结果字符串,因此在使用完毕后,记得使用free()函数释放它。

Python3版本
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        # 定义递归函数,用于求取字符串数组中指定范围内的最长公共前缀
        def lcp(start, end):
            # 如果范围中只有一个字符串,则直接返回该字符串作为最长公共前缀
            if start == end:
                return strs[start]

            # 分治法,将范围划分为两部分,分别求取左右两部分的最长公共前缀
            mid = (start + end) // 2
            lcpLeft, lcpRight = lcp(start, mid), lcp(mid + 1, end)

            # 找到左右两部分最长公共前缀的最小长度
            minLength = min(len(lcpLeft), len(lcpRight))

            # 在最小长度范围内逐个字符比较
            for i in range(minLength):
                if lcpLeft[i] != lcpRight[i]:
                    # 遇到第一个不相等的字符,返回前缀部分
                    return lcpLeft[:i]

            # 返回最小长度范围内的最长公共前缀
            return lcpLeft[:minLength]

        # 如果字符串数组为空,则返回空字符串
        return "" if not strs else lcp(0, len(strs) - 1)

说明:
使用分治法,将指定范围划分为左右两部分,分别求取它们的最长公共前缀。 计算中间索引 mid。 调用 lcp()
函数求取左半部分的最长公共前缀 lcpLeft。 调用 lcp() 函数求取右半部分的最长公共前缀 lcpRight。
找到左右两部分最长公共前缀的最小长度。 在最小长度范围内逐个字符比较左右两部分的对应位置字符。
如果遇到第一个不相等的字符,返回当前位置前的子串作为最长公共前缀。 返回最小长度范围内的最长公共前缀。 如果字符串数组为空,则返回空字符串。
否则,调用 lcp() 函数,传入起始索引0和结束索引 len(strs) - 1,求取整个字符串数组的最长公共前缀。
longestCommonPrefix() 方法是主函数,用于启动递归过程并处理边界情况。lcp() 函数是一个内部递归函数,用于求取字符串数组中指定范围内的最长公共前缀

复杂度分析

  • 时间复杂度:O(mn),其中 m 是字符串数组中的字符串的平均长度,n 是字符串的数量。时间复杂度的递推式是 T(n)=2⋅T(2n )+O(m),通过计算可得 T(n)=O(mn)。
  • 空间复杂度:O(mlogn),其中 m 是字符串数组中的字符串的平均长度,n 是字符串的数量。空间复杂度主要取决于递归调用的层数,层数最大为 logn,每层需要 m 的空间存储返回结果。

方式四:二分查找

思路

显然,最长公共前缀的长度不会超过字符串数组中的最短字符串的长度。用 minLength 表示字符串数组中的最短字符串的长度,则可以在 [0,minLength] 的范围内通过二分查找得到最长公共前缀的长度。每次取查找范围的中间值 mid,判断每个字符串的长度为 mid 的前缀是否相同,如果相同则最长公共前缀的长度一定大于或等于 mid,如果不相同则最长公共前缀的长度一定小于 mid,通过上述方式将查找范围缩小一半,直到得到最长公共前缀的长度。
在这里插入图片描述

代码实现

Java版本
class Solution {
    public String longestCommonPrefix(String[] strs) {
        // 如果字符串数组为空或长度为0,直接返回空字符串
        if (strs == null || strs.length == 0) {
            return "";
        }
        
        // 获取字符串数组中最短字符串的长度
        int minLength = Integer.MAX_VALUE;
        for (String str : strs) {
            minLength = Math.min(minLength, str.length());
        }
        
        // 使用二分查找的思路来查找最长公共前缀
        int low = 0, high = minLength;
        while (low < high) {
            // 取中间位置
            int mid = (high - low + 1) / 2 + low;
            
            // 判断中间位置的前缀是否是公共前缀
            if (isCommonPrefix(strs, mid)) {
                // 如果是,更新 low,继续查找右半部分
                low = mid;
            } else {
                // 如果不是,更新 high,继续查找左半部分
                high = mid - 1;
            }
        }
        
        // 返回最长公共前缀
        return strs[0].substring(0, low);
    }
    
    // 判断指定长度前缀是否是字符串数组的公共前缀
    public boolean isCommonPrefix(String[] strs, int length) {
        // 获取第一个字符串的指定长度前缀
        String str0 = strs[0].substring(0, length);
        int count = strs.length;
        
        // 遍历剩余的字符串,逐个比较前缀字符
        for (int i = 1; i < count; i++) {
            String str = strs[i];
            for (int j = 0; j < length; j++) {
                if (str0.charAt(j) != str.charAt(j)) {
                    return false;
                }
            }
        }
        
        // 返回是否是公共前缀的结果
        return true;
    }
}

说明:
longestCommonPrefix() 方法用于求取字符串数组 strs 中的最长公共前缀。
首先判断字符串数组是否为空或长度为0,如果是,则直接返回空字符串。 获取字符串数组中最短字符串的长度 minLength。
使用二分查找的思路来查找最长公共前缀。 维持一个区间 [low, high],初始为 [0, minLength]。
在每一次循环中,取区间的中间位置 mid。 判断以mid长度作为前缀是否是字符串数组的公共前缀,通过调用 isCommonPrefix()
方法实现。 如果是公共前缀,则更新 low = mid,继续查找右半部分。 如果不是公共前缀,则更新 high = mid -
1,继续查找左半部分。 当 low >= high 时,二分查找结束,得到最长公共前缀的长度。 返回最长公共前缀,使用
strs[0].substring(0, low) 来截取对应长度的前缀。 isCommonPrefix()
方法用于判断指定长度的前缀是否是字符串数组 strs 的公共前缀。 获取第一个字符串的指定长度前缀 str0。
遍历剩余的字符串,逐个比较前缀中的字符。 如果存在不相等的字符,说明不是公共前缀,返回 false。
如果所有字符串的前缀字符都相等,说明是公共前缀,返回 true。

C语言版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 函数声明
char* longestCommonPrefix(char** strs, int strsSize);
int isCommonPrefix(char** strs, int strsSize, int len);

/**
int main() {
    // 测试数据
    char* strs[] = {"flower", "flow", "flight"};
    int strsSize = 3;

    // 调用函数并打印结果
    char* result = longestCommonPrefix(strs, strsSize);
    printf("Longest Common Prefix: %s\n", result);

    return 0;
}
**/
/*
 * 获取字符串数组中的最长公共前缀
 * 参数: strs - 字符串数组, strsSize - 字符串数组的长度
 * 返回值: 最长公共前缀的指针
 */
char* longestCommonPrefix(char** strs, int strsSize) {
    // 如果字符串数组为空或长度为0,直接返回空字符串
    if (strs == NULL || strsSize == 0) {
        return "";
    }

    // 找出最短字符串的长度
    int minLength = INT_MAX;
    for (int i = 0; i < strsSize; i++) {
        int len = strlen(strs[i]);
        if (len < minLength) {
            minLength = len;
        }
    }

    // 使用二分法查找最长公共前缀
    int low = 1;
    int high = minLength;
    int mid = 0;
    while (low <= high) {
        mid = (low + high) / 2;
        if (isCommonPrefix(strs, strsSize, mid)) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }

    // 根据最长公共前缀的长度,创建并返回结果字符串
    char* result = (char*)malloc((mid + 1) * sizeof(char));
    strncpy(result, strs[0], mid);
    result[mid] = '\0';

    return result;
}

/*
 * 判断指定长度前缀是否是字符串数组的公共前缀
 * 参数: strs - 字符串数组, strsSize - 字符串数组的长度, len - 前缀长度
 * 返回值: 是否是公共前缀的整数值,1为是,0为否
 */
int isCommonPrefix(char** strs, int strsSize, int len) {
    for (int i = 0; i < len; i++) {
        char ch = strs[0][i];
        for (int j = 1; j < strsSize; j++) {
            if (strs[j][i] != ch) {
                return 0;
            }
        }
    }
    return 1;
}

说明:
longestCommonPrefix()函数用于找到字符串数组中的最长公共前缀。
在函数中,首先判断字符串数组是否为空或长度为0。如果是,则直接返回空字符串。 找出字符串数组中最短字符串的长度minLength。
使用二分法来查找最长公共前缀。 初始化low为1,high为最短字符串的长度minLength。 循环遍历,直到找到最长公共前缀的长度。
设置mid为low和high的中间值。 如果前缀长度为mid的前缀是字符串数组的公共前缀,则在[mid+1, high]范围继续查找。
如果前缀长度为mid的前缀不是字符串数组的公共前缀,则在[low, mid-1]范围继续查找。
根据最长公共前缀的长度mid,动态分配内存创建结果字符串result。
使用strncpy()函数将字符串数组的第一个字符串的前mid个字符复制到结果字符串中。 在结果字符串的末尾添加结束符’\0’。
返回结果字符串的指针。 请注意,在使用完结果字符串后,不要忘记使用free()函数释放分配的内存。

Python3版本
def longestCommonPrefix(strs):
    # 如果字符串数组为空或长度为0,直接返回空字符串
    if not strs:
        return ""

    # 找出最短字符串的长度
    minLength = min(len(s) for s in strs)

    # 使用二分法查找最长公共前缀
    low = 1
    high = minLength
    while low <= high:
        mid = (low + high) // 2
        if isCommonPrefix(strs, mid):
            low = mid + 1
        else:
            high = mid - 1

    # 根据最长公共前缀的长度,返回结果字符串
    return strs[0][:low]

def isCommonPrefix(strs, length):
    for i in range(length):
        ch = strs[0][i]
        for j in range(1, len(strs)):
            if strs[j][i] != ch:
                return False
    return True

# 调用函数并打印结果
#strs = ["flower", "flow", "flight"]
#result = longestCommonPrefix(strs)
#print("Longest Common Prefix:", result)

说明:
longestCommonPrefix() 函数用于找到字符串数组中的最长公共前缀。
首先判断字符串数组是否为空。如果为空,则直接返回空字符串。 找出字符串数组中最短字符串的长度 minLength,使用 min()函数和生成器表达式来实现。 使用二分法来查找最长公共前缀。 初始化 low 为 1,high 为最短字符串的长度 minLength。
循环遍历,直到找到最长公共前缀的长度。 设置 mid 为 low 和 high 的中间值。 如果前缀长度为 mid
的前缀是字符串数组的公共前缀,则在 [mid+1, high] 范围继续查找。 如果前缀长度为 mid 的前缀不是字符串数组的公共前缀,则在[low, mid-1] 范围继续查找。 根据最长公共前缀的长度 low,返回结果字符串,使用切片操作实现。
isCommonPrefix() 函数用于判断指定长度的前缀是否是字符串数组的公共前缀。
使用嵌套循环遍历前缀的每个字符,逐个比较所有字符串的对应位置字符。 如果存在不相等的字符,说明不是公共前缀,返回 False。
如果所有字符串的前缀字符都相等,说明是公共前缀,返回 True。 调用函数并打印结果,使用示例字符串数组。

复杂度分析

  • 时间复杂度:O(mnlogm),其中 m 是字符串数组中的字符串的最小长度,n 是字符串的数量。二分查找的迭代执行次数是 O(logm),每次迭代最多需要比较 mn 个字符,因此总时间复杂度是 O(mnlogm)。
  • 空间复杂度:O(1)。使用的额外空间复杂度为常数。

总结

解法思路优点缺点时间复杂度空间复杂度
横向扫描从第一个字符串作为初始公共前缀,逐个与后续字符串比较,更新公共前缀简单直观,易于理解和实现需要进行多次字符比较,时间复杂度较高O(m*n)O(1)
纵向扫描逐个字符纵向比较字符串,直到遇到不匹配的字符高效,提前结束不匹配的情况,减少不必要的比较需要对全部字符串进行纵向比较,容易漏掉一些情况O(m*n)O(1)
分治法将字符串数组分成子问题,分别求解左右两组的公共前缀,最后合并得到最长公共前缀减小了比较的次数,更加高效在字符串数组较大时,递归和合并操作可能导致额外的开销O(mnlogk)O(m*logk)
二分法将字符串数组二分,求左右两组的公共前缀,最后求两者的公共前缀大大减少了比较的次数,更加高效需要对字符串数组进行分割和合并,增加了分配内存的开销O(mnlogm)O(m)

其中,m 为字符串的平均长度,n 为字符串数组的长度,k 为字符串数组中的字符串字符最大长度。需要注意的是,在实际应用中,具体优化技巧和实现方法可能会对复杂度产生影响。因此,上述复杂度分析仅提供了一般情况下的大致估计。

相似题目

题目描述难度LeetCode链接
最长回文子串寻找给定字符串中的最长回文子串中等LeetCode 5
最长有效括号寻找给定字符串中的最长有效括号序列困难LeetCode 32
最长连续递增序列寻找给定数组中的最长连续递增子序列简单LeetCode 674
最长连续序列寻找给定数组中的最长连续序列困难LeetCode 128

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1560066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单元测试mockito(一)

1.单元测试 1.1 单元测试的特点 ●配合断言使用(杜绝System.out) ●可重复执行 。不依赖环境 ●不会对数据产生影响 ●spring的上下文环境不是必须的 ●一般都需要配合mock类框架来实现 1.2 mock类框架使用场景 要进行测试的方法存在外部依赖(如db,redis,第三方接口调用等),为…

3.31学习总结

(本次学习总结,总结了目前学习java遇到的一些关键字和零碎知识点) 一.static关键字 static可以用来修饰类的成员方法、类的成员变量、类中的内部类&#xff08;以及用static修饰的内部类中的变量、方法、内部类&#xff09;&#xff0c;另外可以编写static代码块来优化程序性…

权限问题(Windows-System)

方法&#xff1a;用命令来写一个注册表的脚本 &#xff1f;System是最高级用户&#xff0c;但不拥有最高级权限 编写两文档&#xff1a;system.reg 和 remove.reg,代码如下&#xff1a; system.reg&#xff1a; Windows Registry Editor Version 5.00[-HKEY_CLASSES_ROOT\*…

YOLOv5改进 | 低照度检测 | 2024最新改进CPA-Enhancer链式思考网络(适用低照度、图像去雾、雨天、雪天)

一、本文介绍 本文给大家带来的2024.3月份最新改进机制&#xff0c;由CPA-Enhancer: Chain-of-Thought Prompted Adaptive Enhancer for Object Detection under Unknown Degradations论文提出的CPA-Enhancer链式思考网络&#xff0c;CPA-Enhancer通过引入链式思考提示机制&am…

Proteus 12V to 5V buck电路仿真练习及遇到的一些问题汇总

基础电路仿真实验记录贴&#xff01;&#xff01;&#xff01;如有写的不对的地方欢迎交流指正&#xff01;&#xff01;&#xff01; 平台&#xff1a;PC win10 软件&#xff1a;Proteus8.10 仿真目标&#xff1a;buck降压电路&#xff08;PWM控制输出电压&#xff09; 写在…

《Lost in the Middle: How Language Models Use Long Contexts》AI 解读

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

MySQL核心命令详解与实战,一文掌握MySQL使用

文章目录 文章简介演示库表创建数据库表选择数据库删除数据库创建表删除表向表中插入数据更新数据删除数据查询数据WHERE 操作符聚合函数LIKE 子句分组 GROUP BY HAVINGORDER BY(排序) 语句LIMIT 操作符 分页查询多表查询-联合查询 UNION 操作符多表查询-连接的使用-JOIN语句编…

选择排序及其优化

目录 思想&#xff1a; 代码&#xff1a; 代码优化&#xff1a; 需要注意的特殊情况&#xff1a; 可能出现的所有特殊情况&#xff1a; 优化完成代码&#xff1a; 思想&#xff1a; 每一次遍历数组&#xff0c;选择出最大或最小的数&#xff0c;将其与数组末尾或首位进行…

Oracle Solaris 11.3开工失败问题处理记录

1、故障现像 起初是我这有套RAC有点问题&#xff0c;我想重启1个节点&#xff0c;结果发现重启后该节点的IP能PING通&#xff0c;但SSH连不上去&#xff0c;对应的RAC服务也没有自动启动。 操作系统是solaris 11.3。由于该IP对应的主机是LDOM&#xff0c;于是我去主域上telnet…

汇编语言第四版-王爽第2章 寄存器

二进制左移四位&#xff0c;相当于四进制左移一位。 debug命令实操&#xff0c;win11不能启动&#xff0c;需要配置文件 Windows64位系统进入debug模式_window10系统64位怎么使用debugger-CSDN博客

扫雷(蓝桥杯)

题目描述 小明最近迷上了一款名为《扫雷》的游戏。其中有一个关卡的任务如下&#xff0c; 在一个二维平面上放置着 n 个炸雷&#xff0c;第 i 个炸雷 (xi , yi ,ri) 表示在坐标 (xi , yi) 处存在一个炸雷&#xff0c;它的爆炸范围是以半径为 ri 的一个圆。 为了顺利通过这片土…

开源博客项目Blog .NET Core源码学习(13:App.Hosting项目结构分析-1)

开源博客项目Blog的App.Hosting项目为MVC架构的&#xff0c;主要定义或保存博客网站前台内容显示页面及后台数据管理页面相关的控制器类、页面、js/css/images文件&#xff0c;页面使用基于layui的Razor页面&#xff08;最早学习本项目就是想学习layui的用法&#xff0c;不过最…

网络安全 | 网络攻击介绍

关注wx&#xff1a;CodingTechWork 网络攻击 网络攻击定义 以未经授权的方式访问网络、计算机系统或数字设备&#xff0c;故意窃取、暴露、篡改、禁用或破坏数据、应用程序或其他资产的行为。威胁参与者出于各种原因发起网络攻击&#xff0c;从小额盗窃发展到战争行为。采用各…

C语言自定义类型

本篇文章主要介绍三种自定义类型&#xff0c;分别是&#xff1a;结构体、联合体、枚举。 一.结构体 1.结构体类型的声明 直接举一个例子&#xff1a; //一本书 struct s {char name[10]; //名称char a; //作者int p; //价格 }; 2.特殊的声明 结构体也可以不写结构体标…

NVIDIA Jetson Xavier NX入门-镜像为jetpack5(3)——pytorch和torchvision安装

NVIDIA Jetson Xavier NX入门-镜像为jetpack5&#xff08;3&#xff09;——pytorch和torchvision安装 镜像为jetpack5系列&#xff1a; NVIDIA Jetson Xavier NX入门-镜像为jetpack5&#xff08;1&#xff09;——镜像烧写 NVIDIA Jetson Xavier NX入门-镜像为jetpack5&#…

医院陪诊管理系统(源码+文档)

TOC) 文件包含内容 1、搭建视频 2、流程图 3、开题报告 4、数据库 5、参考文献 6、服务器接口文件 7、接口文档 8、任务书 9、功能图 10、环境搭建软件 11、十六周指导记录 12、答辩ppt模板 13、技术详解 14、前端后台管理&#xff08;管理端程序&#xff09; 15、项目截图 1…

CCIE-07-OSPF_TS

目录 实验条件网络拓朴逻辑拓扑实现目标 环境配置开始Troubleshooting问题1. R22的e0/0接口配置了网络类型问题2. R22和R21之间的IP地址子网掩码长度不一致问题3. R21的e0/0口配置了被动接口问题4. R3配置了不一致的hello-time问题5. R21配置了max-metric导致路由无效问题6. R3…

LLM大模型可视化-以nano-gpt为例

内容整理自&#xff1a;LLM 可视化 --- LLM Visualization (bbycroft.net)https://bbycroft.net/llm Introduction 介绍 Welcome to the walkthrough of the GPT large language model! Here well explore the model nano-gpt, with a mere 85,000 parameters. 欢迎来到 GPT 大…

GPUPixel:以光速打造美丽,开源跨平台的实时美颜滤镜库,赋能您的应用尽显商业级影像魅力!- 精选真开源,释放新价值。

GPUPixel&#xff1a;以光速打造美丽&#xff0c;开源跨平台的实时美颜滤镜库&#xff0c;赋能您的应用尽显商业级影像魅力!- 精选真开源&#xff0c;释放新价值。 概览 GPUPixel是一款精心设计并采用现代C11标准编写的高性能图像和视频AI美颜效果处理库&#xff0c;其核心价值…

vue 视频添加水印

1.需求背景 其实腾讯云点播的api也支持视频水印&#xff0c;但是只有单个水印&#xff0c;大概效果是这样子的&#xff0c;不满足我们的需求&#xff0c;我们的需求是需要视频中都是水印。 腾讯云点播水印 项目需求的水印&#xff08;主要是防录屏,最后的实现效果是这样&…