引入
给你一个字符串 num ,表示一个大整数。如果一个整数满足下述所有条件,则认为该整数是一个 优质整数:
- 该整数是 num 的一个长度为 3 的 子字符串 。
- 该整数由唯一一个数字重复 3 次组成。
以字符串形式返回 最大的优质整数 。如果不存在满足要求的整数,则返回一个空字符串 “” 。
注意:
- 子字符串 是字符串中的一个连续字符序列。
- num 或优质整数中可能存在 前导零 。
示例
示例 1:
输入:num = “6777133339”
输出:“777”
解释:num 中存在两个优质整数:“777” 和 “333” 。
“777” 是最大的那个,所以返回 “777” 。
示例 2:
输入:num = “2300019”
输出:“000”
解释:“000” 是唯一一个优质整数。
示例 3:
输入:num = “42352338”
输出:“”
解释:不存在长度为 3 且仅由一个唯一数字组成的整数。因此,不存在优质整数。
解法
我的天啊~这么简单的一道题官方竟然要用枚举法(枚举出字符串num中所有长度为 3的子串,并记录符号要求且对应的数值最大的子串),有点多此一举的样子,我想着不是直接字符串匹配来的快一点嘛,反正一共就9个子串。
C++代码:
class Solution {
public:
string largestGoodInteger(string num) {
for(int i=9 ; i>=0;i--){
string s(3,'0'+i);
if(num.find(s)!= string::npos){
return s; //如果字符串find不为空就证明至少找到一个(从最大的开始找)
}
}
return "";
}
};
官方的枚举法
官方的思路就是枚举字符串 num \textit{num} num 中所有长度为 3 3 3 的子串,并记录符合要求且对应数值最大的子串。
具体地,我们用初值为空的字符串 res \textit{res} res 来维护数值最大的符合要求子串,同时从左至右遍历长度为 3 3 3 子串的起始下标 i i i,每遍历到一个新的下标 i i i,我们判断以子串 num [ i . . i + 2 ] \textit{num}[i..i + 2] num[i..i+2] 是否由相同的字符构成:如果是则该子串符合要求,我们将 res \textit{res} res 更新为 res \textit{res} res 和该子串的较大值(此处字符串字典序的大小关系与对应整数的大小关系一致);如果不是则不进行任何操作。
最终,如果存在符合要求的子串,则 res \textit{res} res 即为对应数值最大的子串;如果不存在,则 res \textit{res} res 为空字符串。因此我们返回 res \textit{res} res 作为答案。
class Solution {
public:
string largestGoodInteger(string num) {
int n = num.size();
string res;
for (int i = 0; i < n - 2; ++i) {
if (num[i] == num[i+1] && num[i+1] == num[i+2]) {
res = max(res, num.substr(i, 3));
}
}
return res;
}
};
总结
官方的枚举法的缺点就是无论你是否找到了都会循环n-3次,
即最好和最坏的时间复杂度都是
O
(
n
)
O(n)
O(n)
,空间复杂度为
O
(
1
)
O(1)
O(1)
而我们从999开始进行字符串匹配的最好时间复杂度是第一次就找到
O
(
1
)
O(1)
O(1), 最坏时间复杂度是
O
(
n
2
)
O(n^2)
O(n2)(虽然没有规定find函数的效率,我们就按照每次都是逐一匹配), 空间复杂度是
O
(
1
)
O(1)
O(1)
卧槽!!大意了没有闪,还是分析下来还是官方牛逼,不调用子串查找函数,直接通过枚举的方法达到了时间和空间上的平衡,枚举的方法在字符串比较乱的情况下应该还是官方的效果好一点,但是如果在早期就出现匹配到的字符串我的算法的效率就会提升的很明显,算是各有千秋了