rust_algorithms/other/sliding_window.rs
1//! Siljuvchi oyna (sliding window) texnikasi.
2//!
3//! **G'oya:** ketma-ket elementlardan iborat "oyna" bo'ylab yuramiz. Oynani
4//! har safar noldan hisoblash o'rniga, **chiqib ketganini ayirib, kirganini qo'shamiz**.
5//!
6//! ```text
7//! [1, 4, 2, 10, 2, 3, 1, 0, 20] k = 4
8//! └────oyna────┘ yig'indi = 17
9//! └────oyna────┘ yig'indi = 17 − 1 + 2 = 18
10//! ```
11//!
12//! Natijada O(n·k) o'rniga **O(n)**.
13//!
14//! Ikki turi bor:
15//! - **Qat'iy o'lchamli** oyna ([`max_sum_subarray_k`]);
16//! - **O'zgaruvchan** o'lchamli oyna ([`longest_unique_substring`], [`min_subarray_len`]).
17
18use std::collections::HashMap;
19
20/// `k` uzunlikdagi qism-massivning maksimal yig'indisi.
21///
22/// - **Time:** O(n), **Space:** O(1).
23///
24/// # Misol
25/// ```
26/// use rust_algorithms::other::sliding_window::max_sum_subarray_k;
27///
28/// assert_eq!(max_sum_subarray_k(&[1, 4, 2, 10, 2, 3, 1, 0, 20], 4), Some(24));
29/// assert_eq!(max_sum_subarray_k(&[1, 2], 5), None); // k massivdan katta
30/// ```
31pub fn max_sum_subarray_k(nums: &[i64], k: usize) -> Option<i64> {
32 if k == 0 || k > nums.len() {
33 return None;
34 }
35 let mut yigindi: i64 = nums[..k].iter().sum();
36 let mut eng_katta = yigindi;
37
38 for i in k..nums.len() {
39 yigindi += nums[i] - nums[i - k]; // kirdi − chiqdi
40 eng_katta = eng_katta.max(yigindi);
41 }
42 Some(eng_katta)
43}
44
45/// Takrorlanuvchi belgisiz eng uzun qism-satr uzunligi.
46///
47/// **G'oya (o'zgaruvchan oyna):** o'ng chetni surib boramiz; takror belgi uchrasa,
48/// chap chetni o'sha belgining oldingi joyidan keyingi pozitsiyaga "sakratamiz".
49///
50/// - **Time:** O(n), **Space:** O(alifbo hajmi).
51///
52/// # Misol
53/// ```
54/// use rust_algorithms::other::sliding_window::longest_unique_substring;
55///
56/// assert_eq!(longest_unique_substring("abcabcbb"), 3); // "abc"
57/// assert_eq!(longest_unique_substring("bbbbb"), 1); // "b"
58/// assert_eq!(longest_unique_substring("pwwkew"), 3); // "wke"
59/// assert_eq!(longest_unique_substring(""), 0);
60/// ```
61pub fn longest_unique_substring(s: &str) -> usize {
62 let belgilar: Vec<char> = s.chars().collect();
63 let mut oxirgi_orin: HashMap<char, usize> = HashMap::new();
64 let mut chap = 0usize;
65 let mut eng_uzun = 0usize;
66
67 for (ong, &ch) in belgilar.iter().enumerate() {
68 if let Some(&orin) = oxirgi_orin.get(&ch) {
69 if orin >= chap {
70 chap = orin + 1; // oynani takrordan keyinga surib yuboramiz
71 }
72 }
73 oxirgi_orin.insert(ch, ong);
74 eng_uzun = eng_uzun.max(ong - chap + 1);
75 }
76 eng_uzun
77}
78
79/// Yig'indisi `target` dan **kam bo'lmagan** eng qisqa qism-massiv uzunligi.
80///
81/// Musbat sonlar uchun. Topilmasa — `None`.
82///
83/// - **Time:** O(n), **Space:** O(1).
84///
85/// # Misol
86/// ```
87/// use rust_algorithms::other::sliding_window::min_subarray_len;
88///
89/// assert_eq!(min_subarray_len(&[2, 3, 1, 2, 4, 3], 7), Some(2)); // [4, 3]
90/// assert_eq!(min_subarray_len(&[1, 1, 1], 10), None);
91/// ```
92pub fn min_subarray_len(nums: &[i64], target: i64) -> Option<usize> {
93 let mut chap = 0usize;
94 let mut yigindi = 0i64;
95 let mut eng_qisqa = usize::MAX;
96
97 for ong in 0..nums.len() {
98 yigindi += nums[ong];
99 while yigindi >= target {
100 eng_qisqa = eng_qisqa.min(ong - chap + 1);
101 yigindi -= nums[chap];
102 chap += 1;
103 }
104 }
105 if eng_qisqa == usize::MAX {
106 None
107 } else {
108 Some(eng_qisqa)
109 }
110}
111
112/// Har bir `k` o'lchamli oynadagi maksimal element (monoton deque bilan).
113///
114/// **G'oya:** deque ichida indekslarni **qiymatlari kamayadigan** tartibda saqlaymiz.
115/// Boshidagi indeks — joriy oynaning maksimumi. Har bir element deque ga
116/// bir marta kiradi va bir marta chiqadi → **O(n)**.
117///
118/// # Misol
119/// ```
120/// use rust_algorithms::other::sliding_window::max_in_windows;
121///
122/// assert_eq!(
123/// max_in_windows(&[1, 3, -1, -3, 5, 3, 6, 7], 3),
124/// vec![3, 3, 5, 5, 6, 7]
125/// );
126/// ```
127pub fn max_in_windows(nums: &[i64], k: usize) -> Vec<i64> {
128 use std::collections::VecDeque;
129
130 if k == 0 || k > nums.len() {
131 return Vec::new();
132 }
133 let mut deque: VecDeque<usize> = VecDeque::new();
134 let mut natija = Vec::with_capacity(nums.len() - k + 1);
135
136 for i in 0..nums.len() {
137 // oynadan chiqib ketgan indeksni olib tashlaymiz
138 if let Some(&bosh) = deque.front() {
139 if bosh + k <= i {
140 deque.pop_front();
141 }
142 }
143 // yangi elementdan kichik bo'lganlar hech qachon maksimum bo'lolmaydi
144 while let Some(&oxir) = deque.back() {
145 if nums[oxir] <= nums[i] {
146 deque.pop_back();
147 } else {
148 break;
149 }
150 }
151 deque.push_back(i);
152
153 if i + 1 >= k {
154 natija.push(nums[*deque.front().unwrap()]);
155 }
156 }
157 natija
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::util::Rng;
164
165 #[test]
166 fn oyna_yigindisi_bruteforce_bilan_mos() {
167 let mut rng = Rng::new(1101);
168 for _ in 0..30 {
169 let v = rng.vec(50, -20, 20);
170 for k in 1..=10 {
171 let kutilgan = v.windows(k).map(|w| w.iter().sum::<i64>()).max();
172 assert_eq!(max_sum_subarray_k(&v, k), kutilgan, "k = {k}");
173 }
174 }
175 }
176
177 #[test]
178 fn takrorsiz_qism_satr() {
179 assert_eq!(longest_unique_substring("abcdef"), 6);
180 assert_eq!(longest_unique_substring("aab"), 2);
181 assert_eq!(longest_unique_substring("dvdf"), 3);
182 assert_eq!(longest_unique_substring("o'zbek"), 6);
183 }
184
185 #[test]
186 fn eng_qisqa_qism_massiv() {
187 assert_eq!(min_subarray_len(&[1, 4, 4], 4), Some(1));
188 assert_eq!(min_subarray_len(&[], 1), None);
189 assert_eq!(min_subarray_len(&[1, 2, 3, 4, 5], 15), Some(5));
190 }
191
192 #[test]
193 fn oynadagi_maksimum_bruteforce_bilan_mos() {
194 let mut rng = Rng::new(1102);
195 for _ in 0..30 {
196 let v = rng.vec(60, -50, 50);
197 for k in 1..=8 {
198 let kutilgan: Vec<i64> = v.windows(k).map(|w| *w.iter().max().unwrap()).collect();
199 assert_eq!(max_in_windows(&v, k), kutilgan, "k = {k}");
200 }
201 }
202 assert!(max_in_windows(&[1, 2], 5).is_empty());
203 }
204}