Golang每日一练(leetDay0089) 滑动窗口最大值、中位数

文章介绍了如何使用滑动窗口解决最大值和中位数问题,提供了暴力枚举、双端队列和动态规划三种方法,并给出了具体的代码示例。此外,还提到了每日一练的刷题专栏更新情况。

目录

239. 滑动窗口最大值 Sliding Window Maximum  🌟🌟🌟

480. 滑动窗口中位数 Sliding Window Median  🌟🌟🌟

🌟 每日一练刷题专栏 🌟

Rust每日一练 专栏

Golang每日一练 专栏

Python每日一练 专栏

C/C++每日一练 专栏

Java每日一练 专栏


239. 滑动窗口最大值 Sliding Window Maximum

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
 滑动窗口的位置                最大值
---------------               -----
[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

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

代码1: 暴力枚举

package main

import "fmt"

func maxSlidingWindow(nums []int, k int) []int {
	ans := make([]int, len(nums)-k+1)
	for i := 0; i <= len(nums)-k; i++ {
		max := nums[i]
		for j := i + 1; j < i+k; j++ {
			if nums[j] > max {
				max = nums[j]
			}
		}
		ans[i] = max
	}
	return ans
}

func main() {
	nums := []int{1, 3, -1, -3, 5, 3, 6, 7}
	k := 3
	fmt.Println(maxSlidingWindow(nums, k))
	nums = []int{1}
	k = 1
	fmt.Println(maxSlidingWindow(nums, k))
}

代码2: 双端队列

package main

import "fmt"

func maxSlidingWindow(nums []int, k int) []int {
	var ans []int
	q := make([]int, 0) // 双端队列,存放的是数字的下标
	for i, num := range nums {
		if len(q) > 0 && q[0] < i-k+1 {
			// 当前滑动窗口的左端已离队列滑出,则要将该元素从队列中弹出
			q = q[1:]
		}
		// 将当前数字与双端队列队尾数字比较,如果当前数字大于队列数字,则弹出队列。
		// 这是因为当前数字更大,而队列中以前数字已经没有用处,我们可以弹出它们。
		for len(q) > 0 && nums[q[len(q)-1]] < num {
			q = q[:len(q)-1]
		}
		// 将当前数字下标加入队列
		q = append(q, i)
		// 到了一个滑动窗口的结束,将当前窗口中的最大值加入结果集中
		if i >= k-1 {
			ans = append(ans, nums[q[0]])
		}
	}
	return ans
}

func main() {
	nums := []int{1, 3, -1, -3, 5, 3, 6, 7}
	k := 3
	fmt.Println(maxSlidingWindow(nums, k))
	nums = []int{1}
	k = 1
	fmt.Println(maxSlidingWindow(nums, k))
}

代码: 动态规划

package main

import "fmt"

func maxSlidingWindow(nums []int, k int) []int {
	n := len(nums)
	leftMax := make([]int, n)
	rightMax := make([]int, n)
	// 计算leftMax数组
	for i := 0; i < n; i++ {
		if i%k == 0 {
			leftMax[i] = nums[i]
		} else {
			leftMax[i] = max(leftMax[i-1], nums[i])
		}
	}
	// 计算rightMax数组
	for i := n - 1; i >= 0; i-- {
		if i == n-1 || (i+1)%k == 0 {
			rightMax[i] = nums[i]
		} else {
			rightMax[i] = max(rightMax[i+1], nums[i])
		}
	}
	// 获取每个窗口的最大值
	ans := make([]int, n-k+1)
	for i := 0; i <= n-k; i++ {
		ans[i] = max(rightMax[i], leftMax[i+k-1])
	}
	return ans
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func main() {
	nums := []int{1, 3, -1, -3, 5, 3, 6, 7}
	k := 3
	fmt.Println(maxSlidingWindow(nums, k))
	nums = []int{1}
	k = 1
	fmt.Println(maxSlidingWindow(nums, k))
}

输出:

[3 3 5 5 6 7]

[1]


480. 滑动窗口中位数 Sliding Window Median

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:

  • [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 以内的答案将被视作正确答案。

代码: 暴力枚举

package main

import (
	"fmt"
	"sort"
)

func medianSlidingWindow(nums []int, k int) []float64 {
	n := len(nums)
	if k == 1 {
		ans := make([]float64, n)
		for i := 0; i < n; i++ {
			ans[i] = float64(nums[i])
		}
		return ans
	}
	ans := make([]float64, n-k+1)
	for i := 0; i <= n-k; i++ {
		tmp := make([]int, k)
		copy(tmp, nums[i:i+k])
		sort.Ints(tmp)
		if k%2 == 0 {
			ans[i] = float64(tmp[k/2-1]+tmp[k/2]) / 2
		} else {
			ans[i] = float64(tmp[k/2])
		}
	}
	return ans
}

func main() {
	nums := []int{1, 3, -1, -3, 5, 3, 6, 7}
	k := 3
	fmt.Println(medianSlidingWindow(nums, k))
}

输出:

[1 -1 -1 3 5 6]


🌟 每日一练刷题专栏 🌟

持续,努力奋斗做强刷题搬运工!

👍 点赞,你的认可是我坚持的动力! 

🌟 收藏,你的青睐是我努力的方向! 

评论,你的意见是我进步的财富!  

 主页:https://hannyang.blog.youkuaiyun.com/ 

Rust每日一练 专栏

(2023.5.16~)更新中...

Golang每日一练 专栏

(2023.3.11~)更新中...

Python每日一练 专栏

(2023.2.18~2023.5.18)暂停更

C/C++每日一练 专栏

(2023.2.18~2023.5.18)暂停更

Java每日一练 专栏

(2023.3.11~2023.5.18)暂停更

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hann Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值