일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 프로그래머스
- 리눅스마스터1급
- toCharArray
- 문자열
- Java
- Linux
- Memoir
- 월간코드챌린지
- GoingBus
- 명령어
- 스프링 컨테이너
- 자바
- 개발자 회고록
- JavaScript
- 백준 javascript
- 스프링 빈
- 리눅스마스터 1급 정리
- 고잉버스
- 카카오
- map
- 코딩테스트
- 리눅스
- 자바스크립트 코딩의 기술
- 코테
- 반복문
- 백준 java
- 연습문제
- Kotlin
- java 백준 1차원 배열
- 리눅스마스터 3과목
- Today
- Total
hoon's bLog
[Java] 프로그래머스 신고 결과 받기 자바 본문
문제 출처 : https://programmers.co.kr/learn/courses/30/lessons/92334
응?! 정확성 테스트?!
뭔가 프로그램이 모든 케이스를 충족하면서,
빨리 돌아가야 한다는 건가?!!??!
일단 가보자구~~~
[나의 풀이]
- 신고인과 피신고인 정보를 담을 map과 id별 신고 횟수 정보를 담을 idxMap 선언
- for문으로 report의 정보를 split 메서드로 쪼게 map 안에 set에 데이터 추가
- map에 담긴 set 데이터를 다시 send set에 담아, for문을 통해 idxMap의 이름을 가져와 해당 index로 배열 구성
import java.util.*;
class Solution {
public int[] solution(String[] id_list, String[] report, int k) {
int[] answer = new int[id_list.length];
Map<String, HashSet<String>> map = new HashMap<>();
Map<String, Integer> idxMap = new HashMap<>();
//id_list의 이름을 name 변수에 저장하여 map과 idxMap에 저장
for (int i = 0; i < id_list.length; i++) {
String name = id_list[i];
map.put(name, new HashSet<>());
idxMap.put(name, i);
}
//report 배열의 인덱스를 split으로 쪼개고, map의 신고당한 유저(to)에 선언된
//Set에 신고한 유저(from) 추가
for (String s : report) {
String[] str = s.split(" "); //"muzi frodo"
String from = str[0]; //str[0] = "muzi"
String to = str[1]; //str[1] = "frodo"
map.get(to).add(from);
}
//map에서 id_list 배열의 값을 키로 하여 값을 가져와
//send Set에 담아주고, 2회 이상 등록된 유저의 인덱스를
//idxMap에서 가져와 answer 배열의 값을 +!
for (int i = 0; i < id_list.length; i++) {
HashSet<String> send = map.get(id_list[i]);
if (send.size() >= k) {
for (String name : send) {
answer[idxMap.get(name)]++;
}
}
}
return answer;
}
}
for문으로 코딩을 하면 역시 직관적이지만,
3번이나 따로따로 도는 건 역시 미관상 보기도 안 좋고,
그다지 유쾌한 방법은 아니다ㅠㅠ
이번 문제는 좋은 풀이들이 많은 것 같아 좀 가져와봤다!
그럼 고수님들의 풀이를 GoGo~~
[다른 사람의 풀이-1]
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
class Solution {
public int[] solution(String[] id_list, String[] report, int k) {
//report 배열에 값을 꺼내 List타입으로 변환하여 저장
List<String> list = Arrays.stream(report).distinct().collect(Collectors.toList());
HashMap<String, Integer> count = new HashMap<>();
//list의 값을 꺼내 인덱스 1번째 값(신고당한 유저)을 target에 저장후
//count map에 target 값 put
//getOrDefault : 찾는 key가 존재한다면 찾는 key의 value를 반환, 없거나 null이면 default 값을 반환
for (String s : list) {
String target = s.split(" ")[1];
count.put(target, count.getOrDefault(target, 0) + 1);
}
//id_list 배열의 원소들로 stream을 생성 후 요소들을
//_user에 담아 user에 저장하여
//그 값을 공백이 뒤에 붙은 user 값을 list stream으로 생성후 reportList에 저장한 값을
//stream으로 생성 후 count map에 k이상인 user를 count한 값 return 후
//mapToInt로 int로 변환한 요소들을 배열로 retrun
return Arrays.stream(id_list).map(_user -> {
final String user = _user;
List<String> reportList = list.stream().filter(s -> s.startsWith(user + " ")).collect(Collectors.toList());
return reportList.stream().filter(s -> count.getOrDefault(s.split(" ")[1], 0) >= k).count();
}).mapToInt(Long::intValue).toArray();
}
}
stream이 확실히 가독성도 좋아 보이고,
멋있어 보이는 건 사실이지만,
굳이 이렇게까지?
라는 생각이 드는 코드였ㄷ...?(절대 Stream을 잘 못써서가 아님ㅠㅠ)
굳이 이렇게까지?
[다른 사람의 풀이-2]
import java.util.*;
class Solution {
public int[] solution(String[] id_list, String[] report, int k) {
int[] answer = new int[id_list.length];
ArrayList<User> users = new ArrayList<>();
HashMap<String,Integer> suspendedList = new HashMap<>();
HashMap<String,Integer> idIdx = new HashMap<String,Integer>();
int idx = 0;
//각 유저에 대한 고유 index를 setting후 users ArrayList에 User 객체 추가
for(String name : id_list) {
idIdx.put(name, idx++);
users.add(new User(name));
}
//users의 idIdx.get(str[0])번째 index에 reportList에 피신고인 추가
//users의 idIdx.get(str[1])번째 index에 reportedList에 신고인 추가
for(String re : report){
String[] str = re.split(" ");
users.get(idIdx.get(str[0])).reportList.add(str[1]);
users.get(idIdx.get(str[1])).reportedList.add(str[0]);
}
//reportedList의 크기가 주어진 k와 같거나 크면 suspendedList의 피신고인 put
for(User user : users){
if(user.reportedList.size() >= k)
suspendedList.put(user.name,1);
}
//answer 배열 각 index에 해당하는 유저의 신고당한 횟수를 count up
for(User user : users){
for(String nameReport : user.reportList){
if(suspendedList.get(nameReport) != null){
answer[idIdx.get(user.name)]++;
}
}
}
return answer;
}
}
class User{
String name; //해당 유저명
HashSet<String> reportList; //피신고인 리스트
HashSet<String> reportedList; //신고인 리스트
public User(String name){
this.name = name;
reportList = new HashSet<>();
reportedList = new HashSet<>();
}
}
진짜 박수가 절로 나오는 풀이...
언뜻 보면 길어 보일 수 있겠지만,
User라는 클래스 객체를 별도로 선언함으로써,
내부 필드의 데이터들을 한 번에 다루는,
전형적인 객체지향적 풀이라고 볼 수 있다...
속도 측면에서도, 설계 측면에서도 매우 훌륭한 코드로
앞으로 우리가 실무에서 지향해야 할 풀이라고 해도 과언이 아니다...
[정리]
- 핵심은 반복문을 통해 List, Map, Set 등을 활용하여 데이터 정리
- 각 유저별 고유의 index를 부여하는 풀이는 자주 나오니 꼭 기억할 것!
- 클래스 객체를 통해 반복되는 변수의 선언 최소화!
개인 피셜 난이도 : ★☆☆☆☆
간단해 보였지만, 결국 반복문을 잘 활용해야 했던 문제,
2번 풀이와 같이 객체지향적 방식의 코딩을 좀 더 공부를 해야겠다.
코딩 테스트 문제들은 대부분 반복문과 조건문에 의해,
풀이가 되는 건 사실이지만,
2번 풀이와 같은 체계적인 설계를 구사할 때,
현업에서 좀 더 창의적으로 코드를 구현할 수
있을 것 같다.
개인 피셜 난이도는 낮았지만,
생각이 많아지는 고수님들의
풀이들이었다...ㅎㅎㅎ
끝!
'코딩테스트 > 프로그래머스' 카테고리의 다른 글
[Java] 프로그래머스 가운데 글자 가져오기 자바 (0) | 2022.08.06 |
---|---|
[Java] 프로그래머스 2016년 자바 (0) | 2022.08.04 |
[Java] 프로그래머스 로또의 최고 순위와 최저순위 자바 (0) | 2022.07.08 |
[Java] 프로그래머스 신규아이디 추천 자바 (0) | 2022.07.05 |
Java 프로그래머스 실패율 자바 (0) | 2022.07.01 |