Add closest string

This commit is contained in:
hal8174 2024-11-21 22:48:34 +01:00
parent 5a3525a9ce
commit c3cfbcbada
14 changed files with 5399 additions and 0 deletions

122
closest_string/src/main.rs Normal file
View file

@ -0,0 +1,122 @@
use std::path::{Path, PathBuf};
use clap::{Parser, ValueEnum};
fn read_input(filename: impl AsRef<Path>) -> Vec<Vec<u8>> {
let text = std::fs::read_to_string(filename).unwrap();
let mut r = Vec::new();
for line in text.lines().skip(1) {
r.push(line.as_bytes().to_vec());
}
r
}
fn calculate_hamming_distance(a: &[u8], b: &[u8]) -> usize {
a.iter().zip(b.iter()).filter(|(a, b)| a != b).count()
}
fn simple<'a>(
strings: &[Vec<u8>],
solution: &'a mut [u8],
d: usize,
depth: usize,
) -> Option<&'a [u8]> {
let (s, i) = strings
.iter()
.map(|s| (s, calculate_hamming_distance(s, solution)))
.max_by_key(|(_, i)| *i)
.unwrap();
if i > d + depth {
return None;
} else if i <= d {
return Some(solution);
}
for index in 0..s.len() {
if s[index] != solution[index] {
let temp = solution[index];
solution[index] = s[index];
simple(strings, solution, d, depth + 1)?;
solution[index] = temp;
}
}
None
}
fn closest_string(strings: &[Vec<u8>], d: usize, method: Method) -> Option<Vec<u8>> {
match method {
Method::Simple => {
let mut s = strings[0].clone();
if simple(strings, &mut s, d, 0).is_some() {
Some(s)
} else {
None
}
}
}
}
#[derive(ValueEnum, Debug, Clone, Copy)]
enum Method {
Simple,
}
#[derive(Debug, Parser)]
struct Args {
filename: PathBuf,
d: Option<usize>,
#[clap(default_value = "simple")]
method: Method,
#[clap(short, long)]
reverse: bool,
}
fn main() {
let total_start = std::time::Instant::now();
let args = Args::parse();
let strings = read_input(args.filename);
let result = if let Some(d) = args.d {
let start = std::time::Instant::now();
let r = closest_string(&strings, d, args.method);
eprintln!("{}: {:?}", d, start.elapsed());
r
} else if args.reverse {
let mut d = strings.len();
let mut last_solution = None;
loop {
let start = std::time::Instant::now();
let r = closest_string(&strings, d, args.method);
eprintln!("{}: {:?}", d, start.elapsed());
if let Some(r) = r {
d = r.len() - 1;
last_solution = Some(r);
} else {
break last_solution;
};
}
} else {
let mut d = 0;
loop {
let start = std::time::Instant::now();
let r = closest_string(&strings, d, args.method);
eprintln!("{}: {:?}", d, start.elapsed());
if let Some(r) = r {
break Some(r);
}
d += 1;
}
};
if let Some(solution) = result {
println!("{}", String::from_utf8(solution).unwrap());
}
eprintln!("Total time: {:?}", total_start.elapsed());
}