算法通关村-----原来滑动窗口如此简单

滑动窗口思想

滑动窗口其实是双指针的特例。两个同向移动指针确定了一个区间,这个区间我们称之为窗口。随着两个指针的移动,窗口在不断滑动,窗口中的元素也在不断变换。

根据两个指针移动的速度是否相同,可以将窗口分为固定窗口和可变窗口。

固定窗口一般是求各个窗口和的最值,均值的最值,可变窗口一般是求最大窗口或者最小窗口。

子数组最大平均数 I

问题描述

给你一个由 n 个元素组成的整数数组 nums 和一个整数 k 。请你找出平均数最大且 长度为 k 的连续子数组,并输出该最大平均数。任何误差小于 10-5 的答案都将被视为正确答案。详见leetcode643

问题分析

这是一个固定窗口问题,窗口大小为k,可以设置两个指针left和right,初始时,left指向0,right指向k,计算窗口和,每次left和right向右移动1直至left移动到数组右边界,不断计算窗口和,取窗口和的最大值除以k,得到最大平均数返回。

代码实现

public double findMaxAverage(int[] nums, int k) {
	if(k>nums.length){
	    return 0;
	}
	int maxSum = Integer.MIN_VALUE;
	int left = 0;
	int right = k;
	while(right<=nums.length){
	    int sum = 0;
	    for(int i=left;i<right;i++){
	        sum += nums[i];
	    }
	    if(sum>maxSum){
	        maxSum = sum;
	    }
	    left++;
	    right++;
	}
	return (double)maxSum/k;
}

代码优化

上述代码与我们的问题分析一致,但是会出现当测试用例规模很大时不通过,这是因为,我们每滑动一次窗口,就会计算一次窗口所有元素求和,这样加法的次数太大了,其实,窗口没滑动一次,会有一个旧元素离开窗口,一个新元素进入窗口,我们只需要在原来的基础上加新减旧就可以了

优化实现

public double findMaxAverage(int[] nums, int k) {
    int sum=0;
    int n = nums.length;
    for(int i=0;i<k;i++){
        sum += nums[i];
    }
    int maxSum = sum;
    for(int i=k;i<n;i++){
        sum = sum+nums[i]-nums[i-k];
        if(sum>maxSum){
            maxSum=sum;
        }
    }
    return (double)maxSum/k;
}

最长连续递增序列

问题描述

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], …, nums[r - 1], nums[r]] 就是连续递增子序列。详见leetcode674

问题分析

这是一个可变窗口问题,本质上就是求最大窗口。可以设置两个指针left和right,初始时,left指向0,right指向1,判断right只想如果递增,计数加一,否则left指针移动到right。

代码实现

public int findLengthOfLCIS(int[] nums) {
    if(nums.length==0||nums.length==1){
        return nums.length;
    }
    int left=0;
    int right=1;
    int res = 0;
    while(right<nums.length){
        if(nums[right-1]>=nums[right]){
            left =right;
        }
        right++;
        if(right-left>res){
            res = right-left;
        }
    }
    return res;
}

代码优化

我们可以在遍历过程中直接判断,如果是递增序列计数器加1,否则计数器置1重新计算

优化实现

public int findLengthOfLCIS(int[] nums) {
    if(nums.length==0||nums.length==1){
        return nums.length;
    }
    int res = 1;
    int count =1;
    for(int i=1;i<nums.length;i++){
        if(nums[i-1]>=nums[i]){
            count =1;
        }else{
            count++;
        }
        if(count>res){
            res = count;
        }
    }
    return res;
}

你可能感兴趣的:(算法训练营,算法)