Leetcode-239-Sliding Window Maximum

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 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       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

Therefore, return the max sliding window as [3,3,5,5,6,7].

Note:
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.

题意:给定一个数组和一个正整数k,从第一个元素开始找到k个连续的元素中最大的元素组成一个数组。

解析:暴力方法可以很简单的解决问题,遍历每个窗口内的元素找到最大值,不需要多余的存储空间,时间复杂度是O(k*n)。接下来我们看如何在这个基础上进行优化改进。

思路一:以题目中给出的例子为例,假设我们找到了第二组(例子中第二行)的Max = 3,接下来计算第三行,窗口右移,新的窗口跟原来的窗口的区别就在于第一个元素和最后一个元素,窗口新加入进来的元素是5,它大于之前窗口的最大元素,理所当然的当前窗口的最大元素就是5了。接下来是第4行,新加入的元素是3,3小于前一窗口的最大元素5,那么是不是说明当前窗口的最大元素也是5呢?这是不确定的,因为并没有考虑窗口右移去掉的那个元素,如果刚好去掉了最大的元素,那么就没办法立即定位出最大元素了,比较笨的方法就是遍历一遍当前窗口。

根据这个思路,窗口右移时如果出现了新加入的元素大于之前的最大元素时,可以立即就确定当前窗口的最大元素,反之还是需要重新遍历窗口。

代码实现:

 public class Solution
    {
        public int[] MaxSlidingWindow(int[] nums, int k)
        {
            if (nums.Length == 0)
                return new int[]{};
            if (k == 1)
                return nums;
            int[] ret = new int[nums.Length - k + 1];
            ret[0] = help(nums, k, 0);
            for (int i = k; i < nums.Length; i++)
            {
                if (ret[i - k] <= nums[i])
                    ret[i - k + 1] = nums[i];
                else
                    ret[i - k + 1] = help(nums, k, i - k + 1);
            }
            return ret;
        }
        public int help(int[] nums, int k, int begin)
        {
            int max = nums[begin];
            for (int i = begin; i <= begin + k - 1; i++)
            {
                max = max >= nums[i] ? max : nums[i];
            }
            return max;
        }
    }


思路二:如果可以借助一个数据结构,将当前窗口的元素按照降序排列,当窗口右移时,只需对数据结构进行相应的插入、删除工作同时不改变数据结构的相对顺序,这样就可以轻松的得到当前窗口的最大元素,其实一个简单的链表就可以实现这个功能了,但是链表的操作同样会拖慢效率。题目的hint提示用deque这个数据结构,这个数据结构的优点是可以在两端进行元素的插入删除,下面借助一个大神的代码,来解释一下这个思路的实现方法。

代码实现:

 public class Solution
    {
        public int[] MaxSlidingWindow(int[] nums, int k)
        {
            if (k == 0) return new int[0];
            LinkedList<int> q = new LinkedList<int>();//定义一个双端队列q,q里存储的时元素的索引,并非元素本身。
            int[] res = new int[nums.Length - k + 1];//存储结果
            for (int i = 0; i < nums.Length; i++)
            {
                //元素的索引 i 入队之前,将比nums[i]小的所有元素的索引在队列中删除,这样可以保证队列中的元素索引所指的数组对应元素是按照降序排列。
                while (q.Count != 0 && nums[i] >= nums[q.Last()])
                {
                    q.RemoveLast();
                }
                q.AddLast(i);//每个元素的索引都会在队列的末尾入队,保证入队的索引是升序排列
                //当前索引 i 与队列中第一个索引的差如果大于k,说明当前队列里的元素个数超过窗口大小,需要删除元素,因为索引是顺序入队的,所以第一个元素就是要删除的元素。
                if (i - q.First() + 1 > k)

                {
                    q.RemoveFirst();
                }
                //在 i -k +1 =0 开始对res赋值。
                if (i + 1 >= k) res[i - k + 1] = nums[q.First()];
            }
            return res;  
        }
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值