滑动窗口中位数之问题拆解 + linkedHashMap底层实现

前言

解决问题 == 问题拆解,通过滑动窗口的中位数来完成问题拆解过程,以及linkedHashMap底层实现。

一、滑动窗口中位数

在这里插入图片描述

二、问题拆解

package com.xhu.offer.everyday;

import java.util.HashMap;
import java.util.Map;

//滑动窗口中位数
public class MedianSlidingWindow {
    /*
    target:滑动窗口的中位数?
    1-滑动窗口,每次去掉begin对应的数,加入end对应的数,然后begin++,end++,得到动态窗口。
    2-窗口中位数,
    窗口长度为偶数时,取mid、 mid - 1的值求平均;
    窗口长度为奇数时,取mid的值。
    M1:带头尾节点的双向链表 + Map<index,Node>来存窗口的有序值。
    通过begin index 来删除对应Node,通过顺序查找来插入end index Node。
    通过快慢指针来获取中间节点。
    时间复杂度控制在O(N)。
     */
    public double[] medianSlidingWindow(int[] nums, int k) {
        initWindow(nums, 0, k);

        double[] rs = new double[nums.length - k + 1];
        rs[0] = findMidVal(k & 1);

        for (int begin = 1; begin <= nums.length - k; begin++) {
            //删begin节点,加入end节点
            remove(linkedHashMap.get(begin - 1));
            insertVal(nums[begin + k - 1], begin + k - 1);

            rs[begin] = findMidVal(k & 1);
        }
        return rs;
    }

    /**
     * 移除新窗口不需要的数
     * @param garbage
     */
    private void remove(Node garbage){
        //断链
        garbage.prev.next = garbage.next;
        garbage.next.prev = garbage.prev;
    }

    /**
     * 寻找窗口中的midVal
     * @param flag
     * @return
     */
    private double findMidVal(int flag) {
        //快慢指针寻找midValue
        Node slow = dummyHead;
        Node fast = dummyHead;
        while (fast != dummyTail) {
            slow = slow.next;
            fast = fast.next;
            if (fast != dummyTail) fast = fast.next;
        }
        //根据k为奇偶数来返回平均值
        if (1 == flag) return slow.val;
        //bug1:两integer value 相加可以溢出
        return slow.prev.val / 2.0 + slow.val / 2.0;
    }

    /**
     * 初始化一个k大的窗口
     * @param nums
     * @param begin
     * @param end
     */
    private void initWindow(int[] nums, int begin, int end) {
        //初始化一个k长有序的双向链表
        for (int i = begin; i < end; i++) insertVal(nums[i], i);
    }

    /**
     * 将新数据按升序插入到链表中
     * @param num
     * @param index
     */
    private void insertVal(int num, int index) {
        Node cur = dummyHead.next;
        //寻找需插入的位置
        while (cur != dummyTail && cur.val < num) cur = cur.next;
        //生成新节点
        Node node = new Node();
        node.val = num;
        //因为只有一个指针cur,所以为了保证不断链,先操作cur.prev节点。
        node.prev = cur.prev;
        cur.prev.next = node;
        //操作cur节点
        node.next = cur;
        cur.prev = node;
        //Map记录新节点位置。
        linkedHashMap.put(index, node);
    }
    //数据结构:带头尾节点的双向链表 + Map == LinkedHashMap
    Node dummyHead = new Node();
    Node dummyTail = new Node();
    Map<Integer, Node> linkedHashMap = new HashMap<>();

    {
        //初始化空链表
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
    }
    //双向链表结构
    class Node  {
        int val;//值

        Node prev;//前驱指针
        Node next;//后继指针
    }
}

总结

1)解决问题 == 问题拆解
2)linkedHashMap

参考文献

[1] LeetCode 滑动窗口中位数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值