一、题目
给你一个由英文字母组成的字符串 s ,请你找出并返回 s 中的最好英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。
最好 英文字母的大写和小写形式必须 都 在 s 中出现。
英文字母 b 比另一个英文字母 a 更好 的前提是:英文字母表中,b 在 a 之 后 出现。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/greatest-english-letter-in-upper-and-lower-case/
二、C解法
我的思路及代码
该题目涉及到了字母的大小写,我的第一反应就是采用ASCII码来进行操作,ASCII码会放在本文末尾。由于题目要求是需要同时出现大写和小写,于是很自然会想到给26个字母的大写和小写一个标志位,访问到某个字母的大写/小写的时候就给设置标志位。当某一个字母的大小写标志位全部被修改后此字母成为最好字母的候选。由于要找到最好的英文字母,所以不妨再设置一个变量来存储遍历到目前为止的最好的英文字母,牺牲一点点空间,节约了大量的时间。下面是我的代码。
- 时间复杂度O(n)
- 空间复杂度O(∣Σ∣),其中 Σ是字符集,本题中 ∣Σ∣=26。
char * greatestLetter(char * s){
char ans=0;//ans只存储大写字母,所以比较时和大写比较
char *res = (char *)malloc(sizeof(char) * 2);
bool str[52]={false};//大写存在前面,小写存在后面
for(;*s!='\0';s++){
//表明是大写字母
if(*s>=65 && *s<=90){
if(str[*s-'A'+26]==true && *s>ans){
ans = *s;
}
str[*s-'A']=true;
}
//表明是小写字母
if(*s>=97 && *s<=122){
if(str[*s-'a']==true && *s-32>ans){
ans = *s-32;//转化为大写进行存储
}
str[*s-'a'+26]=true;
}
}
if (ans == 0)
return "";
else {
//这里是迎合力扣的格式要求,不这样写会报错
res[0]=ans;
res[1] = '\0';
return res;
}
}
官方参考代码
官方的亮点有两个,一个是采用了32位的int来代替数组的使用,节约了空间,其次是采用位运算来进行操作,这样的速度也会有所提升。
- 时间复杂度:O(n+∣Σ∣),其中 Σ是字符集,本题中 ∣Σ∣=26。
- 空间复杂度O(1)
char * greatestLetter(char * s) {
int lower = 0, upper = 0;
for (int i = 0; s[i] != '\0'; i++) {
char c = s[i];
if (islower(c)) {
lower |= 1 << (c - 'a');
} else {
upper |= 1 << (c - 'A');
}
}
for (int i = 25; i >= 0; i--) {
if (lower & upper & (1 << i)) {
char *res = (char *)malloc(sizeof(char) * 2);
res[0] = 'A' + i;
res[1] = 0;
return res;
}
}
return "";
}