Skip to main content

string/
lib.rs

1//! # String :: Rusty
2
3#![feature(test)]
4
5extern crate test;
6
7/// 38m Count and Say
8struct Sol38;
9
10impl Sol38 {
11    /// 1 <= n <= 30
12    pub fn count_and_say(n: i32) -> String {
13        let mut s = "1".to_string();
14        for _ in 0..n - 1 {
15            let mut enc = vec![];
16
17            let (mut count, mut prv) = (0, '^');
18            for chr in s.chars().chain("$".chars()) {
19                if chr == prv {
20                    count += 1;
21                } else {
22                    enc.push((count, prv));
23                    (count, prv) = (1, chr);
24                }
25            }
26
27            println!("-> {:?}", enc);
28
29            let mut t = String::new();
30            for (count, chr) in enc.iter().skip(1) {
31                t += &format!("{}{}", count, chr);
32            }
33
34            s = t;
35        }
36
37        println!("** {}", s);
38
39        s
40    }
41}
42
43/// 65h Valid Number
44struct Sol65;
45
46impl Sol65 {
47    pub fn is_number(s: String) -> bool {
48        // State Transition Table :: State/Input -> State
49        // ['0-9', '+|-', '.', 'e', ' ']
50        let stt = [
51            [0, 0, 0, 0, 0], // State: 0 (*Bad* State)
52            [3, 2, 4, 0, 1], // State: 1 (Start/End)
53            [3, 0, 4, 0, 0], // State: 2
54            [3, 0, 5, 6, 9], // State: 3 (End)
55            [5, 0, 0, 0, 0], // State: 4
56            [5, 0, 0, 6, 9], // State: 5 (End)
57            [8, 7, 0, 0, 0], // State: 6
58            [8, 0, 0, 0, 0], // State: 7
59            [8, 0, 0, 0, 9], // State: 8 (End)
60            [0, 0, 0, 0, 9], // State: 9 (End)
61        ];
62
63        let mut cstate = 1; // Current State := <- Start State
64
65        for chr in s.chars() {
66            cstate = match chr {
67                '0'..='9' => stt[cstate][0],
68                '+' | '-' => stt[cstate][1],
69                '.' => stt[cstate][2],
70                'e' | 'E' => stt[cstate][3],
71                ' ' => stt[cstate][4],
72                _ => return false, // Bad: input
73            }
74        }
75
76        matches!(cstate, 3 | 5 | 8 | 9)
77    }
78
79    fn is_number_enum(s: String) -> bool {
80        #[derive(Debug)]
81        enum State {
82            Start,
83            Sign,
84            Dot,
85            Int,
86            IntDot,
87            Decimal,
88            E,
89            ESign,
90            Exp,
91        }
92
93        use State::*;
94
95        let mut cstate = Start;
96        for chr in s.chars() {
97            cstate = match (&cstate, chr) {
98                (Start, '+' | '-') => Sign,
99                (Start | Sign, '.') => Dot,
100                (Start | Sign, '0'..='9') => Int,
101                (Dot | IntDot, '0'..='9') => Decimal,
102                (Int | Decimal | Exp, '0'..='9') => cstate, // No-Transition
103                (Int, '.') => IntDot,
104                (Int | Decimal | IntDot, 'e' | 'E') => E,
105                (E, '+' | '-') => ESign,
106                (E | ESign, '0'..='9') => Exp,
107
108                _ => return false,
109            }
110        }
111
112        matches!(cstate, Int | IntDot | Decimal | Exp)
113    }
114}
115
116/// 165m Compare Version Numbers
117struct Sol165 {}
118
119impl Sol165 {
120    pub fn compare_version(version1: String, version2: String) -> i32 {
121        let version1: Vec<_> = version1
122            .split('.')
123            .flat_map(|rv| rv.parse::<i32>())
124            .collect();
125        let version2: Vec<_> = version2
126            .split('.')
127            .flat_map(|rv| rv.parse::<i32>())
128            .collect();
129
130        println!("-> {version1:?} {version2:?}");
131
132        version1
133            .iter()
134            .chain(std::iter::repeat(&0))
135            .zip(version2.iter().chain(std::iter::repeat(&0)))
136            .take(version1.len().max(version2.len()))
137            .inspect(|z| println!("-> {z:?}"))
138            .filter(|&(rv1, rv2)| rv1 != rv2)
139            .nth(0)
140            .map_or(0, |(rv1, rv2)| if rv1 > rv2 { 1 } else { -1 })
141    }
142}
143
144/// 466h Count The Repetition
145struct Sol466 {}
146
147impl Sol466 {
148    /// 1 <= L1, L2 <= 100
149    pub fn get_max_repetitions(s1: String, n1: i32, s2: String, n2: i32) -> i32 {
150        let (mut counts, mut marks) = (vec![0; s2.len() + 1], vec![0; s2.len() + 1]);
151
152        let s2: Vec<_> = s2.chars().collect();
153
154        let (mut count, mut mark) = (0, 0);
155        for i in 0..n1 as usize {
156            for chr in s1.chars() {
157                if chr == s2[mark] {
158                    mark += 1;
159                }
160                if mark == s2.len() {
161                    mark = 0;
162                    count += 1;
163                }
164            }
165
166            (counts[i], marks[i]) = (count, mark);
167            println!("-> {i} {counts:?} {marks:?}");
168
169            for k in 0..i {
170                if marks[k] == mark {
171                    let prv = counts[k];
172                    let pattern = (counts[i] - counts[k]) * ((n1 - 1 - k as i32) / (i - k) as i32);
173                    let rest = counts[k + (n1 as usize - 1 - k) % (i - k)] - counts[k];
174
175                    return (prv + pattern + rest) / n2;
176                }
177            }
178        }
179
180        counts[n1 as usize - 1] / n2
181    }
182}
183
184/// 804 Unique Morse Code Words
185struct Sol804 {}
186
187impl Sol804 {
188    pub fn unique_morse_representations(words: Vec<String>) -> i32 {
189        use std::collections::HashSet;
190
191        const MORSE: [&str; 26] = [
192            ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..",
193            "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-",
194            "-.--", "--..",
195        ];
196
197        let mut codes: HashSet<String> = HashSet::new();
198        for word in words.iter() {
199            let mut code = String::new();
200            for chr in word.chars() {
201                if let Some(i) = ('a'..='z').position(|x| x == chr) {
202                    code.push_str(MORSE[i]);
203                }
204            }
205
206            codes.insert(code);
207        }
208        println!("-> {codes:?}");
209
210        codes.len() as _
211    }
212}
213
214/// 917 Reverse Only Letters
215struct Sol917;
216
217impl Sol917 {
218    pub fn reverse_only_letters(s: String) -> String {
219        let mut ichr = s.chars().rev().filter(|c| c.is_alphabetic());
220
221        s.chars()
222            .flat_map(|c| (!c.is_alphabetic()).then_some(c).or_else(|| ichr.next()))
223            .collect()
224    }
225}
226
227/// 966m Vowel Spellchecker
228struct Sol966 {}
229
230impl Sol966 {
231    pub fn spellchecker(wordlist: Vec<String>, queries: Vec<String>) -> Vec<String> {
232        use std::collections::HashMap;
233
234        let words: HashMap<String, Vec<_>> =
235            wordlist.iter().fold(HashMap::new(), |mut words, w| {
236                words
237                    .entry(
238                        w.to_string()
239                            .to_lowercase()
240                            .chars()
241                            .map(|chr| match chr {
242                                'a' | 'e' | 'i' | 'o' | 'u' => '*',
243                                _ => chr,
244                            })
245                            .collect(),
246                    )
247                    .and_modify(|lst| lst.push(w))
248                    .or_insert(vec![w]);
249
250                words
251            });
252        println!("-> {words:?}");
253
254        queries
255            .iter()
256            .map(|w| {
257                let key: String = w
258                    .to_lowercase()
259                    .chars()
260                    .map(|chr| if "aeiou".contains(chr) { '*' } else { chr })
261                    .collect();
262
263                if let Some(lst) = words.get(&key) {
264                    if lst.contains(&w) {
265                        w.to_string()
266                    } else {
267                        for lw in lst.iter() {
268                            if lw.to_lowercase() == w.to_lowercase() {
269                                return lw.to_string();
270                            }
271                        }
272                        lst.first().unwrap().to_string()
273                    }
274                } else {
275                    "".to_string()
276                }
277            })
278            .collect()
279    }
280}
281
282/// 1061m Lexicographically Smallest Equivalent String
283struct Sol1061 {}
284
285impl Sol1061 {
286    pub fn smallest_equivalent_string(s1: String, s2: String, base_str: String) -> String {
287        let mut djset: Vec<_> = (0..26).collect();
288
289        let mut union = |v1, v2| {
290            let (v1, v2) = (find(v1, &mut djset), find(v2, &mut djset));
291            match v1.cmp(&v2) {
292                std::cmp::Ordering::Greater => djset[v1] = v2,
293                std::cmp::Ordering::Less => djset[v2] = v1,
294                _ => {}
295            }
296        };
297
298        fn find(v: usize, djset: &mut [usize]) -> usize {
299            if djset[v] != v {
300                djset[v] = find(djset[v], djset);
301            }
302            djset[v]
303        }
304
305        for (chr1, chr2) in s1.as_bytes().iter().zip(s2.as_bytes().iter()) {
306            union((chr1 - b'a') as usize, (chr2 - b'a') as usize);
307        }
308
309        println!("-> {djset:?}");
310
311        base_str
312            .as_bytes()
313            .iter()
314            .map(|&chr| (find((chr - b'a') as usize, &mut djset) as u8 + b'a') as char)
315            .collect()
316    }
317}
318
319/// 1078 Occurrences After Bigram
320struct Sol1078 {}
321
322impl Sol1078 {
323    pub fn find_ocurrences(text: String, first: String, second: String) -> Vec<String> {
324        println!(
325            ":? {:?}",
326            text.split(" ")
327                .collect::<Vec<_>>()
328                .windows(3)
329                .filter(|w| w[0] == first && w[1] == second)
330                .map(|w| w[2].to_string())
331                .collect::<Vec<_>>()
332        );
333
334        text.split(" ")
335            .collect::<Vec<_>>()
336            .windows(3)
337            .fold(vec![], |mut v, w| {
338                if w[0] == first && w[1] == second {
339                    v.push(w[2].to_string());
340                }
341                v
342            })
343    }
344}
345
346/// 1154 Days of the Year
347struct Sol1154;
348
349impl Sol1154 {
350    pub fn day_of_year(date: String) -> i32 {
351        let mut days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
352
353        let mut vs = vec![];
354        for w in date.split('-') {
355            vs.push(w.parse::<i32>());
356        }
357
358        println!(" -> {:?}", vs);
359
360        let mut dy = 0;
361        if let (Ok(year), Ok(month), Ok(day)) = (&vs[0], &vs[1], &vs[2]) {
362            dy += day;
363            if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) {
364                days[1] += 1;
365            }
366
367            for m in 0..month - 1 {
368                dy += days[m as usize];
369            }
370        }
371
372        dy
373    }
374}
375
376/// 1163h Last Substring in Lexicographical Order
377struct Sol1163 {}
378
379impl Sol1163 {
380    pub fn last_substring(s: String) -> String {
381        let s: Vec<_> = s.chars().collect();
382        let n = s.len();
383
384        let (mut i, mut j) = (0, 1);
385        while j < n {
386            let mut k = 0;
387            while j + k < n && s[i + k] == s[j + k] {
388                k += 1;
389            }
390
391            if j + k < n && s[i + k] < s[j + k] {
392                (i, j) = (j, (j + 1).max(i + k + 1));
393            } else {
394                j += k + 1;
395            }
396        }
397
398        s.iter().skip(i).collect()
399    }
400}
401
402/// 1513m Number of Substrings With Only 1s
403struct Sol1513 {}
404
405impl Sol1513 {
406    pub fn num_sub(s: String) -> i32 {
407        const M: usize = 1e9 as usize + 7;
408
409        s.chars()
410            .collect::<Vec<char>>()
411            .chunk_by(|c, c_next| c == c_next)
412            .filter(|chk| chk[0] == '1')
413            .inspect(|e| println!("-> {e:?}"))
414            .map(|chk| (chk.len() * (chk.len() + 1) / 2) % M)
415            .fold(0, |total, n| (total + n) % M) as _
416    }
417}
418
419/// 1876 Substrings of Size Three with Distinct Characters
420struct Sol1876 {}
421
422impl Sol1876 {
423    pub fn count_good_substrings(s: String) -> i32 {
424        s.chars()
425            .collect::<Vec<_>>()
426            .windows(3)
427            .fold(0, |count, w| {
428                if w[0] == w[1] || w[1] == w[2] || w[2] == w[0] {
429                    count
430                } else {
431                    count + 1
432                }
433            }) as _
434    }
435}
436
437/// 1957 Delete Characters to Make Fancy String
438struct Sol1957 {}
439
440impl Sol1957 {
441    pub fn make_fancy_string(s: String) -> String {
442        if s.len() < 3 {
443            return s;
444        }
445
446        println!(
447            ":? {:?}",
448            s.chars()
449                .collect::<Vec<_>>()
450                .chunk_by(|&a, &b| a == b)
451                .flat_map(|chunk| chunk.iter().take(2.min(chunk.len())).collect::<Vec<_>>())
452                .collect::<Vec<_>>()
453        );
454
455        let mut chars: Vec<_> = s.chars().collect();
456
457        let mut p = 2;
458        for x in 2..chars.len() {
459            if chars[x] != chars[p - 1] || chars[x] != chars[p - 2] {
460                chars[p] = chars[x];
461                p += 1;
462            }
463        }
464
465        chars[..p].iter().collect()
466    }
467}
468
469/// 2138 Divide a String Into Group of Size K
470struct Sol2138 {}
471
472impl Sol2138 {
473    pub fn divide_string(s: String, k: i32, fill: char) -> Vec<String> {
474        let mut divs = vec![];
475
476        let k = k as usize;
477        for start in (0..=s.len() - k).step_by(k) {
478            divs.push(s[start..start + k].to_string());
479        }
480
481        if !s.len().is_multiple_of(k) {
482            let mut last = s[s.len() / k * k..].to_string();
483            for _ in 0..k - s.len() % k {
484                last.push(fill);
485            }
486            divs.push(last);
487        }
488
489        divs
490    }
491}
492
493/// 2269 Find the K-Beauty of a Number
494struct Sol2269 {}
495
496impl Sol2269 {
497    pub fn divisor_substrings(num: i32, k: i32) -> i32 {
498        let k = k as usize;
499
500        let mut count = 0;
501        let s = num.to_string();
502        for start in 0..=s.len() - k {
503            let n = s[start..start + k].parse::<i32>().unwrap();
504            if n != 0 && num % n == 0 {
505                count += 1;
506            }
507        }
508
509        count as _
510    }
511}
512
513/// 2273 Find Resultant Array After Removing Anagrams
514struct Sol2273 {}
515
516impl Sol2273 {
517    pub fn remove_anagrams(words: Vec<String>) -> Vec<String> {
518        let mut fs_prv = [0; 26];
519        println!("-> {:p} {fs_prv:?}", &fs_prv);
520
521        words.into_iter().fold(vec![], |mut ls, word| {
522            let mut fs = [0; 26];
523            word.chars()
524                .for_each(|chr| fs[chr.to_digit(36).unwrap() as usize - 10] += 1);
525
526            println!("-> {:p} {fs:?}", &fs);
527
528            if fs_prv != fs {
529                ls.push(word);
530            }
531            fs_prv = fs;
532            println!("-> {:p}", &fs_prv);
533
534            ls
535        })
536    }
537}
538
539/// 2315 Count Asterisks
540struct Sol2315 {}
541
542impl Sol2315 {
543    pub fn count_asterisks(s: String) -> i32 {
544        println!(
545            ":? {}",
546            s.split('|').step_by(2).fold(0, |count, pair| {
547                count + pair.chars().filter(|&chr| chr == '*').count()
548            })
549        );
550
551        s.split('|')
552            .enumerate()
553            .filter(|(i, _)| i & 1 == 0)
554            .map(|(_, pair)| pair)
555            .fold(0, |count, pair| {
556                count + pair.chars().filter(|&chr| chr == '*').count()
557            }) as _
558    }
559}
560
561/// 2785m Sort Vowels in a String
562struct Sol2785 {}
563
564impl Sol2785 {
565    pub fn sort_vowels(s: String) -> String {
566        let mut vws: Vec<_> = s
567            .chars()
568            .filter(|&chr| "aAeEiIoOuU".contains(chr))
569            .collect();
570        vws.sort();
571        println!("-> {vws:?}");
572
573        let s: Vec<_> = s
574            .chars()
575            .map(|chr| if "aAeEiIoOuU".contains(chr) { '*' } else { chr })
576            .collect();
577        println!("-> {s:?}");
578
579        s.iter()
580            .scan(0, |i, &chr| {
581                if chr == '*' {
582                    *i += 1;
583                    Some(vws[*i - 1])
584                } else {
585                    Some(chr)
586                }
587            })
588            .collect()
589    }
590}
591
592/// 3330 Find the Original Typed String I
593struct Sol3330;
594
595impl Sol3330 {
596    pub fn possible_string_count(word: String) -> i32 {
597        word.as_bytes()
598            .windows(2)
599            .fold(1, |count, w| if w[0] == w[1] { count + 1 } else { count })
600    }
601}
602
603/// 3403h Find the Lexicographically Largest String From the Box I
604struct Sol3403 {}
605
606impl Sol3403 {
607    pub fn answer_string(word: String, num_friends: i32) -> String {
608        if num_friends == 1 {
609            return word;
610        }
611
612        let n = word.len();
613        let mut answer = String::new();
614        for i in 0..n {
615            let s = &word[i..n.min(i + n - (num_friends as usize - 1))];
616            if &answer[..] < s {
617                answer = s.to_string();
618            }
619        }
620
621        answer
622    }
623}
624
625/// 3442 Maximum Difference Between Even and Odd Frequency I
626struct Sol3442 {}
627
628impl Sol3442 {
629    pub fn max_difference(s: String) -> i32 {
630        use std::collections::HashMap;
631
632        let mut freqs = HashMap::new();
633        for chr in s.chars() {
634            freqs.entry(chr).and_modify(|f| *f += 1).or_insert(1);
635        }
636
637        println!("-> {freqs:?}");
638
639        if let (Some(omax), Some(emin)) = (
640            freqs.values().filter(|&f| f & 1 == 1).max(),
641            freqs.values().filter(|&f| f & 1 == 0).min(),
642        ) {
643            return omax - emin;
644        }
645
646        0
647    }
648}
649
650#[cfg(test)]
651mod tests;