시리즈: 알고리즘 (32개 글)
- 자바로 알고리즘 풀기
- [Java] 백준 10431 - 줄 세우기
- [Java & Node.js] 백준 9935 - 문자열 폭발
- [Node.js] 백준 22866 - 탑 보기
- [Java] 백준 4485 - 녹색 옷 입은 애가 젤다지?
- [Node.js] 백준 1283 - 단축키 지정
- [Java & Node.js] 백준 14469 - 소가 길을 건너간 이유 3
- [Java] 백준 8979 - 올림픽
- [Node.js] 백준 22866 - 탑 보기
- [Java] 백준 7568 - 덩치
- [Java] 백준 1244 - 스위치 켜고 끄기
- [Node.js] 백준 19941 - 햄버거 분배
- [Node.js] 백준 1254 - 팰린드롬 만들기
- [Java] 백준 2589 - 보물섬
- [Java] 백준 2309 - 일곱 난쟁이
- [Java] 백준 1789 - 수들의 합
- [Java] 백준 1987 - 알파벳
- [Node.js] [Rust] 백준 24460 - 특별상이라도 받고 싶어
- [Node.js] 백준 7576 - 탑 보기
- [Rust] 백준 1047 - 울타리 (N^4 브루트포스 + 그리디)
- [Node.js] 백준 9657 - 돌게임3
- [Rust] 백준 4963 - 섬의 개수
- [Node.js] 프로그래머스 - 모의고사 / 실패율
- [Rust] 백준 2667 - 단지번호붙이기
- [Node.js] 프로그래머스 - 방문 길이
- [Node.js] 프로그래머스 - 괄호 회전하기
- [Rust] 백준 1002 - 터렛
- [Node.js] 프로그래머스 - 크레인 인형뽑기 게임
- [Node.js] 프로그래머스 - 기능개발
- [Rust] 백준 13717 - 포켓몬 GO
- [JavaScript] 백준 1092 - 배
- [Rust] 백준 25329 - 학생별 통화 요금 계산
해시맵을 이용한 데이터 집계
문제 설명
- 학생들의 통화 기록이 N개 주어진다.
- 같은 학생의 통화 시간은 누적된다.
- 누적된 시간을 기준으로 요금을 계산한다.
- 기본 100분까지 10원
- 초과 시 50분당 3원 (올림)
- 요금이 많은 순서로, 요금이 같다면 이름 사전(오름차)순 출력
접근
데이터를 집계해야 하므로 HashMap을 사용해보았다.
Rust에서는 entry 를 사용하면 키가 없을 때 초기화하고 값을 더하는 로직을 편하게 적용할 수 있음.
시간은 HH:MM 형태로 주어지니 미리 분으로 바꿔버리는게 편함.
정렬 조건이 두 가지라는 부분이 머리를 복잡하게 만들지만
Rust 의 경우 cmp와 Ordering 사용해서 해보았다.
JavaScript는 조건문으로..
정답
Rust
use std::{
cmp::Ordering,
collections::HashMap,
io::{self, Read},
};
const BASE_MINS: i32 = 100;
const BASE_PRICE: i32 = 10;
const UNIT_MINS: f64 = 50.0;
const UNIT_PRICE: i32 = 3;
#[derive(Debug, Clone)]
struct StudentBill {
name: String,
price: i32,
}
fn main() -> io::Result<()> {
let mut input = String::new();
io::stdin().read_to_string(&mut input)?;
let mut lines = input.trim().lines();
let n: usize = lines.next().and_then(|l| l.parse().ok()).unwrap_or(0);
let mut students: HashMap<String, i32> = HashMap::new();
for _ in 0..n {
if let Some(line) = lines.next() {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() != 2 {
continue;
}
let time = parts[0];
let name = parts[1];
let time_parts: Vec<&str> = time.split(":").collect();
if time_parts.len() != 2 {
continue;
}
let hour = time_parts[0].parse::<i32>().unwrap_or(0);
let mins = time_parts[1].parse::<i32>().unwrap_or(0);
let total_mins = hour * 60 + mins;
*students.entry(name.to_string()).or_insert(0) += total_mins;
}
}
let mut bills: Vec<StudentBill> = Vec::new();
for (name, total_mins) in students {
let mut final_price = BASE_PRICE;
let excess_mins = total_mins - BASE_MINS;
if excess_mins > 0 {
let excess_mins_f64 = excess_mins as f64;
let unit_count = (excess_mins_f64 / UNIT_MINS).ceil() as i32;
let excess_price = unit_count * UNIT_PRICE;
final_price += excess_price
}
bills.push(StudentBill {
name,
price: final_price,
});
}
bills.sort_by(|a, b| {
let price_cmp = b.price.cmp(&a.price);
if price_cmp != Ordering::Equal {
return price_cmp;
}
a.name.cmp(&b.name)
});
for bill in bills {
println!("{} {}", bill.name, bill.price);
}
Ok(())
}
Node(JavaScript)
const fs = require("fs");
const input = fs.readFileSync(0).toString().trim().split("\n");
const N = input[0];
const students = {};
for (let i = 1; i <= N; i++) {
const [time, name] = input[i].trim().split(" ");
const [hour, mins] = time.split(":");
const tmp_total_mins = parseInt(hour) * 60 + parseInt(mins);
students[name] = (students[name] || 0) + tmp_total_mins;
}
// 기본 제공 시간 : 100 분
// 기본 요금 : 10
// 기본 단위 시간 : 50
// 단위 요금 : 3
// [name, mins]
let bill = [];
for (const student of Object.entries(students)) {
// 기본 제공 시간 100분 : 10원
let tmp = student[1] - 100;
if (tmp <= 0) {
bill.push([student[0], 10]);
} else {
bill.push([student[0], 10 + Math.ceil(tmp / 50) * 3]);
}
}
bill.sort((a, b) => {
if (a[1] !== b[1]) {
return b[1] - a[1];
}
return a[0].localeCompare(b[0]);
});
for (const [name, price] of bill) {
console.log(`${name} ${price}`);
}
후기
코드 길이 차이 무엇
문자열 파싱부터, 해시맵 + 정렬까지 아주 다양한 부분을 연습하기 좋은 기본기 문제 아닐까.
흐어어억
하지만
화이팅화이팅
-뱅-
