Skip to content

Commit 00dbb52

Browse files
authored
Merge branch 'master' into ref/string/anagram
2 parents cff0c5d + 5afbec4 commit 00dbb52

File tree

2 files changed

+117
-52
lines changed

2 files changed

+117
-52
lines changed
Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,71 @@
1-
// Given two strings str1 and str2, return true if str1 is a subsequence of str2, or false otherwise.
2-
// A subsequence of a string is a new string that is formed from the original string
3-
// by deleting some (can be none) of the characters without disturbing the relative
4-
// positions of the remaining characters.
5-
// (i.e., "ace" is a subsequence of "abcde" while "aec" is not).
6-
pub fn is_subsequence(str1: &str, str2: &str) -> bool {
7-
let mut it1 = 0;
8-
let mut it2 = 0;
1+
//! A module for checking if one string is a subsequence of another string.
2+
//!
3+
//! A subsequence is formed by deleting some (can be none) of the characters
4+
//! from the original string without disturbing the relative positions of the
5+
//! remaining characters. This module provides a function to determine if
6+
//! a given string is a subsequence of another string.
97
10-
let byte1 = str1.as_bytes();
11-
let byte2 = str2.as_bytes();
8+
/// Checks if `sub` is a subsequence of `main`.
9+
///
10+
/// # Arguments
11+
///
12+
/// * `sub` - A string slice that may be a subsequence.
13+
/// * `main` - A string slice that is checked against.
14+
///
15+
/// # Returns
16+
///
17+
/// Returns `true` if `sub` is a subsequence of `main`, otherwise returns `false`.
18+
pub fn is_subsequence(sub: &str, main: &str) -> bool {
19+
let mut sub_iter = sub.chars().peekable();
20+
let mut main_iter = main.chars();
1221

13-
while it1 < str1.len() && it2 < str2.len() {
14-
if byte1[it1] == byte2[it2] {
15-
it1 += 1;
22+
while let Some(&sub_char) = sub_iter.peek() {
23+
match main_iter.next() {
24+
Some(main_char) if main_char == sub_char => {
25+
sub_iter.next();
26+
}
27+
None => return false,
28+
_ => {}
1629
}
17-
18-
it2 += 1;
1930
}
2031

21-
it1 == str1.len()
32+
true
2233
}
2334

2435
#[cfg(test)]
2536
mod tests {
2637
use super::*;
2738

28-
#[test]
29-
fn test() {
30-
assert!(is_subsequence("abc", "ahbgdc"));
31-
assert!(!is_subsequence("axc", "ahbgdc"));
39+
macro_rules! subsequence_tests {
40+
($($name:ident: $test_case:expr,)*) => {
41+
$(
42+
#[test]
43+
fn $name() {
44+
let (sub, main, expected) = $test_case;
45+
assert_eq!(is_subsequence(sub, main), expected);
46+
}
47+
)*
48+
};
49+
}
50+
51+
subsequence_tests! {
52+
test_empty_subsequence: ("", "ahbgdc", true),
53+
test_empty_strings: ("", "", true),
54+
test_non_empty_sub_empty_main: ("abc", "", false),
55+
test_subsequence_found: ("abc", "ahbgdc", true),
56+
test_subsequence_not_found: ("axc", "ahbgdc", false),
57+
test_longer_sub: ("abcd", "abc", false),
58+
test_single_character_match: ("a", "ahbgdc", true),
59+
test_single_character_not_match: ("x", "ahbgdc", false),
60+
test_subsequence_at_start: ("abc", "abchello", true),
61+
test_subsequence_at_end: ("cde", "abcde", true),
62+
test_same_characters: ("aaa", "aaaaa", true),
63+
test_interspersed_subsequence: ("ace", "abcde", true),
64+
test_different_chars_in_subsequence: ("aceg", "abcdef", false),
65+
test_single_character_in_main_not_match: ("a", "b", false),
66+
test_single_character_in_main_match: ("b", "b", true),
67+
test_subsequence_with_special_chars: ("a1!c", "a1!bcd", true),
68+
test_case_sensitive: ("aBc", "abc", false),
69+
test_subsequence_with_whitespace: ("hello world", "h e l l o w o r l d", true),
3270
}
3371
}

src/searching/linear_search.rs

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
use std::cmp::PartialEq;
2-
3-
pub fn linear_search<T: PartialEq>(item: &T, arr: &[T]) -> Option<usize> {
1+
/// Performs a linear search on the given array, returning the index of the first occurrence of the item.
2+
///
3+
/// # Arguments
4+
///
5+
/// * `item` - A reference to the item to search for in the array.
6+
/// * `arr` - A slice of items to search within.
7+
///
8+
/// # Returns
9+
///
10+
/// * `Some(usize)` - The index of the first occurrence of the item, if found.
11+
/// * `None` - If the item is not found in the array.
12+
pub fn linear_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {
413
for (i, data) in arr.iter().enumerate() {
514
if item == data {
615
return Some(i);
@@ -14,36 +23,54 @@ pub fn linear_search<T: PartialEq>(item: &T, arr: &[T]) -> Option<usize> {
1423
mod tests {
1524
use super::*;
1625

17-
#[test]
18-
fn search_strings() {
19-
let index = linear_search(&"a", &["a", "b", "c", "d", "google", "zoo"]);
20-
assert_eq!(index, Some(0));
21-
}
22-
23-
#[test]
24-
fn search_ints() {
25-
let index = linear_search(&4, &[1, 2, 3, 4]);
26-
assert_eq!(index, Some(3));
27-
28-
let index = linear_search(&3, &[1, 2, 3, 4]);
29-
assert_eq!(index, Some(2));
30-
31-
let index = linear_search(&2, &[1, 2, 3, 4]);
32-
assert_eq!(index, Some(1));
33-
34-
let index = linear_search(&1, &[1, 2, 3, 4]);
35-
assert_eq!(index, Some(0));
36-
}
37-
38-
#[test]
39-
fn not_found() {
40-
let index = linear_search(&5, &[1, 2, 3, 4]);
41-
assert_eq!(index, None);
26+
macro_rules! test_cases {
27+
($($name:ident: $tc:expr,)*) => {
28+
$(
29+
#[test]
30+
fn $name() {
31+
let (item, arr, expected) = $tc;
32+
if let Some(expected_index) = expected {
33+
assert_eq!(arr[expected_index], item);
34+
}
35+
assert_eq!(linear_search(&item, arr), expected);
36+
}
37+
)*
38+
}
4239
}
4340

44-
#[test]
45-
fn empty() {
46-
let index = linear_search(&1, &[]);
47-
assert_eq!(index, None);
41+
test_cases! {
42+
empty: ("a", &[] as &[&str], None),
43+
one_item_found: ("a", &["a"], Some(0)),
44+
one_item_not_found: ("b", &["a"], None),
45+
search_strings_asc_start: ("a", &["a", "b", "c", "d", "google", "zoo"], Some(0)),
46+
search_strings_asc_middle: ("google", &["a", "b", "c", "d", "google", "zoo"], Some(4)),
47+
search_strings_asc_last: ("zoo", &["a", "b", "c", "d", "google", "zoo"], Some(5)),
48+
search_strings_asc_not_found: ("x", &["a", "b", "c", "d", "google", "zoo"], None),
49+
search_strings_desc_start: ("zoo", &["zoo", "google", "d", "c", "b", "a"], Some(0)),
50+
search_strings_desc_middle: ("google", &["zoo", "google", "d", "c", "b", "a"], Some(1)),
51+
search_strings_desc_last: ("a", &["zoo", "google", "d", "c", "b", "a"], Some(5)),
52+
search_strings_desc_not_found: ("x", &["zoo", "google", "d", "c", "b", "a"], None),
53+
search_ints_asc_start: (1, &[1, 2, 3, 4], Some(0)),
54+
search_ints_asc_middle: (3, &[1, 2, 3, 4], Some(2)),
55+
search_ints_asc_end: (4, &[1, 2, 3, 4], Some(3)),
56+
search_ints_asc_not_found: (5, &[1, 2, 3, 4], None),
57+
search_ints_desc_start: (4, &[4, 3, 2, 1], Some(0)),
58+
search_ints_desc_middle: (3, &[4, 3, 2, 1], Some(1)),
59+
search_ints_desc_end: (1, &[4, 3, 2, 1], Some(3)),
60+
search_ints_desc_not_found: (5, &[4, 3, 2, 1], None),
61+
with_gaps_0: (0, &[1, 3, 8, 11], None),
62+
with_gaps_1: (1, &[1, 3, 8, 11], Some(0)),
63+
with_gaps_2: (2, &[1, 3, 8, 11], None),
64+
with_gaps_3: (3, &[1, 3, 8, 11], Some(1)),
65+
with_gaps_4: (4, &[1, 3, 8, 10], None),
66+
with_gaps_5: (5, &[1, 3, 8, 10], None),
67+
with_gaps_6: (6, &[1, 3, 8, 10], None),
68+
with_gaps_7: (7, &[1, 3, 8, 11], None),
69+
with_gaps_8: (8, &[1, 3, 8, 11], Some(2)),
70+
with_gaps_9: (9, &[1, 3, 8, 11], None),
71+
with_gaps_10: (10, &[1, 3, 8, 11], None),
72+
with_gaps_11: (11, &[1, 3, 8, 11], Some(3)),
73+
with_gaps_12: (12, &[1, 3, 8, 11], None),
74+
with_gaps_13: (13, &[1, 3, 8, 11], None),
4875
}
4976
}

0 commit comments

Comments
 (0)