코드 출현 2020: 1일 차
22917 단어 rustadventofcode
1일 차: 보고서 수리
문제 1에 대한 연습
이 문제의 경우 한 줄에 하나씩 숫자 목록이 주어지고 합계가 2020인 두 항목을 찾도록 요청받습니다. 두 숫자가 있으면 곱하여 답을 얻습니다.
순진한 접근
고전적인 합계 2 문제를 해결하기 위한 순진한 접근 방식은 중첩 검색을 사용하여 원하는 양(2020)에 추가되는 모든 숫자 조합을 테스트하는 것입니다.
let mut v: Vec<i32> = Vec::new();
// load data
let input = File::open("./input.txt").unwrap();
let reader = BufReader::new(input);
for line in reader.lines() {
let integer = line.unwrap().parse::<i32>().unwrap();
v.push(integer);
}
// for every number in the vector, check if any other value in the vector sums
// with that number to equal 2020. If a pair of numbers is found, print them
// and the answer.
for num1 in &v {
for num2 in &v {
if num1 + num2 == 2020 {
println!{"Values: {} and {}", num1, num2};
println!{"Answer: {}", num1 * num2};
break
}
}
}
이 접근 방식은 시간이 매우 비효율적입니다. 입력의 모든 추가 고유 숫자에 대해 이 솔루션은 벡터의 모든 항목에 대해 추가 계산 단계를 추가합니다. 이 솔루션의 시간 복잡도는 O(n2)입니다.
최적의 접근
보다 효율적인 방법 중 하나는 이진 검색 알고리즘을 사용하는 것입니다.
먼저 사용할 이진 검색 알고리즘이 필요합니다.
fn binary_search(vector: &Vec<i32>, len: usize, target: &i32) -> Option<bool> {
// set the low and high indices
let mut low: i8 = 0;
let mut high: i8 = len as i8 -1;
while low <= high {
// find the mid point by floor dividing the sum of the high and low
let mid = ((high - low) / 2) + low;
let mid_index = mid as usize;
let val = vector[mid_index];
// return the index of the number if it is found, or set the high and
// low to reduce the search space
if val == *target { return Some(true); }
if val < *target { low = mid + 1; }
if val > *target { high = mid - 1; }
}
Some(false)
}
이제 이진 검색 구현이 있으므로 이를 사용하여 2020까지 합산되는 목록의 각 항목에 대한 가수를 검색할 수 있습니다.
let mut v: Vec<i32> = Vec::new();
// load data
let input = File::open("./input.txt").unwrap();
let reader = BufReader::new(input);
for line in reader.lines() {
let integer = line.unwrap().parse::<i32>().unwrap();
v.push(integer);
}
for num1 in &v {
// calculate the value we would need to sum with num1 to get to 2020.
let target = 2020 - num1;
// check if that item is in the vector
let answer = binary_search(&v, v.len(), &target);
if answer.unwrap() == true {
println!{"Values: {} and {}", num1, target};
println!{"Answer: {}", num1 * target};
}
}
이 기능은 문제에 대한 입력의 크기에 관계없이 합리적인 시간 내에 첫 번째 문제에 대한 답변을 제공합니다. 시간 복잡도는 N*log(N)입니다.
그러나 더 간단하고 똑같이 효율적인 옵션은 세트를 사용하는 것입니다.
println!("\n Puzzle 1: \n");
let mut set: HashSet<i32> = HashSet::new();
let input = File::open("./input.txt").unwrap();
let reader = BufReader::new(input);
// I decided to use a set because it eliminates duplicate values and
// reduces the iteration and accessing times to roughly 0.
for line in reader.lines() {
let integer = line.unwrap().parse::<i32>().unwrap();
set.insert(integer);
}
// iterate over all of the items in the set checking if the second value
// for the solution is in the set. If so, print and exit.
for number in &set {
let target: i32 = 2020 - number;
if set.contains(&target){
println!{"Values: {} and {}", number, target};
println!{"Answer: {}", number * target};
break;
}
}
순진한 접근 방식처럼 보이지만 세트를 사용하면 즉각적인 항목 액세스와 O(n)의 시간 복잡도가 가능합니다.
문제 2
첫째 날의 두 번째 문제는 첫 번째 문제와 매우 유사합니다. 유일한 차이점은 합이 2020인 세 개의 덧셈을 반환하는 솔루션을 찾아야 한다는 것입니다. 마지막 문제와 마찬가지로 답은 세 숫자의 곱입니다.
순진한 접근
문제 2에 대한 이 순진한 솔루션은 문제 1에 대한 순진한 솔루션과 거의 동일합니다. 유일한 차이점은 이제 솔루션의 검색 부분에 추가 루프를 추가한다는 것입니다.
let mut v: Vec<i32> = Vec::new();
// load data
let input = File::open("./input.txt").unwrap();
let reader = BufReader::new(input);
for line in reader.lines() {
let integer = line.unwrap().parse::<i32>().unwrap();
v.push(integer);
}
// for every number in the vector, check if any other value in the vector
// sums with that number to equal 2020. If a pair of numbers is found, print
// them and the answer
for num1 in &v {
for num2 in &v {
for num3 in &v {
if num1 + num2 + num3 == 2020 {
println!{"Values: {}, {}, and {}", num1, num2, num3};
println!{"Answer: {}", num1 * num2 * num3};
process::exit(0x0100);
}
}
}
}
이것은 문제 1의 순진한 솔루션보다 훨씬 더 느린 알고리즘입니다. 추가 루프로 인해 이 솔루션의 시간 복잡도는 이제 O(n3)입니다. 아야.
최적의 접근
이 문제에 대한 최적의 솔루션은 문제 1과 유사합니다. 그러나이 솔루션의 경우 목록의 모든 항목을 반복하는 루프를 추가한 다음 문제 하나의 솔루션을 실행하여 다른 두 숫자를 찾습니다. 이는 알고리즘의 시간 복잡도를 크게 증가시키지만 비교적 비슷한 수준의 코딩 복잡도를 가진 다른 솔루션이 없습니다.
let mut set: HashSet<i32> = HashSet::new();
let input = File::open("./input.txt").unwrap();
let reader = BufReader::new(input);
for line in reader.lines() {
let integer = line.unwrap().parse::<i32>().unwrap();
set.insert(integer);
}
// While this implementation uses nested for loops, it is only O(n^2)
// in the worst case and is still the best solution to this problem.
// In terms of space complexity, it could be more efficient if I didn't
// copy all of the data into a set first, but I valued speed more than
// space in this instance.
for number1 in &set {
for number2 in &set {
let target: i32 = 2020 - number1 - number2;
if set.contains(&target){
println!{"Values: {}, {}, and {}", number1, number2, target};
println!{"Answer: {}", number1 * number2 * target};
process::exit(0x0100);
}
}
}
Reference
이 문제에 관하여(코드 출현 2020: 1일 차), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/koltonmusgrove/advent-of-code-2020-day-1-3cfa텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)