【LeetCode 每日一题】2021.02
2021-02-01 【简单】 888. 公平的糖果棒交换
展开代码
class Solution {
public int[] fairCandySwap(int[] A, int[] B) {
int[] res = new int[2];
Set<Integer> set = new HashSet<>();
int sumA = 0, sumB = 0;
for(int a: A){
set.add(a);
sumA += a;
}
for(int b: B){
sumB += b;
}
int t = (sumA - sumB)/2;
for(int b: B){
if(!set.contains(b+t)){
continue;
}
res[0] = b+t;
res[1] = b;
}
return res;
}
}
2021-02-02 【中等】 424. 替换后的最长重复字符
展开代码
// 模板题:双指针(蠕动法)
// 以每个元素为右边界,逐个找到最长的符合条件的子串长度,并记录其中的最大值
class Solution {
public int characterReplacement(String s, int k) {
int len = s.length();
if(len<2 || k>=len-1)
return len;
char[] arr = s.toCharArray();
int left = 0, right = 0, res = 0;
int[] bucket = new int[26];
int maxSub = 0;
// 新的右边界不能超出范围,否则结束
while(right<len){
// 将新的右边界计数
bucket[arr[right]-'A']++;
// 判断新范围,是否改变了最长相同字符子序列
maxSub = Math.max(maxSub, bucket[arr[right]-'A']);
// 如果此时子串中去掉最长相同字符子序列,即需要更改的次数,大于最大可以更改的次数
// 则子串不满足要求,需要移动左边界
while(right - left + 1 - maxSub > k){
bucket[arr[left]-'A']--;
left++;
}
// 判断以当前右边界结束的符合要求的最长子串长度是否更新记录
res = Math.max(res, right - left + 1);
// 开始探寻新的右边界
right++;
}
return res;
}
}
2021-02-03 【困难】 480. 滑动窗口中位数
展开代码
/**
大小顶堆 + 延迟删除
延迟删除:当我们需要移出优先队列中的某个元素时,我们只将这个删除操作「记录」下来,而不去真的删除这个元素。当这个元素出现在堆顶时,我们再去将其移出对应的优先队列。
保证在insert(涉及tar和堆顶的比较)、detele(涉及tar和堆顶的比较)、getMid(涉及取堆顶值)操作前,堆顶的元素都是不需要删除的。
*/
class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
Window window = new Window();
double[] res = new double[nums.length - k + 1];
for(int i = 0; i<k; i++){
window.insert(nums[i]);
}
res[0] = window.getMid();
for(int i = k; i<nums.length; i++){
window.insert(nums[i]);
window.delete(nums[i-k]);
res[i-k+1] = window.getMid();
}
return res;
}
}
class Window{
// 大顶堆,维护较小的一半元素
private PriorityQueue<Integer> small;
// 小顶堆,维护较大的一半元素
private PriorityQueue<Integer> large;
// small 和 large 当前包含的元素个数,需要扣除被「延迟删除」的元素
private int smallSize, largeSize;
// 哈希表,记录「延迟删除」的元素,key 为元素,value 为需要删除的次数
private Map<Integer, Integer> delayed;
public Window(){
// 默认是小顶堆
large = new PriorityQueue<>();
// 重写Comparator设置为大顶堆
small = new PriorityQueue<>(new Comparator<Integer>(){
public int compare(Integer x, Integer y){
// 注意这里不能用y-x,否则会出现超出范围
return y.compareTo(x);
}
});
delayed = new HashMap<>();
smallSize = 0;
largeSize = 0;
}
public void insert(int tar){
if(small.isEmpty() || tar <= small.peek()){
small.offer(tar);
smallSize++;
}
else{
large.offer(tar);
largeSize++;
}
balance();
}
public void delete(int tar){
delayed.put(tar, delayed.getOrDefault(tar, 0) + 1);
if(tar <= small.peek()){
smallSize--;
tryClear(small);
}
else{
largeSize--;
tryClear(large);
}
balance();
}
/**
尝试清理。发生在:
1. 刚刚产生新的延迟删除对象时,可以尝试是否能直接清理。
2. 在任何一个队列有poll操作后(balance与tryClear本身中出现),
顶都有可能是需要延迟删除的元素,因此需要尝试清理。
*/
private void tryClear(PriorityQueue<Integer> q){
int tar;
while(!q.isEmpty()){
tar = q.peek();
if(delayed.containsKey(tar)){
q.poll();
delayed.put(tar, delayed.get(tar)-1);
if(delayed.get(tar) == 0)
delayed.remove(tar);
}
else
break;
}
}
public double getMid(){
if(largeSize == 0 || (smallSize + largeSize)%2==1){
return (double)small.peek();
}
return ((double)small.peek() + large.peek())/2;
}
private void balance(){
if(smallSize == largeSize || smallSize == largeSize+1)
return;
while(smallSize > largeSize + 1){
large.offer(small.poll());
smallSize--;
largeSize++;
tryClear(small);
}
while(largeSize > smallSize){
small.offer(large.poll());
smallSize++;
largeSize--;
tryClear(large);
}
}
}
2021-02-04 【简单】 643. 子数组最大平均数 I
展开代码
class Solution {
public double findMaxAverage(int[] nums, int k) {
double res = Integer.MIN_VALUE;
Window window = new Window();
for(int i = 0; i<k; i++){
window.insert(nums[i]);
}
res = Math.max(res, window.getAvg());
for(int i = k; i<nums.length; i++){
window.insert(nums[i]);
window.delete(nums[i-k]);
res = Math.max(res, window.getAvg());
}
return res;
}
}
class Window{
int count;
double sum;
public Window(){
count = 0;
sum = 0;
}
public void insert(int tar){
sum += tar;
count++;
}
public void delete(int tar){
sum -= tar;
count--;
}
public double getAvg(){
return sum/count;
}
}
2021-02-05 【中等】 1208. 尽可能使字符串相等
展开代码
class Solution {
public int equalSubstring(String s, String t, int maxCost) {
int len = s.length();
int[] diff = new int[len];
for(int i = 0; i<len; i++){
diff[i] = Math.abs(s.charAt(i) - t.charAt(i));
}
int l = 0, r = 0, sum = 0, maxLen = 0;
while(r<len){
sum += diff[r];
while(sum > maxCost){
sum -= diff[l];
l++;
}
maxLen = Math.max(r-l+1, maxLen);
r++;
}
return maxLen;
}
}
2021-02-06 【中等】 1423. 可获得的最大点数
展开代码
// 将左右两个滑动窗口之和最大值的问题,变成中间滑动窗口最小值的问题
class Solution {
public int maxScore(int[] cardPoints, int k) {
int n = cardPoints.length;
int size = n - k;
int sum = 0;
for (int i = 0; i < size; i++) {
sum += cardPoints[i];
}
int minSum = sum, total = sum;
for (int i = size; i < n; i++) {
total += cardPoints[i];
sum += cardPoints[i] - cardPoints[i - size];
minSum = Math.min(minSum, sum);
}
return total - minSum;
}
}
2021-02-07 【简单】 665. 非递减数列
展开代码
class Solution {
public boolean checkPossibility(int[] nums) {
int len = nums.length;
int count = 1;
if(len<=2){
return true;
}
if(nums[0]>nums[1]){
nums[0] = nums[1];
count--;
}
for(int i = 2; i<len; i++){
if(nums[i-1] <= nums[i])
continue;
if(count==0)
return false;
if(nums[i] >= nums[i-2])
nums[i-1] = nums[i-2];
else
nums[i] = nums[i-1];
count--;
}
return true;
}
}
2021-02-08 【中等】 978. 最长湍流子数组
展开代码
// 双指针蠕动。本题左边界不是步进的,而且直接更新到right-1/right处。
class Solution {
public int maxTurbulenceSize(int[] arr) {
int len = arr.length;
if(len<=1)
return len;
int res = 1, left = 0, right = 1, cur = 1;
int flag = 0;
while(right < len){
if(arr[right] == arr[right-1]){
left = right;
cur = 1;
flag = 0;
}
else if((arr[right]>arr[right-1] && flag < 0) || (arr[right]<arr[right-1] && flag > 0)){
left = right - 1;
cur = 2;
}
else {
if(flag == 0)
flag = arr[right] > arr[right-1] ? -1: 1;
else
flag = flag > 0 ? -1: 1;
cur++;
res = Math.max(right - left + 1, res);
}
right++;
}
return res;
}
}
2021-02-09 【困难】 992. K 个不同整数的子数组
展开代码
// 恰好k 转换成 (最多k)-(最多k-1)
// 最多k使用双指针蠕动
class Solution {
public int subarraysWithKDistinct(int[] A, int k) {
int a = atMostKDistinct(A, k);
int b = atMostKDistinct(A, k-1);
return a-b;
}
private int atMostKDistinct(int[] A, int k){
int len = A.length;
int res = 0, l = 0, r = 0, d = 0;
int[] bucket = new int[len+1];
while(r<len){
if(bucket[A[r]]==0)
d++;
bucket[A[r]]++;
while(d>k){
bucket[A[l]]--;
if(bucket[A[l]]==0)
d--;
l++;
}
res += r - l;
r++;
}
return res;
}
}

浙公网安备 33010602011771号