Skip to main content

hashing/
lib.rs

1//! # Hashing
2
3/// 336h Palindrome Pairs
4struct Sol336 {}
5
6impl Sol336 {
7    pub fn palindrome_pairs(words: Vec<String>) -> Vec<Vec<i32>> {
8        use std::collections::{HashMap, HashSet};
9
10        let hwords: HashMap<_, _> = words
11            .iter()
12            .enumerate()
13            .map(|(i, word)| (word.chars().rev().collect::<String>(), i))
14            .collect();
15        println!("-> {hwords:?}");
16
17        let is_palindrome = |s: &str| {
18            let (mut l, mut r) = (0, s.len().saturating_sub(1));
19            while l < r {
20                if s[l..l + 1] != s[r..r + 1] {
21                    return false;
22                }
23                l += 1;
24                r = r.saturating_sub(1);
25            }
26            true
27        };
28
29        let mut spairs = HashSet::new();
30        for (i, word) in words.iter().enumerate() {
31            for p in 0..=word.len() {
32                let lword = &word[..p];
33
34                if let Some(&j) = hwords.get(lword) {
35                    if i != j && is_palindrome(&word[p..]) {
36                        spairs.insert(vec![i as i32, j as i32]);
37                    }
38                }
39
40                let rword = &word[word.len() - p..];
41                if let Some(&j) = hwords.get(rword) {
42                    if j != i && is_palindrome(&word[..word.len() - p]) {
43                        spairs.insert(vec![j as i32, i as i32]);
44                    }
45                }
46            }
47        }
48        println!("-> {spairs:?}");
49
50        spairs.drain().collect()
51    }
52}
53
54/// 599 Minimum Index Sum of Two Lists
55struct Sol599;
56
57impl Sol599 {
58    pub fn find_restaurant(list1: Vec<String>, list2: Vec<String>) -> Vec<String> {
59        use std::collections::{BTreeMap, HashMap};
60
61        let hm1: HashMap<_, _> = list1.iter().enumerate().map(|(i, s)| (s, i)).collect();
62
63        let mut m: BTreeMap<usize, Vec<String>> = BTreeMap::new();
64        for (i, s) in list2.iter().enumerate() {
65            if hm1.contains_key(s) {
66                m.entry(i + hm1[s])
67                    .and_modify(|v| v.push(s.to_string()))
68                    .or_insert(vec![s.to_string()]);
69            }
70        }
71
72        println!("-> {:?}", m);
73
74        match m.first_key_value() {
75            Some((_, v)) => v.to_vec(),
76            _ => vec![],
77        }
78    }
79}
80
81/// 763m Partition Labels
82struct Sol763;
83
84impl Sol763 {
85    pub fn partition_labels(s: String) -> Vec<i32> {
86        use std::collections::HashMap;
87
88        let mut lasts = HashMap::new();
89        for (i, chr) in s.chars().enumerate() {
90            lasts.entry(chr).and_modify(|last| *last = i).or_insert(i);
91        }
92
93        println!("-> {:?}", lasts);
94
95        let mut parts = vec![];
96        let (mut start, mut end) = (0, 0);
97        for (i, chr) in s.chars().enumerate() {
98            end = end.max(lasts[&chr]);
99
100            if i == end {
101                parts.push((end - start + 1) as i32);
102                start = i + 1;
103            }
104        }
105
106        parts
107    }
108}
109
110/// 869m Reordered Power of 2
111struct Sol869 {}
112
113impl Sol869 {
114    pub fn reordered_power_of2(n: i32) -> bool {
115        let mut nfreqs = [0; 10];
116        let mut n = n;
117        while n > 0 {
118            nfreqs[(n % 10) as usize] += 1;
119            n /= 10;
120        }
121
122        let mut p = 1;
123        while p <= 1e9 as i64 {
124            let mut pfreqs = [0; 10];
125            let mut n = p as i32;
126            while n > 0 {
127                pfreqs[(n % 10) as usize] += 1;
128                n /= 10;
129            }
130
131            if (0..=9).all(|d| pfreqs[d] == nfreqs[d]) {
132                return true;
133            }
134
135            p <<= 1;
136        }
137
138        false
139    }
140}
141
142/// 898m Bitwise ORs of Subarrays
143struct Sol898 {}
144
145impl Sol898 {
146    pub fn subarray_bitwise_o_rs(arr: Vec<i32>) -> i32 {
147        use std::collections::HashSet;
148        use std::iter::once;
149
150        let mut cur = HashSet::new();
151
152        arr.iter()
153            .fold(HashSet::<i32>::new(), |mut ors, &n| {
154                cur = cur.iter().map(|&x| n | x).chain(once(n)).collect();
155                ors.extend(&cur);
156
157                ors
158            })
159            .len() as _
160    }
161}
162
163/// 1128 Number of Equivalent Domino Pairs
164struct Sol1128;
165
166impl Sol1128 {
167    pub fn num_equiv_domino_pairs(dominoes: Vec<Vec<i32>>) -> i32 {
168        let mut hash = vec![0; 100];
169
170        dominoes.iter().fold(0, |mut pairs, domino| {
171            let hval = match domino[0].cmp(&domino[1]) {
172                std::cmp::Ordering::Less => 10 * domino[0] + domino[1],
173                _ => 10 * domino[1] + domino[0],
174            } as usize;
175            pairs += hash[hval];
176            hash[hval] += 1;
177
178            pairs
179        })
180    }
181}
182
183/// 1399 Count Largest Group
184struct Sol1399;
185
186impl Sol1399 {
187    /// 1 <= N <= 10^4
188    pub fn count_largest_group(n: i32) -> i32 {
189        use std::collections::HashMap;
190
191        let mut xmap = HashMap::new();
192        for mut n in 1..=n {
193            let mut sum = 0;
194            while n > 0 {
195                sum += n % 10;
196                n /= 10;
197            }
198
199            xmap.entry(sum).and_modify(|f| *f += 1).or_insert(1);
200        }
201
202        println!("-> {:?}", xmap);
203
204        match xmap.values().max() {
205            Some(x) => xmap.values().filter(|&f| f == x).count() as i32,
206            _ => 0,
207        }
208    }
209}
210
211/// 1726m Tuple With Same Product
212struct Sol1726;
213
214impl Sol1726 {
215    pub fn tuple_same_product(nums: Vec<i32>) -> i32 {
216        use std::collections::HashMap;
217
218        let mut fqs = HashMap::new();
219        for i in 0..nums.len() {
220            for j in i + 1..nums.len() {
221                fqs.entry(nums[i] * nums[j])
222                    .and_modify(|f| *f += 1)
223                    .or_insert(1);
224            }
225        }
226
227        println!("-> {:?}", fqs);
228
229        fqs.into_values()
230            .filter(|&f| f > 1)
231            .map(|f| (f - 1) * f / 2) // nCk :: n!/k!(n-k)!
232            .sum::<i32>()
233            * 8
234    }
235}
236
237/// 1790 Check if One String Swap Can Make Strings Equal
238struct Sol1790;
239
240impl Sol1790 {
241    pub fn are_almost_equal(s1: String, s2: String) -> bool {
242        use std::collections::HashMap;
243
244        let diffv = s1
245            .chars()
246            .zip(s2.chars())
247            .filter(|(c1, c2)| c1 != c2)
248            .take(3)
249            .collect::<Vec<_>>();
250
251        println!(
252            ":: {} ~ {:?}",
253            diffv.is_empty()
254                || diffv.len() == 2 && diffv[0].0 == diffv[1].1 && diffv[0].1 == diffv[1].0,
255            diffv
256        );
257
258        let (mut hm1, mut hm2) = (HashMap::new(), HashMap::new());
259        let diffs =
260            s1.chars()
261                .zip(s2.chars())
262                .filter(|(c1, c2)| c1 != c2)
263                .fold(0, |r, (c1, c2)| {
264                    hm1.entry(c1).and_modify(|f| *f += 1).or_insert(1);
265                    hm2.entry(c2).and_modify(|f| *f += 1).or_insert(1);
266                    r + 1
267                });
268
269        println!("-> {:?} | {:?}", hm1, hm2);
270
271        if diffs > 2 {
272            return false;
273        }
274
275        for (chr, f1) in hm1 {
276            if let Some(&f2) = hm2.get(&chr) {
277                if f2 != f1 {
278                    return false;
279                }
280            } else {
281                return false;
282            }
283        }
284        true
285    }
286}
287
288/// 1865m Finding Pairs With a Certain Sum
289#[derive(Debug)]
290struct Sol1865 {
291    nums1: Vec<i32>,
292    nums2: Vec<i32>,
293    m: std::collections::HashMap<i32, i32>,
294}
295
296impl Sol1865 {
297    fn new(nums1: Vec<i32>, nums2: Vec<i32>) -> Self {
298        let mut m = std::collections::HashMap::new();
299        for &n in nums2.iter() {
300            *m.entry(n).or_insert(0) += 1;
301        }
302        println!("-> {m:?}");
303
304        Sol1865 { nums1, nums2, m }
305    }
306
307    fn add(&mut self, index: i32, val: i32) {
308        let index = index as usize;
309
310        self.m.entry(self.nums2[index]).and_modify(|f| *f -= 1);
311        self.nums2[index] += val;
312        self.m
313            .entry(self.nums2[index])
314            .and_modify(|f| *f += 1)
315            .or_insert(1);
316    }
317
318    fn count(&self, total: i32) -> i32 {
319        self.nums1.iter().fold(0, |count, &n| {
320            count + self.m.get(&(total - n)).unwrap_or(&0)
321        })
322    }
323}
324
325/// 2206 Divide Array Into Equal Pairs
326struct Sol2206;
327
328impl Sol2206 {
329    pub fn divide_array(nums: Vec<i32>) -> bool {
330        use std::collections::HashMap;
331
332        println!("-> {}", nums.iter().fold(0, |xors, n| xors ^ n) == 0);
333
334        nums.iter()
335            .fold(HashMap::new(), |mut frq, &n| {
336                frq.entry(n).and_modify(|f| *f += 1).or_insert(1);
337                frq
338            })
339            .into_values()
340            .all(|v| v & 1 == 0)
341    }
342}
343
344/// 2342m Max Sum of a Pair With Equal Sum of Digits
345struct Sol2342;
346
347impl Sol2342 {
348    pub fn maximum_sum(nums: Vec<i32>) -> i32 {
349        let mut mem = [0; 9 * 9 + 1];
350
351        let mut rst = -1;
352        nums.iter().for_each(|&n| {
353            let (mut dsum, mut x) = (0, n as usize);
354            while x > 0 {
355                dsum += x % 10;
356                x /= 10;
357            }
358
359            if mem[dsum] > 0 {
360                rst = rst.max(mem[dsum] + n);
361            }
362            mem[dsum] = mem[dsum].max(n);
363        });
364
365        println!("-> {:?}", mem);
366
367        rst
368    }
369}
370
371use std::cmp::Reverse;
372use std::collections::{BTreeSet, BinaryHeap, HashMap};
373
374/// 2349m Design a Number Container System
375struct NumberContainers {
376    nmap: HashMap<i32, BinaryHeap<Reverse<i32>>>, // number -> PQ(index...)
377    minds: HashMap<i32, i32>,                     // index -> number
378
379    nset: HashMap<i32, BTreeSet<i32>>, // with BTreeSet :: number -> TreeSet(index...)
380}
381
382impl NumberContainers {
383    fn new() -> Self {
384        NumberContainers {
385            nmap: HashMap::new(),
386            minds: HashMap::new(),
387
388            nset: HashMap::new(),
389        }
390    }
391
392    fn change(&mut self, index: i32, number: i32) {
393        if let Some(&prv) = self.minds.get(&index) {
394            if let Some(nset) = self.nset.get_mut(&prv) {
395                nset.remove(&index);
396                if nset.is_empty() {
397                    self.nset.remove(&prv);
398                }
399            }
400        }
401        self.nset.entry(number).or_default().insert(index);
402
403        self.minds.insert(index, number);
404        self.nmap
405            .entry(number)
406            .and_modify(|pq| pq.push(Reverse(index)))
407            .or_insert(BinaryHeap::from([Reverse(index)]));
408
409        println!("-> {:?} {:?} {:?}", self.minds, self.nmap, self.nset);
410    }
411
412    fn find(&mut self, number: i32) -> i32 {
413        println!(
414            " ? {:?}",
415            if let Some(nset) = self.nset.get(&number) {
416                nset.first()
417            } else {
418                Some(&-1)
419            }
420        );
421
422        if let Some(pq) = self.nmap.get_mut(&number) {
423            while let Some(&Reverse(i)) = pq.peek() {
424                if let Some(&n) = self.minds.get(&i) {
425                    if n == number {
426                        return i;
427                    }
428
429                    pq.pop();
430                }
431            }
432        }
433
434        -1
435    }
436}
437
438/// 2363m Merge Similar Items
439struct Sol2363 {}
440
441impl Sol2363 {
442    pub fn merge_similar_items(items1: Vec<Vec<i32>>, items2: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
443        use std::collections::BTreeMap;
444
445        let mut merged = BTreeMap::new();
446        for item in items1 {
447            merged.insert(item[0], item[1]);
448        }
449        for item in items2 {
450            merged
451                .entry(item[0])
452                .and_modify(|w| *w += item[1])
453                .or_insert(item[1]);
454        }
455
456        merged.iter().map(|(&i, &w)| vec![i, w]).collect()
457    }
458}
459
460/// 2364m Count Number of Bad Pairs
461struct Sol2364;
462
463impl Sol2364 {
464    pub fn count_bad_pairs(nums: Vec<i32>) -> i64 {
465        use std::collections::HashMap;
466
467        let mut hmap = HashMap::new();
468        nums.iter().enumerate().fold(
469            nums.len() as i64 * (nums.len() as i64 - 1) / 2, // total pairs: nCk n!/k!(n-k)!
470            |r, (i, v)| {
471                hmap.entry(v - i as i32)
472                    .and_modify(|count| *count += 1)
473                    .or_insert(1);
474
475                match hmap.get(&(v - i as i32)) {
476                    Some(count) => r - count + 1,
477                    _ => r,
478                }
479            },
480        )
481    }
482}
483
484/// 2570 Merge Two 2D Arrays by Summing Values
485struct Sol2570;
486
487impl Sol2570 {
488    /// 1 <= N_i[id_i, value_i] <= 1000
489    pub fn merge_arrays(nums1: Vec<Vec<i32>>, nums2: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
490        let mut rst = vec![];
491        let (mut l, mut r) = (0, 0);
492
493        use std::cmp::Ordering::*;
494        while l < nums1.len() && r < nums2.len() {
495            match nums1[l][0].cmp(&nums2[r][0]) {
496                Equal => {
497                    rst.push(vec![nums1[l][0], nums1[l][1] + nums2[r][1]]);
498                    l += 1;
499                    r += 1;
500                }
501                Greater => {
502                    rst.push(nums2[r].to_vec());
503                    r += 1;
504                }
505                Less => {
506                    rst.push(nums1[l].to_vec());
507                    l += 1;
508                }
509            }
510        }
511
512        while l < nums1.len() {
513            rst.push(nums1[l].to_vec());
514            l += 1;
515        }
516        while r < nums2.len() {
517            rst.push(nums2[r].to_vec());
518            r += 1;
519        }
520
521        println!("-> {:?}", rst);
522
523        {
524            let mut merge = vec![0; 1000 + 1];
525            for nums in [nums1, nums2] {
526                for v in nums {
527                    merge[v[0] as usize] += v[1];
528                }
529            }
530
531            let mut rst = vec![];
532            for (i, &v) in merge.iter().enumerate() {
533                if v > 0 {
534                    rst.push(vec![i as i32, v]);
535                }
536            }
537
538            println!("-> {:?}", rst);
539        }
540
541        rst
542    }
543}
544
545/// 2661m First Completely Painted Row or Column
546struct Sol2661;
547
548impl Sol2661 {
549    pub fn first_complete_index(arr: Vec<i32>, mat: Vec<Vec<i32>>) -> i32 {
550        use std::collections::HashMap;
551
552        let (rows, cols) = (mat.len(), mat[0].len());
553        let mut hm = HashMap::new();
554
555        (0..rows).for_each(|r| {
556            (0..cols).for_each(|c| {
557                hm.insert(mat[r][c], (r, c));
558            })
559        });
560
561        let (mut rcount, mut ccount) = (vec![0; rows], vec![0; cols]);
562
563        arr.iter()
564            .take_while(|n| match hm.get(n) {
565                Some(&(r, c)) => {
566                    rcount[r] += 1;
567                    ccount[c] += 1;
568                    rcount[r] != cols && ccount[c] != rows
569                }
570                _ => true,
571            })
572            .count() as i32
573    }
574}
575
576/// 2965 Find Missing and Repeated Values
577struct Sol2965;
578
579impl Sol2965 {
580    pub fn find_missing_and_repeated_values(grid: Vec<Vec<i32>>) -> Vec<i32> {
581        let mut m = vec![0; grid.len() * grid.len() + 1];
582
583        for row in grid {
584            for n in row {
585                m[n as usize] += 1;
586            }
587        }
588
589        let mut rst = vec![0; 2];
590        for (n, &v) in m.iter().enumerate().skip(1) {
591            match v {
592                2 => rst[0] = n as i32,
593                0 => rst[1] = n as i32,
594                _ => (),
595            }
596        }
597
598        println!("-> {:?}", rst);
599
600        rst
601    }
602}
603
604/// 3085m Minimum Deletions to Make String K-Special
605struct Sol3085 {}
606
607impl Sol3085 {
608    pub fn minimum_deletions(word: String, k: i32) -> i32 {
609        use std::collections::HashMap;
610
611        let mut fmap = HashMap::new();
612        for chr in word.chars() {
613            fmap.entry(chr).and_modify(|f| *f += 1).or_insert(1);
614        }
615        println!("-> {fmap:?}");
616
617        let freqs: Vec<_> = fmap.values().copied().collect();
618        println!("-> {freqs:?}");
619
620        fmap.iter().fold(word.len() as i32, |mdels, (_, &f)| {
621            let mut dels = 0;
622            for &frq in &freqs {
623                if f > frq {
624                    dels += frq;
625                } else if f + k < frq {
626                    dels += frq - (f + k);
627                }
628            }
629
630            mdels.min(dels)
631        })
632    }
633}
634
635/// 3160m Find the Number of Distinct Colors Among the Balls
636struct Sol3160;
637
638impl Sol3160 {
639    pub fn query_results(limit: i32, queries: Vec<Vec<i32>>) -> Vec<i32> {
640        use std::collections::HashMap;
641
642        println!("|| {:?}", limit);
643
644        let (mut colors, mut balls) = (HashMap::new(), HashMap::new());
645        let mut rst = vec![];
646
647        queries.iter().for_each(|v| {
648            let (ball, color) = (v[0] as usize, v[1] as usize);
649
650            if let Some(&prv) = balls.get(&ball) {
651                colors.entry(prv).and_modify(|f| *f -= 1);
652                if let Some(&f) = colors.get(&prv) {
653                    if f == 0 {
654                        colors.remove(&prv);
655                    }
656                }
657            }
658
659            balls
660                .entry(ball)
661                .and_modify(|f| *f = color)
662                .or_insert(color);
663            colors.entry(color).and_modify(|f| *f += 1).or_insert(1);
664
665            println!("-> {:?} ~ {:?}", balls, colors);
666
667            rst.push(colors.len() as i32);
668        });
669
670        println!(":: {:?}", rst);
671
672        rst
673    }
674}
675
676/// 3375 Minimum Operations to Make Array Values Equal to K
677struct Sol3375;
678
679impl Sol3375 {
680    pub fn min_operations(nums: Vec<i32>, k: i32) -> i32 {
681        use std::collections::HashSet;
682
683        let mut set = HashSet::new();
684
685        use std::cmp::Ordering::*;
686        for n in nums {
687            match n.cmp(&k) {
688                Less => {
689                    return -1;
690                }
691                Greater => {
692                    set.insert(n);
693                }
694                _ => (),
695            }
696        }
697
698        set.len() as i32
699    }
700}
701
702/// 3484m Design Spreadsheet
703#[derive(Debug)]
704struct Spreadsheet3484 {
705    cells: std::collections::HashMap<String, i32>,
706}
707
708impl Spreadsheet3484 {
709    fn new(rows: i32) -> Self {
710        Spreadsheet3484 {
711            cells: std::collections::HashMap::with_capacity(26 * rows as usize),
712        }
713    }
714
715    fn set_cell(&mut self, cell: String, value: i32) {
716        self.cells.insert(cell, value);
717    }
718
719    fn reset_cell(&mut self, cell: String) {
720        self.cells.insert(cell, 0);
721    }
722
723    fn get_value(&self, formula: String) -> i32 {
724        formula[1..]
725            .split('+')
726            .map(|cell| {
727                if cell.starts_with(char::is_numeric) {
728                    cell.parse::<i32>().unwrap()
729                } else {
730                    *self.cells.get(cell).unwrap_or(&0)
731                }
732            })
733            .sum::<i32>()
734    }
735}
736
737/// 3508m Implement Router
738#[derive(Debug)]
739struct Router3508 {
740    fifo: std::collections::VecDeque<(i32, i32, i32)>,
741    pkts: std::collections::HashSet<(i32, i32, i32)>,
742    dsts: std::collections::HashMap<i32, std::collections::BTreeMap<i32, i32>>,
743}
744
745impl Router3508 {
746    /// 1 <= Src, Dst <= 2*10^5
747    /// 1 <= T, T_start <= T_end <= 10^9
748    fn new(memory_limit: i32) -> Self {
749        Router3508 {
750            fifo: std::collections::VecDeque::with_capacity(memory_limit as usize),
751            pkts: std::collections::HashSet::with_capacity(memory_limit as usize),
752            dsts: std::collections::HashMap::new(),
753        }
754    }
755
756    fn add_packet(&mut self, source: i32, destination: i32, timestamp: i32) -> bool {
757        if self.pkts.contains(&(source, destination, timestamp)) {
758            false
759        } else {
760            if self.fifo.len() == self.fifo.capacity() {
761                if let Some((src, dst, ts)) = self.fifo.pop_front() {
762                    self.pkts.remove(&(src, dst, ts));
763                    self.dsts
764                        .get_mut(&dst)
765                        .unwrap()
766                        .entry(ts)
767                        .and_modify(|count| *count -= 1);
768                }
769            }
770
771            self.fifo.push_back((source, destination, timestamp));
772            self.pkts.insert((source, destination, timestamp));
773
774            self.dsts
775                .entry(destination)
776                .or_insert(std::collections::BTreeMap::new())
777                .entry(timestamp)
778                .and_modify(|count| *count += 1)
779                .or_insert(1);
780
781            true
782        }
783    }
784
785    fn forward_packet(&mut self) -> Vec<i32> {
786        if let Some((src, dst, ts)) = self.fifo.pop_front() {
787            self.pkts.remove(&(src, dst, ts));
788            self.dsts
789                .get_mut(&dst)
790                .unwrap()
791                .entry(ts)
792                .and_modify(|count| *count -= 1);
793
794            vec![src, dst, ts]
795        } else {
796            vec![]
797        }
798    }
799
800    fn get_count(&self, destination: i32, start_time: i32, end_time: i32) -> i32 {
801        self.dsts
802            .get(&destination)
803            .unwrap()
804            .range(start_time..=end_time)
805            .map(|(_, count)| count)
806            .sum::<i32>()
807    }
808}
809
810#[cfg(test)]
811mod tests;