题目
给定字符串列表 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)
,用于存储字符串和它们的长度。