「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。
每日刷题第36天 2021.02.01
1763.最长的美好子字符串
- leetcode原题链接:leetcode-cn.com/problems/lo…
- 难度:简单
- 方法:位运算
题目
- 当一个字符串 s 包含的每一种字母的大写和小写形式 同时 出现在 s 中,就称这个字符串 s 是 美好 字符串。比方说,"abABB" 是美好字符串,因为 'A' 和 'a' 同时出现了,且 'B' 和 'b' 也同时出现了。然而,"abA" 不是美好字符串因为 'b' 出现了,而 'B' 没有出现。
- 给你一个字符串 s ,请你返回 s 最长的 美好子字符串 。如果有多个答案,请你返回 最早 出现的一个。如果不存在美好子字符串,请你返回一个空字符串。
示例
- 示例1
输入:s = "YazaAay"
输出:"aAa"
解释:"aAa" 是一个美好字符串,因为这个子串中仅含一种字母,其小写形式 'a' 和大写形式 'A' 也同时出现了。
"aAa" 是最长的美好子字符串。
- 示例2
输入: s = "Bb"
输出: "Bb"
解释: "Bb" 是美好字符串,因为 'B' 和 'b' 都出现了。整个字符串也是原字符串的子字符串。
- 示例3
输入: s = "c"
输出: ""
解释: 没有美好子字符串。
- 示例4
输入:s = "dDzeE"
输出:"dD"
解释:"dD" 和 "eE" 都是最长美好子字符串。
由于有多个美好子字符串,返回 "dD" ,因为它出现得最早。
提示
1 <= s.length <= 100s只包含大写和小写英文字母。
解法
优化解法
- 自己写的纯纯暴力,相当于使用
js模拟了一个优先队列 - 前缀和优化:在
check中,我们不可避免的遍历整个子串,复杂度为O(n)。- 该过程可以使用前缀和思想进行优化:构建二维数组
cnt来记录子串的词频,cnt[i]为一个长度为128的数组,用于记录字符串s中下标范围为[0, i - 1]的词频。 - 即
cnt[i + 1][j]所代表的含义为在子串s[0...i]中字符j的出现次数。 - 那么利用「容斥原理」,对于
s的任意连续段[l, r]所代表的子串中的任意字符i的词频,我们可以作差算得:res[i] = cnt[r + 1][i] - cnt[l][i]res[i]=cnt[r+1][i]−cnt[l][i]
- 该过程可以使用前缀和思想进行优化:构建二维数组
- 这样我们在
check实现中,只要检查26个字母对应的大小写词频(ASCII相差32),是否同时为0或者同时不为0即可,复杂度为O(C)。
/**
* @param {string} s
* @return {string}
*/
var longestNiceSubstring = function(s) {
// 记录数组 小写字母
let lower = new Array(26);
// 大写字母
let upper = new Array(26);
// console.log('u',upper,'l',lower);
let n = s.length;
if(n == 1) return "";
let ansLen = 0;
let index = [];
for (let i = 0; i < n; i++) {
//下次循环,需要提前置空
lower.fill(0);
upper.fill(0);
for(let j = i; j < n; j++) {
if('a' <= s[j] && s[j] <= 'z') {
// 小写字母
let temptL = (s[j].charCodeAt() - 'a'.charCodeAt());
lower[temptL] = 1;
}else {
// 大写字母
let temptU = (s[j].charCodeAt() - 'A'.charCodeAt());
upper[temptU] = 1;
}
// 每次都需要判断一下当前是否完美,完美就跳出循环,len++,记录下标
// (i,j) 这个子串是否为完美的
if (lower.toString() == upper.toString()) {
// 完全相等的是完美的
if(ansLen < j - i + 1) {
ansLen = j - i + 1;
index = [i, j];
}
}
}
}
// console.log('shuchu','ansLen',ansLen,'index',index);
return s.slice(index[0], index[1] + 1);
};