LeetCode Contest 238
❤
1837. Sum of Digits in Base K
进制转换: n%=k ,n/=k
🐷 :
class Solution {
public int sumBase(int n, int k) {
int mod = 0;
int res = 0;
while (n != 0) {
res = res + n % k;
n /= k;
}
return res;
}
}
🍀 :
class Solution {
public int sumBase(int n, int k) {
int ans = 0;
while (n>0) {
ans += n%k;
n = n/k;
}
return ans;
}
}
1838. Frequency of the Most Frequent Element
🐷 :
🍀 :
- 暴力解法
每次跳过重复元素,尝试操作后回退,记录最优解
class Solution {
public int maxFrequency(int[] nums, int k) {
Arrays.sort(nums);
int i = nums.length-1;
int ans = 0;
while (i >= 0) {
int start = i;
while (i > 0 && nums[i] == nums[i-1]) {
i--;
}
int end = i, res = k;
while (i >= 0) {
res -= (nums[start]- nums[i]);
if (res < 0) break;
i--;
}
ans = Math.max(ans, start-i);
start = i = end-1;
}
return ans;
}
}
- Sliding Window
- 升序排序,从后往前遍历(因为java int[]无法降序排序)
- 记录的变量:
- window范围区间: 前边界start,后边界end
- window区间和sum: s u m = ∑ i = s t a r t e n d a [ i ] sum=\sum_{i=start}^{end}{a[i]} sum=∑i=startenda[i]
- 遍历操作:
- 每次尝试扩展window后边界end,把所有元素变为
n
u
m
s
[
s
t
a
r
t
]
nums[start]
nums[start]:
-合法窗口条件: s u m + k > n u m s [ s t a r t ] ∗ c o u n t ; sum+k >nums[start]*count; sum+k>nums[start]∗count; - 不合法时,窗口前边界元素出窗口
- 窗口的大小只增不减:前边界出窗口后,后边界继续扩展,而无需验证长度更短的window是否合法,因为我们只关心最大合法窗口的长度而非找出所有合法窗口
- 每次尝试扩展window后边界end,把所有元素变为
n
u
m
s
[
s
t
a
r
t
]
nums[start]
nums[start]:
- 最后一个窗口的长度即为最大合法窗口的长度,但最后一个窗口并不一定是合法的窗口,只代表遍历过程中曾经有过此长度的合法窗口
class Solution {
public int maxFrequency(int[] nums, int k) {
Arrays.sort(nums);
int start = nums.length-1, end = nums.length-1;
int sum = 0;
while (end >= 0) {
sum += nums[end];
int count = start-end+1;
if (sum + k < nums[start]*count) {
sum -= nums[start--];
}
end--;
}
return start-end;
}
}
** Sliding Window题目特征总结
- 往往与区间有关
- 求解过程出现大量重合区间,大量重复的计算内容 通过双指针一前一后控制元素的进出实现sliding,以合并重复计算
<区间和/积 | 累加/乘数组 | 概率密度函数 | 无穷积分> - 通过寻找等式/不等式关系,定义合法窗口
- 当只关心最大区间范围or计算结果最大值时,通过尝试滑动并扩大区间的长度,减少验证窗口是否合法的次数
- 往往需要排序以保证结果的最优性(例如求最大区间和)
1839. Longest Substring Of All Vowels in Order
解法1:用HashSet判断是否为aeiou
🐷 :
class Solution {
public int longestBeautifulSubstring(String word) {
if (word.length() < 5) return 0;
int res = 0;
int count = 0;
char[] temp = word.toCharArray();
HashSet<Character> set = new HashSet<>();
for (int i = 0; i < temp.length - 1; i++) {
if (temp[i] - temp[i + 1] > 0) {
set.add(temp[i]);
if (set.size() == 5) {
res = Math.max(res, count);
}
set.clear();
count = 0;
} else {
count += 1;
set.add(temp[i]);
}
}
set.add(temp[temp.length - 1]);
if (set.size() == 5 && count != 0) res = Math.max(res, count);
return res == 0 ? 0 : res + 1;
}
}
解法2:创建vowels数组,按顺序依次匹配aeiou,匹配结束记录结果
依次匹配word[i],当前匹配到vowels[j]
- 情况1: words[i]== vowels[j]继续匹配当前元音,i++
- 情况2:words[i]== vowels[j+1]匹配下一个元音,i++, j++
- 情况3:完全不匹配
-
- a) 已经匹配到结尾,合法:记录结果
-
- b) 未匹配到结尾,不合法:重新从a开始匹配
-
-
- 若当前words[i]==a, 手动匹配一位: j=1, start = i, i++
-
-
-
- 若当前words[i]!=a: j=0, start = i+1, i++
-
🍀 :
class Solution {
public int longestBeautifulSubstring(String word) {
int i = 0, j = 0; // 记录匹配位置
int ans = 0;
int start = 0;
char[] words = word.toCharArray();
char[] vowels = new char[]{' ','a','e','i','o','u','/'};
while (i < words.length) {
if (words[i] == vowels[j]) {
i++;
} else {
if (words[i]==vowels[j+1]) {
i++; j++;
} else {
if (vowels[j+1]=='/') {
ans = Math.max(ans, i-start);
}
if (words[i] == 'a') {
start = i++;
j = 1;
}
else {
start = ++i;
j = 0;
}
}
}
}
if (vowels[j+1]=='/') {
ans = Math.max(ans, i-start);
}
return ans;
}
}
1840. Maximum Building Height
- restrictions按building idx升序排序,正向收缩,反向收缩
- 计算两个位置间的峰值 peek[i ~ j] = (h[i] + h[j] + i - j ) / 2;
**注意首尾单独处理
🐷 :
class Solution {
// Time O(nlogn)
public int maxBuilding(int n, int[][] restrictions) {
if (restrictions == null || restrictions.length == 0 || restrictions[0] == null ||restrictions[0].length == 0) {
return n - 1;
}
Arrays.sort(restrictions, (a, b) -> a[0] - b[0]);
int len = restrictions.length;
restrictions[0][1] = Math.min(restrictions[0][0] - 1, restrictions[0][1]);
for (int i = 1; i < len; i++) {
restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i - 1][1] + restrictions[i][0] - restrictions[i - 1][0]);
}
for (int i = len - 2; i >= 0; i--) {
restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i + 1][1] + restrictions[i + 1][0] - restrictions[i][0]);
}
int res = 0;
for (int i = 1; i < len; i++) {
int peek = (restrictions[i][0] - restrictions[i][1] - restrictions[i - 1][0] + restrictions[i - 1][1]) / 2;
res = Math.max(res, restrictions[i][1] + peek);
}
//restrictions数组的最后一个,不一定是所有楼的最后。所以还要考虑在restrictions之后还有没有楼
res = Math.max(res, restrictions[len - 1][1] + n - restrictions[len - 1][0]);
return res;
}
}
🍀 :
class Solution {
public int maxBuilding(int n, int[][] restrictions) {
int LEN = restrictions.length;
if (LEN==0) return n-1;
Arrays.sort(restrictions, (a,b)-> a[0] - b[0]);
restrictions[0][1] = Math.min(restrictions[0][1], restrictions[0][0]-1);
for (int i=1; i<LEN; i++) {
int dist = restrictions[i][0] - restrictions[i-1][0];
restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i-1][1] + dist);
}
for (int i=LEN-2; i>=0; i--) {
int dist = restrictions[i+1][0] - restrictions[i][0];
restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i+1][1] + dist);
}
int ans = Math.max(0, restrictions[LEN-1][1] + n - restrictions[LEN-1][0]);
for (int i=1; i<LEN; i++) {
int dist = restrictions[i][0] - restrictions[i-1][0];
int peek = (restrictions[i][1] + restrictions[i-1][1] + dist) / 2;
ans = Math.max(ans, peek);
}
return ans;
}
}