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

news2024/11/25 4:28:18

最长公共前缀

  • 题目
  • 思路及实现
    • 方式一:横向扫描
      • 思路
      • 代码实现
        • 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/1561687.html

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

相关文章

VBA技术资料MF136:复制整个数据范围到PowerPoint

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Php_Code_challenge13

题目&#xff1a; 答案&#xff1a; 解析&#xff1a; 开启一个会话&#xff0c;在SESSION变量"nums"为空时则对"nums","time","whoami"进行赋值&#xff0c;并在120秒后关闭会话&#xff0c;创建一个变量"$value"…

【算法集训】基础算法:前缀和 | 概念篇

前缀和就是对于顺序表&#xff08;数组、列表&#xff09;来说&#xff0c;计算前面某一段元素的和。 1、部分和 给定一个数组&#xff0c;求某一段子数组的和。 2、朴素做法 int partialSum(int *a, int l, int r) {int i;int s 0;for(i l; i < r; i) {s a[i];}retu…

蓝桥杯单片机速成4-温度传感器DS18B20

目录 一、电路图 二、底层驱动代码 三、温度读取实现 四、实际使用 一、电路图 二、底层驱动代码 时序是单总线 我们需要修改的地方是单总线内部延时函数&#xff0c;改成 void Delay_OneWire(unsigned int t) { t*12; while(t--); } #ifndef __ONEWIRE_H #defi…

ZKFair 步入Dargon Slayer 新阶段,未来还有哪些财富效应?

在当前区块链技术的发展中&#xff0c;Layer 2&#xff08;L2&#xff09;解决方案已成为提高区块链扩容性、降低交易成本和提升交易速度的关键技术&#xff0c;但它仍面临一些关键问题和挑战&#xff0c;例如用户体验的改进、跨链互操作性、安全性以及去中心化程度。在这些背景…

HQL,SQL刷题,尚硅谷(初级)

目录 相关表数据&#xff1a; 题目及思路解析&#xff1a; 多表连接 1、课程编号为"01"且课程分数小于60&#xff0c;按分数降序排列的学生信息 2、查询所有课程成绩在70分以上 的学生的姓名、课程名称和分数&#xff0c;按分数升序排列 3、查询该学生不同课程的成绩…

Linux多进程通信(2)——POSIX信号量使用例程

1.POSIX信号量 1&#xff09;POSIX信号量和System V信号量区别 常用的是POSIX信号量&#xff0c;使用起来更加方便&#xff0c;而POSIX信号量分为有名信号量和无名信号量 POSIX信号量是多线程多进程安全的&#xff0c;而System V标准的信号量并不是&#xff0c;Posix通过sem_…

java----继承

1、继承的定义 继承就是子类继承父类的特征和行为&#xff0c;使得子类对象具有父类的属性和方法&#xff08;不劳而获&#xff09; 使用 extends关键字 2、方法重写&#xff08;方法覆盖&#xff09; 子类可以重写父类中的方法&#xff0c;要求方法签名必须一样 3、方法重载…

2、jvm基础知识(二)

类的生命周期 加载 1、加载(Loading)阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。 程序员可以使用Java代码拓展的不同的渠道。 2、类加载器在加载完类之后&#xff0c;Java虚拟机会将字节码中的信息保存到内存的方法区中。在方法区生…

【已解决】Port 8080 was already in use

问题描述 运行项目时显示错误页&#xff0c;无法成功进入目标页 *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 8080 was already in use.Action:Identify and stop the process thats…

MySQL常见故障案例与优化介绍

前言 MySQL故障排查的意义在于及时识别并解决数据库系统中的问题&#xff0c;确保数据的完整性和可靠性&#xff1b;而性能优化则旨在提高数据库系统的效率和响应速度&#xff0c;从而提升用户体验和系统整体性能。这两方面的工作都对于保证数据库系统稳定运行、提升业务效率和…

html基础:颜色的 5 种表示方法(最全!)

你好&#xff0c;我是云桃桃。一个希望帮助更多朋友快速入门 WEB 前端的程序媛&#xff0c;大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 HTML 颜色在网页设计中扮演着重要角色&#xff0c;给网页增加颜色可以增强用户体验&#xff0c;…

臻奶惠无人售货机:新零售时代的便捷消费革命

臻奶惠无人售货机&#xff1a;新零售时代的便捷消费革命 在新零售的浪潮中&#xff0c;智能无人售货机作为一个创新的消费模式&#xff0c;已经成为距离消费者最近的便捷购物点之一。这种模式不仅能够满足居民对消费升级的需求&#xff0c;还能通过建立多样化和多层次的消费体…

Spring使用(一)注解

Spring使用 资源 Spring 框架内部使用 Resource 接口作为所有资源的抽象和访问接口&#xff0c;在上一篇文章的示例代码中的配置文件是通过ClassPathResource 进行封装的&#xff0c;ClassPathResource 是 Resource 的一个特定类型的实现&#xff0c;代表的是位于 classpath …

Python创建三维空间立体方阵,根据赋予数值绘图赋色

代码如下&#xff1a; import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection from matplotlib.colors import LinearSegmentedColormap, Normalize import numpy as npdef make_cube(matrix: np.ndarray)->None:fig plt.figure(figs…

vue项目视频播放ckplayer使用

ckplayer 官方网址&#xff0c;点击访问 1&#xff0c;打开网页后能看到这里&#xff0c;我现在使用的是最新 X3版手册 2&#xff0c;这个ckplayer不是npm 插件&#xff0c;要下载安装包解压到项目里面使用 安装包网址 通过gitee下载 3&#xff0c;解析安装包到项目中 publ…

leetcode 不同路径

62. 不同路径 问题描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的…

仿真黑科技EasyGo DeskSim 2022

DeskSim2022的FPGA支持多种solver的混合应用&#xff0c;对于每一种solver可以采用不同的仿真步长&#xff0c;以下图模型为例&#xff0c;模型运行在FPGA上&#xff0c;FPGA解算方式采用的是Power Electronic & FPGA Coder解算&#xff0c;其中电力电子电路部分采用了两种…

SD-WAN支持的多种线路类型

SD-WAN技术的崛起为企业网络带来了全新的可能性&#xff0c;尤其是在连接选项的多样性方面。通过SD-WAN方案&#xff0c;企业可以根据自身需求来选择最适合的连接类型&#xff0c;以实现性能优化和成本效益的平衡。下面&#xff0c;让我们深入了解SD-WAN所支持的各种线路类型。…

【御控物联】JavaScript JSON结构转换(12):对象To数组——键值互换属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、核心构件之转换映射三、案例之《JSON对象 To JSON数组》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换…