Skip to main content

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}