题目
给定字符串列表 strs
,返回其中最长的特殊序列的长度。如果最长特殊序列不存在,返回 -1。
特殊序列定义如下:该序列为某字符串独有的子序列(即不能是其他字符串的子序列)。
字符串 s
的子序列可以通过删去字符串 s
中的某些字符实现。
例如,“abc” 是 “aebdc” 的子序列,因为您可以删除"aebdc"中的下划线字符来得到 “abc” 。“aebdc"的子序列还包括"aebdc”、 “aeb” 和 “” (空字符串)。
示例 1:
- 输入:
strs = ["aba","cdc","eae"]
- 输出:
3
示例 2:
- 输入:
strs = ["aaa","aaa","aa"]
- 输出:
-1
提示:
2 <= strs.length <= 50
1 <= strs[i].length <= 10
strs[i]
只包含小写英文字母
代码
完整代码
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>typedef struct {char* s;int len;
} combo_t;int cmp(const void *a, const void *b) {combo_t* pofa = (combo_t*)a;combo_t* pofb = (combo_t*)b;return pofb->len - pofa->len;
}bool isSubsequence(char* a, char* b) {// 判断 a 是否为 b 的子序列int i = 0, j = 0;while (i < strlen(a) && j < strlen(b)) {if (a[i] == b[j]) {i++;}j++;}return i == strlen(a);
}int findLUSlength(char** strs, int strsSize) {combo_t* arr = (combo_t*)calloc(strsSize, sizeof(combo_t));for (int i = 0; i < strsSize; i++) {arr[i].len = strlen(strs[i]);arr[i].s = strs[i];}qsort(arr, strsSize, sizeof(combo_t), cmp);for (int i = 0; i < strsSize; i++) {bool isUnique = true;// 检查是否是唯一的for (int j = 0; j < strsSize; j++) {if (i != j && arr[i].len == arr[j].len && strcmp(arr[i].s, arr[j].s) == 0) {isUnique = false;break;}}// 如果是唯一的,检查是否不是其他更长字符串的子序列if (isUnique) {bool isSub = false;for (int j = 0; j < i; j++) {if (isSubsequence(arr[i].s, arr[j].s)) {isSub = true;break;}}if (!isSub) {int len = arr[i].len;free(arr);return len;}}}free(arr);return -1;
}
思路分析
该问题可以通过以下步骤解决:
- 定义结构体:用来存储字符串和它们的长度。
- 排序:按照字符串的长度从大到小排序,这样可以先检查较长的字符串。
- 检查唯一性:检查当前字符串是否在列表中唯一。
- 判断子序列:如果当前字符串是唯一的,检查它是否不是其他更长字符串的子序列。
- 返回结果:如果满足条件,返回当前字符串的长度;否则返回 -1。
拆解分析
-
定义结构体和比较函数:
typedef struct {char* s;int len; } combo_t;int cmp(const void *a, const void *b) {combo_t* pofa = (combo_t*)a;combo_t* pofb = (combo_t*)b;return pofb->len - pofa->len; }
结构体
combo_t
用于存储字符串及其长度。比较函数cmp
用于按字符串长度从大到小排序。 -
检查是否为子序列:
bool isSubsequence(char* a, char* b) {int i = 0, j = 0;while (i < strlen(a) && j < strlen(b)) {if (a[i] == b[j]) {i++;}j++;}return i == strlen(a); }
函数
isSubsequence
用于检查字符串a
是否是字符串b
的子序列。 -
主函数实现:
int findLUSlength(char** strs, int strsSize) {combo_t* arr = (combo_t*)calloc(strsSize, sizeof(combo_t));for (int i = 0; i < strsSize; i++) {arr[i].len = strlen(strs[i]);arr[i].s = strs[i];}qsort(arr, strsSize, sizeof(combo_t), cmp);for (int i = 0; i < strsSize; i++) {bool isUnique = true;for (int j = 0; j < strsSize; j++) {// 这里可以优化,如果len 不同,就break,因为前面经过排序,len不同则strcmp一定 != 0// 但是为了美观就不写了,因为总长度也就50条if (i != j && arr[i].len == arr[j].len && strcmp(arr[i].s, arr[j].s) == 0) {isUnique = false;break;}}if (isUnique) {bool isSub = false;for (int j = 0; j < i; j++) {if (isSubsequence(arr[i].s, arr[j].s)) {isSub = true;break;}}if (!isSub) {int len = arr[i].len;free(arr); // 记得提前返回的时候别内存泄漏return len;}}}free(arr);return -1; }
- 使用
combo_t
数组存储字符串和它们的长度。 - 对数组进行排序,使得较长的字符串先被处理。
- 遍历排序后的数组,检查每个字符串是否是唯一的。
- 对于唯一的字符串,进一步检查它是否不是其他更长字符串的子序列。
- 如果找到满足条件的字符串,返回它的长度;否则返回 -1。
- 使用
复杂度分析
- 时间复杂度:未优化的话是
O(n^2 * m)
,其中n
是字符串的数量,m
是字符串的最大长度, 可以通过仅比较相同长度字符串减小。排序的时间复杂度为O(n log n)
,判断子序列的时间复杂度为O(n * m)
。 - 空间复杂度:
O(n * m)
,用于存储字符串和它们的长度。