leetcode

Log | Files | Refs | README

commit 2d8ac40efa60e54ea126eed84808a29faf9eaa1e
parent ac0e24ff74150cfb7543d1d0b6910f6464783679
Author: ling0x <ling0x@users.noreply.github.com>
Date:   Sat, 25 Jul 2026 04:21:59 +0100

update

Diffstat:
Msrc/array/longest_common_prefix.rs | 95++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/hash_table/two_sum.rs | 236+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/main.rs | 10+---------
3 files changed, 196 insertions(+), 145 deletions(-)

diff --git a/src/array/longest_common_prefix.rs b/src/array/longest_common_prefix.rs @@ -1,31 +1,75 @@ +//! Write a function to find the longest common prefix string amongst +//! an array of strings. +//! +//! If there is no common prefix, return an empty string "". + +use std::collections::{HashMap, HashSet}; + use tracing::info; -pub fn longest_common_prefix_1(strs: Vec<String>) -> String { - let mut seen = std::collections::HashSet::<char>::new(); - let mut seen_seen = std::collections::HashSet::<char>::new(); - let mut common = Vec::<char>::new(); - let mut common_common = Vec::<char>::new(); - - for word in strs { - let chars = word.chars().collect::<Vec<char>>(); - for c in chars.iter() { - let result = seen.insert(c.to_owned()); - if !result { - common.push(c.to_owned()); +// First manual attempt - the ugliest solution that worked +fn solution_1(words: Vec<String>) -> String { + let mut prefixes = HashMap::<usize, char>::new(); + let mut matches = Vec::<(usize, char)>::new(); + + let mut final_results = Vec::<(usize, char)>::new(); + + for word in words.iter() { + info!("{word}"); + for (idx, char) in word.chars().enumerate() { + info!("{idx}: {char}"); + prefixes.insert(idx, char); + } + } + + for word in words.iter() { + for (index, prefix) in prefixes.clone() { + let mut current = word.char_indices(); + let result = current.find(|(idx, char)| idx.eq(&index) && char.eq(&prefix)); + if let Some(found) = result { + info!("Match found: {index}: {prefix}: {found:?}"); + matches.push((index, prefix)); + } else { + info!("No match found"); } } } - for cc in &common { - let result = seen_seen.insert(cc.to_owned()); - if !result { - common_common.push(cc.to_owned()); + for char in matches.iter() { + let count = matches.iter().filter(|x| x.eq(&char)).count(); + + if count.eq(&words.len()) && !final_results.contains(char) { + final_results.push(*char); } } - info!("{common_common:?}"); + final_results.sort_by_key(|x| x.0); + + info!("Final results: {final_results:?}"); + + let mut prev: usize = 0; + final_results.retain(|(index, _)| { + if index.eq(&0) { + return true; + } + if index.eq(&(prev + 1)) { + prev = *index; + true + } else { + false + } + }); + + info!("Retained results: {final_results:?}"); + + let has_zero = final_results.iter().any(|(idx, _)| idx.eq(&0)); + if !has_zero { + return String::new(); + } - String::from_iter(common_common) + let result = String::from_iter(final_results.iter().map(|x| x.1)); + info!("Result: {result}\n\n"); + result } #[cfg(test)] @@ -33,8 +77,7 @@ mod tests { use tracing::info; use crate::{ - array::longest_common_prefix::longest_common_prefix_1, - test_utils::benchmark::init_benchmark_tracing, + array::longest_common_prefix::solution_1, test_utils::benchmark::init_benchmark_tracing, }; struct Case { @@ -56,6 +99,14 @@ mod tests { input: vec!["dog".to_string(), "racecar".to_string(), "car".to_string()], output: String::new(), }, + Case { + input: vec!["cir".to_string(), "car".to_string()], + output: "c".to_string(), + }, + Case { + input: vec!["babb".to_string(), "caa".to_string()], + output: String::new(), + }, ] } @@ -68,7 +119,7 @@ mod tests { } #[test] - fn longest_common_prefix_1_cases() { - run_solver_cases("solver 1", longest_common_prefix_1, full_cases()); + fn longest_2_cases() { + run_solver_cases("solver 1", solution_1, full_cases()); } } diff --git a/src/hash_table/two_sum.rs b/src/hash_table/two_sum.rs @@ -1,3 +1,11 @@ +//! Given an array of integers nums and an integer target, return indices +//! of the two numbers such that they add up to target. +//! +//! You may assume that each input would have exactly one solution, and +//! you may not use the same element twice. +//! +//! You can return the answer in any order. + // First try - brute force approach without optimization // 101ms, 2.37MB pub fn two_sum_1(nums: Vec<i32>, target: i32) -> Vec<i32> { @@ -185,117 +193,117 @@ pub fn two_sum_9(nums: Vec<i32>, target: i32) -> Vec<i32> { Vec::new() } -#[cfg(test)] -mod tests { - use crate::hash_table::two_sum::{ - two_sum_1, two_sum_2, two_sum_3, two_sum_4, two_sum_5, two_sum_6, two_sum_7, two_sum_8, - two_sum_9, - }; - use crate::test_utils::benchmark::{init_benchmark_tracing, run_and_assert_vec_any_order}; - - #[derive(Clone)] - struct TwoSumCase { - name: &'static str, - nums: Vec<i32>, - target: i32, - expected: Vec<i32>, - } - - fn full_cases() -> Vec<TwoSumCase> { - vec![ - TwoSumCase { - name: "case_1", - nums: vec![2, 7, 11, 15], - target: 9, - expected: vec![0, 1], - }, - TwoSumCase { - name: "case_2", - nums: vec![3, 2, 3], - target: 6, - expected: vec![0, 2], - }, - TwoSumCase { - name: "case_3", - nums: vec![3, 2, 4], - target: 6, - expected: vec![1, 2], - }, - TwoSumCase { - name: "case_4", - nums: vec![-3, 4, 3, 90], - target: 0, - expected: vec![0, 2], - }, - ] - } - - fn run_solver_cases( - solver_name: &str, - solver: fn(Vec<i32>, i32) -> Vec<i32>, - cases: Vec<TwoSumCase>, - ) { - init_benchmark_tracing(); - for case in cases { - run_and_assert_vec_any_order( - &format!("{solver_name}_{}", case.name), - case.expected, - || solver(case.nums, case.target), - ); - } - } - - #[test] - #[ignore] - fn two_sum_1_cases() { - run_solver_cases("two_sum_1", two_sum_1, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_2_cases() { - run_solver_cases("two_sum_2", two_sum_2, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_3_cases() { - run_solver_cases("two_sum_3", two_sum_3, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_4_cases() { - run_solver_cases("two_sum_4", two_sum_4, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_5_cases() { - run_solver_cases("two_sum_5", two_sum_5, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_6_cases() { - run_solver_cases("two_sum_6", two_sum_6, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_7_cases() { - run_solver_cases("two_sum_7", two_sum_7, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_8_cases() { - run_solver_cases("two_sum_8", two_sum_8, full_cases()); - } - - #[test] - #[ignore] - fn two_sum_9_cases() { - run_solver_cases("two_sum_9", two_sum_9, full_cases()); - } -} +// #[cfg(test)] +// mod tests { +// use crate::hash_table::two_sum::{ +// two_sum_1, two_sum_2, two_sum_3, two_sum_4, two_sum_5, two_sum_6, two_sum_7, two_sum_8, +// two_sum_9, +// }; +// use crate::test_utils::benchmark::{init_benchmark_tracing, run_and_assert_vec_any_order}; + +// #[derive(Clone)] +// struct TwoSumCase { +// name: &'static str, +// nums: Vec<i32>, +// target: i32, +// expected: Vec<i32>, +// } + +// fn full_cases() -> Vec<TwoSumCase> { +// vec![ +// TwoSumCase { +// name: "case_1", +// nums: vec![2, 7, 11, 15], +// target: 9, +// expected: vec![0, 1], +// }, +// TwoSumCase { +// name: "case_2", +// nums: vec![3, 2, 3], +// target: 6, +// expected: vec![0, 2], +// }, +// TwoSumCase { +// name: "case_3", +// nums: vec![3, 2, 4], +// target: 6, +// expected: vec![1, 2], +// }, +// TwoSumCase { +// name: "case_4", +// nums: vec![-3, 4, 3, 90], +// target: 0, +// expected: vec![0, 2], +// }, +// ] +// } + +// fn run_solver_cases( +// solver_name: &str, +// solver: fn(Vec<i32>, i32) -> Vec<i32>, +// cases: Vec<TwoSumCase>, +// ) { +// init_benchmark_tracing(); +// for case in cases { +// run_and_assert_vec_any_order( +// &format!("{solver_name}_{}", case.name), +// case.expected, +// || solver(case.nums, case.target), +// ); +// } +// } + +// #[test] +// #[ignore] +// fn two_sum_1_cases() { +// run_solver_cases("two_sum_1", two_sum_1, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_2_cases() { +// run_solver_cases("two_sum_2", two_sum_2, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_3_cases() { +// run_solver_cases("two_sum_3", two_sum_3, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_4_cases() { +// run_solver_cases("two_sum_4", two_sum_4, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_5_cases() { +// run_solver_cases("two_sum_5", two_sum_5, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_6_cases() { +// run_solver_cases("two_sum_6", two_sum_6, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_7_cases() { +// run_solver_cases("two_sum_7", two_sum_7, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_8_cases() { +// run_solver_cases("two_sum_8", two_sum_8, full_cases()); +// } + +// #[test] +// #[ignore] +// fn two_sum_9_cases() { +// run_solver_cases("two_sum_9", two_sum_9, full_cases()); +// } +// } diff --git a/src/main.rs b/src/main.rs @@ -1,15 +1,7 @@ -use leetcode::{ - array::longest_common_prefix::longest_common_prefix_1, hash_table::two_sum::two_sum_9, -}; use tracing::info; use tracing_subscriber::fmt; fn main() { fmt().with_target(false).compact().init(); - info!("-----------------------"); - longest_common_prefix_1(vec![ - "flower".to_string(), - "flow".to_string(), - "flight".to_string(), - ]); + info!("Run `cargo test` to test cases"); }