rust_algorithms/other/two_pointers.rs
1//! Ikki ko'rsatkich (two pointers) texnikasi.
2//!
3//! **G'oya:** ichma-ich ikki tsikl (O(n²)) o'rniga, ikkita indeksni **bir yo'nalishda
4//! yoki qarama-qarshi** harakatlantirib, bitta yurishda javob topamiz — O(n).
5//!
6//! Ko'pincha massiv **tartiblangan** bo'lishi kerak.
7
8/// Tartiblangan massivda yig'indisi `target` ga teng ikkita son topadi.
9///
10/// **G'oya:** ikki ko'rsatkich — biri boshda, biri oxirida.
11/// Yig'indi katta bo'lsa o'ngdagini chapga suramiz, kichik bo'lsa chapdagini o'ngga.
12///
13/// ```text
14/// [1, 3, 4, 6, 8, 11] target = 10
15/// ↑ ↑ 1 + 11 = 12 > 10 → o'ngni suramiz
16/// ↑ ↑ 1 + 8 = 9 < 10 → chapni suramiz
17/// ↑ ↑ 3 + 8 = 11 > 10 → o'ngni suramiz
18/// ↑ ↑ 3 + 6 = 9 < 10 → chapni suramiz
19/// ↑ ↑ 4 + 6 = 10 ✓
20/// ```
21///
22/// - **Time:** O(n) (hash-jadvalsiz!), **Space:** O(1).
23///
24/// # Misol
25/// ```
26/// use rust_algorithms::other::two_pointers::two_sum_sorted;
27///
28/// assert_eq!(two_sum_sorted(&[1, 3, 4, 6, 8, 11], 10), Some((2, 3)));
29/// assert_eq!(two_sum_sorted(&[1, 2], 100), None);
30/// ```
31pub fn two_sum_sorted(nums: &[i64], target: i64) -> Option<(usize, usize)> {
32 if nums.len() < 2 {
33 return None;
34 }
35 let (mut chap, mut ong) = (0usize, nums.len() - 1);
36 while chap < ong {
37 let yigindi = nums[chap] + nums[ong];
38 match yigindi.cmp(&target) {
39 std::cmp::Ordering::Equal => return Some((chap, ong)),
40 std::cmp::Ordering::Less => chap += 1,
41 std::cmp::Ordering::Greater => ong -= 1,
42 }
43 }
44 None
45}
46
47/// Tartiblangan massivdan takrorlarni **joyida** olib tashlaydi.
48///
49/// Qaytadi: yangi (noyob) elementlar soni. Massivning shu qadar boshlang'ich qismi
50/// to'g'ri qiymatlarni saqlaydi.
51///
52/// **G'oya:** `yozish` ko'rsatkichi noyob qiymatlar uchun, `oqish` — skanerlash uchun.
53///
54/// - **Time:** O(n), **Space:** O(1).
55///
56/// # Misol
57/// ```
58/// use rust_algorithms::other::two_pointers::remove_duplicates;
59///
60/// let mut v = vec![1, 1, 2, 2, 2, 3, 4, 4];
61/// let n = remove_duplicates(&mut v);
62/// assert_eq!(n, 4);
63/// assert_eq!(&v[..n], &[1, 2, 3, 4]);
64/// ```
65pub fn remove_duplicates<T: PartialEq + Copy>(nums: &mut [T]) -> usize {
66 if nums.is_empty() {
67 return 0;
68 }
69 let mut yozish = 1usize;
70 for oqish in 1..nums.len() {
71 if nums[oqish] != nums[yozish - 1] {
72 nums[yozish] = nums[oqish];
73 yozish += 1;
74 }
75 }
76 yozish
77}
78
79/// Eng ko'p suv sig'diradigan idish (container with most water).
80///
81/// Balandliklari berilgan ustunlardan ikkitasini tanlab, ular orasidagi
82/// maksimal suv hajmini topamiz: `hajm = min(h[i], h[j]) × (j − i)`.
83///
84/// **G'oya:** ikki chetdan boshlaymiz va **pastroq** devorni ichkariga suramiz —
85/// chunki uni qoldirib, kenglikni kamaytirish hech qachon foyda bermaydi.
86///
87/// - **Time:** O(n), **Space:** O(1).
88///
89/// # Misol
90/// ```
91/// use rust_algorithms::other::two_pointers::max_water_container;
92///
93/// assert_eq!(max_water_container(&[1, 8, 6, 2, 5, 4, 8, 3, 7]), 49);
94/// assert_eq!(max_water_container(&[1, 1]), 1);
95/// ```
96pub fn max_water_container(heights: &[i64]) -> i64 {
97 if heights.len() < 2 {
98 return 0;
99 }
100 let (mut chap, mut ong) = (0usize, heights.len() - 1);
101 let mut eng_katta = 0i64;
102
103 while chap < ong {
104 let hajm = heights[chap].min(heights[ong]) * (ong - chap) as i64;
105 eng_katta = eng_katta.max(hajm);
106 if heights[chap] < heights[ong] {
107 chap += 1;
108 } else {
109 ong -= 1;
110 }
111 }
112 eng_katta
113}
114
115/// Yig'indisi nolga teng bo'lgan barcha uchliklar (3Sum) — takrorsiz.
116///
117/// **G'oya:** massivni tartiblab, har bir element uchun qolganida
118/// [`two_sum_sorted`] mantiqini qo'llaymiz.
119///
120/// - **Time:** O(n²), **Space:** O(n) (natijadan tashqari).
121///
122/// # Misol
123/// ```
124/// use rust_algorithms::other::two_pointers::three_sum_zero;
125///
126/// let mut r = three_sum_zero(&[-1, 0, 1, 2, -1, -4]);
127/// r.sort();
128/// assert_eq!(r, vec![vec![-1, -1, 2], vec![-1, 0, 1]]);
129/// ```
130pub fn three_sum_zero(nums: &[i64]) -> Vec<Vec<i64>> {
131 let mut v = nums.to_vec();
132 v.sort_unstable();
133 let n = v.len();
134 let mut natija = Vec::new();
135
136 for i in 0..n.saturating_sub(2) {
137 if i > 0 && v[i] == v[i - 1] {
138 continue; // takror uchliklardan qochamiz
139 }
140 let (mut chap, mut ong) = (i + 1, n - 1);
141 while chap < ong {
142 let yigindi = v[i] + v[chap] + v[ong];
143 match yigindi.cmp(&0) {
144 std::cmp::Ordering::Equal => {
145 natija.push(vec![v[i], v[chap], v[ong]]);
146 while chap < ong && v[chap] == v[chap + 1] {
147 chap += 1;
148 }
149 while chap < ong && v[ong] == v[ong - 1] {
150 ong -= 1;
151 }
152 chap += 1;
153 ong -= 1;
154 }
155 std::cmp::Ordering::Less => chap += 1,
156 std::cmp::Ordering::Greater => ong -= 1,
157 }
158 }
159 }
160 natija
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use crate::util::Rng;
167
168 #[test]
169 fn two_sum_bruteforce_bilan_mos() {
170 let mut rng = Rng::new(1001);
171 for _ in 0..50 {
172 let mut v = rng.vec(30, -30, 30);
173 v.sort_unstable();
174 let target = rng.range(-40, 40);
175
176 let natija = two_sum_sorted(&v, target);
177 let kutilgan_bor =
178 (0..v.len()).any(|i| ((i + 1)..v.len()).any(|j| v[i] + v[j] == target));
179
180 assert_eq!(natija.is_some(), kutilgan_bor, "target = {target}");
181 if let Some((i, j)) = natija {
182 assert_eq!(v[i] + v[j], target);
183 }
184 }
185 }
186
187 #[test]
188 fn takrorlarni_olib_tashlash() {
189 let mut bosh: Vec<i32> = vec![];
190 assert_eq!(remove_duplicates(&mut bosh), 0);
191
192 let mut v = vec![7];
193 assert_eq!(remove_duplicates(&mut v), 1);
194
195 let mut hammasi_teng = vec![3, 3, 3, 3];
196 assert_eq!(remove_duplicates(&mut hammasi_teng), 1);
197
198 let mut noyob = vec![1, 2, 3];
199 assert_eq!(remove_duplicates(&mut noyob), 3);
200 }
201
202 #[test]
203 fn idish_hajmi() {
204 assert_eq!(max_water_container(&[]), 0);
205 assert_eq!(max_water_container(&[5]), 0);
206 assert_eq!(max_water_container(&[4, 3, 2, 1, 4]), 16);
207 assert_eq!(max_water_container(&[1, 2, 1]), 2);
208 }
209
210 #[test]
211 fn uchliklar_togri_va_takrorsiz() {
212 let mut rng = Rng::new(1002);
213 for _ in 0..20 {
214 let v = rng.vec(25, -10, 10);
215 let uchliklar = three_sum_zero(&v);
216 for u in &uchliklar {
217 assert_eq!(u.iter().sum::<i64>(), 0);
218 }
219 let mut nusxa = uchliklar.clone();
220 nusxa.sort();
221 nusxa.dedup();
222 assert_eq!(nusxa.len(), uchliklar.len());
223 }
224 assert!(three_sum_zero(&[1, 2, 3]).is_empty());
225 }
226}