スライディングウィンドウの実装

スライディングウィンドウアルゴリズムの実装を解説。固定・動的ウィンドウサイズ、配列の部分和を検索するユースケース(レートリミッター等)、ウィンドウをスライドさせる処理の流れをGoコードで紹介します。

Read in: en
スライディングウィンドウの実装

スライディングウィンドウとは

配列のサブアレイを”ウィンドウ(サブセット)”をずらすしていくように探索するアルゴリズム。

ウィンドウサイズは固定または動的。

実例としては、レートリミッターで使われたりする。

実装

ソースコードは以下。

sliding_window

与えられた配列から合計がN以上になるサブアレイを探索する関数。

package main

import "fmt"

func SlidingWindow(s []int, sum int) [][]int {
	rslt := [][]int{}
	windowSum := 0
	windowStart := 0

	for windowEnd := 0; windowEnd < len(s); windowEnd++ {
		windowSum += s[windowEnd]

		// サブアレイを見つける
		for windowSum >= sum {
			rslt = append(rslt, s[windowStart:windowEnd+1])
			windowSum -= s[windowStart]
			windowStart++
		}
	}

	return rslt
}

func main() {
	s := []int{1, 3, 2, 6, 4, 9, 9, 5}
	sum := 9
	subAry := SlidingWindow(s, sum)
	for _, sa := range subAry {
		fmt.Println(sa)
	}
}
// 出力
[1 3 2 6]
[3 2 6]
[2 6 4]
[6 4]
[4 9]
[9]
[9]

SlidingWindow関数の処理の流れとしてはこんな感じ。

  1. データの先頭から開始位置までウィンドウを配置
  2. ウィンドウ内の要素が条件を満たすかどうかを確認
  3. 条件を満たす場合、ウィンドウ内のサブアレイを結果に追加
  4. ウィンドウを右に1段階スライド
  5. ウィンドウがデータの終わりに達するまで、手順 3 ~ 5 を繰り返す

ウィンドウがずれていくイメージが次の通り。

[1 3 2 6] ← 最初に見つかった条件を満たすウィンドウ
[3 2 6] ←条件を満たすウィンドウ内で更に探索

[2 6 4]  ←探索開始位置をズラして次のウィンドウを確保
[6 4]  ←ウィンドウ内を更に探索

以下繰り返し・・・
[4 9]
[9]

[9]

配列を扱う問題で応用が効く。

最適解ではないが、leetcode.com - two-sumはスライディングウィンドウを使って解くこともできる。

追記

この動画が分かりやすかった。

youtube.com - Solve subarray problems FASTER (using Sliding Windows)

ウインドウサイズが固定の場合、動的な場合の解説がある。

参考

Tags: スライディングウィンドウ
Share: 𝕏 Post Facebook Hatena
✏️ View source / Discuss on GitHub
☕ サポート

このブログを応援していただける方は、以下からサポートをお願いします。いただいたサポートはブログ運営・技術研鑽に活用します。


関連記事