计划把力扣2月打卡徽章拿下,坚持每日打卡学习。这月是滑动窗口月。
维护一个移动的窗口来处理在数组中运算。
避免反复的重复计算,只需要关注每次窗口移动增加和减少的数值就行了。
/**
* 爱丽丝和鲍勃有不同大小的糖果棒:A[i] 是爱丽丝拥有的第 i 根糖果棒的大小,B[j] 是鲍勃拥有的第 j 根糖果棒的大小。
*
* 因为他们是朋友,所以他们想交换一根糖果棒,这样交换后,他们都有相同的糖果总量。(一个人拥有的糖果总量是他们拥有的糖果棒大小的总和。)
*
* 返回一个整数数组 ans,其中 ans[0] 是爱丽丝必须交换的糖果棒的大小,ans[1] 是 Bob 必须交换的糖果棒的大小。
*
* 如果有多个答案,你可以返回其中任何一个。保证答案存在。
*
*
*
* 示例 1:
*
* 输入:A = [1,1], B = [2,2]
* 输出:[1,2]
* 示例 2:
*
* 输入:A = [1,2], B = [2,3]
* 输出:[1,2]
* 示例 3:
*
* 输入:A = [2], B = [1,3]
* 输出:[2,3]
* 示例 4:
*
* 输入:A = [1,2,5], B = [2,4]
* 输出:[5,4]
*/
public static void main(String[] args) {
int[] A = {1, 1};
int[] B = {2, 2};
System.out.println(Arrays.toString(fairCandySwap(A, B)));
int[] A1 = {1, 2};
int[] B1 = {2, 3};
System.out.println(Arrays.toString(fairCandySwap(A1, B1)));
int[] A2 = {1, 2, 5};
int[] B2 = {2, 4};
System.out.println(Arrays.toString(fairCandySwap(A2, B2)));
int[] A3 = {35,17,4,24,10};
int[] B3 = {63,21};
System.out.println(Arrays.toString(fairCandySwap(A3, B3))); //24 21
}
public static int[] fairCandySwap(int[] A, int[] B) {
//哈希表
int sumA = Arrays.stream(A).sum();
int sumB = Arrays.stream(B).sum();
int delta = (sumA - sumB) / 2;
Set<Integer> rec = new HashSet<Integer>();
for (int num : A) {
rec.add(num);
}
int[] ans= new int[2];
for (int y:B){
int x=y+delta;
if(rec.contains(x)){
ans[0]=x;
ans[1]=y;
break;
}
}
return ans;
}
class Solution {
public double findMaxAverage(int[] nums, int k) {
int max= 0;
for (int i = 0; i <k ; i++) {
max+=nums[i];
}
int pre=max;
for (int i = k; i <nums.length ; i++) {
pre=pre-nums[i-k]+nums[i];
max=Math.max(pre,max);
}
double m=max*1.0;
return m/k;
}
}
public static void main(String[] args) {
int[][] matrix={{1,2,3,4},
{5,1,2,3},
{9,5,1,2}};
System.out.println(isToeplitzMatrix(matrix));
int[][] matrix3={{1,2},
{1,2}};
System.out.println(isToeplitzMatrix(matrix3));
}
public static boolean isToeplitzMatrix(int[][] matrix) {
int m=matrix[0].length;
int n=matrix.length;
//前一行比后一行大一
//斜着向上滑动,用一个数组来表示前一位数
for (int i = -n+1; i <m ; i++) {
int pre=-1;
for (int j = 0; j < n; j++) {
if(j+i>=0&j+i<m){
int now=matrix[j][j+i];
if(pre==-1){
pre=now;
}else if (pre!=now){
return false;
}
}
}
}
return true;
}
/**
* 给你两个长度相同的字符串,s 和 t。
*
* 将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),
* 也就是两个字符的 ASCII 码值的差的绝对值。
*
* 用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。
*
* 如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。
*
* 如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。
*
*
*
* 示例 1:
*
* 输入:s = "abcd", t = "bcdf", cost = 3
* 输出:3
* 解释:s 中的 "abc" 可以变为 "bcd"。开销为 3,所以最大长度为 3。
* 示例 2:
*
* 输入:s = "abcd", t = "cdef", cost = 3
* 输出:1
* 解释:s 中的任一字符要想变成 t 中对应的字符,其开销都是 2。因此,最大长度为 1。
* 示例 3:
*
* 输入:s = "abcd", t = "acde", cost = 0
* 输出:1
* 解释:你无法作出任何改动,所以最大长度为 1。
*
*/
public static void main(String[] args) {
System.out.println(equalSubstring("abcd","bcdf",3)); //3
System.out.println(equalSubstring("abcd","cdef",3)); //1
System.out.println(equalSubstring("abcd","acde",0)); //1
System.out.println(equalSubstring("abcd","cdef",1)); //0
System.out.println(equalSubstring("krrgw","zjxss",19)); //2
System.out.println(equalSubstring("krasfsfrgw","zjxasdczss",34));
}
public static int equalSubstring(String s, String t, int maxCost) {
//记录每个位置变化需要的长度
int n=s.length();
int[] costList=new int[n];
for (int i = 0; i <n ; i++) {
int cost=Math.abs(s.charAt(i)-t.charAt(i));
costList[i]=cost;
}
//双指针,滑动窗口
int len=0; //窗口长度
int total=0;
int left=0,right=0;
while (right<n){
//向右扩张
total+=costList[right];
if(total<=maxCost){ //还在可操作数内
len++;
}else {
total-=costList[left];
left++;
}
right++;
}
return len;
}
/**
* 给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,
* 总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
*
* 注意:字符串长度 和 k 不会超过 104。
*
* 示例 1:
*
* 输入:s = "ABAB", k = 2
* 输出:4
* 解释:用两个'A'替换为两个'B',反之亦然。
* 示例 2:
*
* 输入:s = "AABABBA", k = 1
* 输出:4
* 解释:
* 将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。
* 子串 "BBBB" 有最长重复字母, 答案为 4。
*
*/
public static void main(String[] args) {
}
public static int characterReplacement(String s, int k) {
int[] num = new int[26];
int n = s.length();
int maxn = 0;
int left = 0, right = 0;
while (right < n) {
num[s.charAt(right) - 'A']++;
maxn = Math.max(maxn, num[s.charAt(right) - 'A']);
if (right - left + 1 - maxn > k) {
num[s.charAt(left) - 'A']--;
left++;
}
right++;
}
return right - left;
}
/**
* 当 A 的子数组 A[i], A[i+1], ..., A[j] 满足下列条件时,我们称其为湍流子数组:
*
* 若 i <= k < j,当 k 为奇数时, A[k] > A[k+1],且当 k 为偶数时,A[k] < A[k+1];
* 或 若 i <= k < j,当 k 为偶数时,A[k] > A[k+1] ,且当 k 为奇数时, A[k] < A[k+1]。
* 也就是说,如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是湍流子数组。
*
* 返回 A 的最大湍流子数组的长度。
*
* 示例 1:
*
* 输入:[9,4,2,10,7,8,8,1,9]
* 输出:5
* 解释:(A[1] > A[2] < A[3] > A[4] < A[5])
* 示例 2:
*
* 输入:[4,8,12,16]
* 输出:2
* 示例 3:
*
* 输入:[100]
* 输出:1
*
*
* 提示:
*
* 1 <= A.length <= 40000
* 0 <= A[i] <= 10^9
*
* @param args
*/
public static void main(String[] args) {
System.out.println(maxTurbulenceSize(new int[]{9,4,2,10,7,8,8,1,9}));
System.out.println(maxTurbulenceSize(new int[]{4,8,12,16}));
System.out.println(maxTurbulenceSize(new int[]{4,5}));
}
public static int maxTurbulenceSize(int[] arr) {
if(arr.length==1)return 1;
int max=arr[0]==arr[1]?1:2;
int left=0;
int right=1;
int k=arr[left]>arr[right]?1:2; //0 开始 1:前大于后 2 后大于前
while (right<arr.length-1){
right++;
if(arr[right-1]==arr[right]){
left=right;
}else if(k==1){
if(arr[right-1]<arr[right]){
k=2;
}else {
left=right-1;
}
}else if(k==2){
if(arr[right-1]>arr[right]){
k=1;
}else {
left=right-1;
}
}
max=Math.max(max,right-left+1);
}
return max;
}
//今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。
//
//在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。
//
//书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。
//
//请你返回这一天营业下来,最多有多少客户能够感到满意的数量。
//
//
//示例:
//
//输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3
//输出:16
//解释:
//书店老板在最后 3 分钟保持冷静。
//感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.
//
//
//提示:
//
//1 <= X <= customers.length == grumpy.length <= 20000
//0 <= customers[i] <= 1000
//0 <= grumpy[i] <= 1
//
public static void main(String[] args) {
int[] customers = {1,0,1,2,1,1,7,5}, grumpy = {0,1,0,1,0,1,0,1};
System.out.println(maxSatisfied(customers,grumpy,3));
int[] customers2 = {1}, grumpy2 = {0};
System.out.println(maxSatisfied(customers2,grumpy2,1));
}
public static int maxSatisfied(int[] customers, int[] grumpy, int X) {
//1,先计算不使用技能情况下会让多少人满意
int n=customers.length;
int ans=0;
for (int i = 0; i <n ; i++) {
if(grumpy[i]==0) ans+=customers[i];
}
//2,滑动窗口,计算在X长区间内因为发脾气而赶走客人的最大数量
int max=0;
int now=0;
for (int i = 0; i <n ; i++) {
if(i+1<=X){
now+=customers[i]*grumpy[i];
max=now;
}else {
now=now+customers[i]*grumpy[i]-customers[i-X]*grumpy[i-X];
max=Math.max(max,now);
}
}
return ans+max;
}
public class 滑动窗口中位数 {
//中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
//
// 例如:
//
//
// [2,3,4],中位数是 3
// [2,3],中位数是 (2 + 3) / 2 = 2.5
//
//
// 给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗
//口中元素的中位数,并输出由它们组成的数组。
//
//
//
// 示例:
//
// 给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。
//
//
//窗口位置 中位数
//--------------- -----
//[1 3 -1] -3 5 3 6 7 1
// 1 [3 -1 -3] 5 3 6 7 -1
// 1 3 [-1 -3 5] 3 6 7 -1
// 1 3 -1 [-3 5 3] 6 7 3
// 1 3 -1 -3 [5 3 6] 7 5
// 1 3 -1 -3 5 [3 6 7] 6
//
//
// 因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]。
//
//
//
// 提示:
//
//
// 你可以假设 k 始终有效,即:k 始终小于等于输入的非空数组的元素个数。
// 与真实值误差在 10 ^ -5 以内的答案将被视作正确答案。
public static void main(String[] args) {
int[] nums={1,3,-1,-3,5,3,6,7};
System.out.println(Arrays.toString(medianSlidingWindow(nums,3)));//[1,-1,-1,3,5,6]
int[] nums2= {2147483647,2147483647};
System.out.println(Arrays.toString(medianSlidingWindow(nums2,2)));//[2147483647.0]
int[] nums3= {4,1,7,1,8,7,8,7,7,4};
System.out.println(Arrays.toString(medianSlidingWindow(nums3,4)));//[2.5,4.0,7.0,7.5,7.5,7.0,7.0]
}
public static double[] medianSlidingWindow(int[] nums, int k) {
int n=nums.length;
double[] ans=new double[n-k+1];
List<Integer> list=new ArrayList<>();
for (int i = 0; i < k; i++) {
list.add(nums[i]);
}
Collections.sort(list);
ans[0]=getMidNum(list,k);
for (int i = k; i <n ; i++) {
removeFromList(list,nums[i-k]);
add2OrderedList(list,nums[i]);
ans[i-k+1]=getMidNum(list,k);
// System.out.println(Arrays.toString(ans));
}
return ans;
}
private static void add2OrderedList(List<Integer> list,int num){
for (int i = 0; i <list.size() ; i++) {
if(list.get(i)>num){
list.add(i,num);
return;
}
}
list.add(num);
}
private static void removeFromList(List<Integer> list,int num){
for (int i = 0; i < list.size(); i++) {
if(num==list.get(i)){
list.remove(i);
break;
}
}
}
public static double getMidNum(List<Integer> list,int k){
if(k%2==0){
// return (list.get(k/2)+list.get(k/2-1))/2.0;
return list.get(k/2)/2.0+list.get(k/2-1)/2.0;
}else {
return list.get(k/2);
}
}
}