
프로그래머스 코딩테스트 Lv. 1 Java로 01부터 10까지 풀기 (최신순 정렬 기준)
문제 설명
당신은 폰켓몬을 잡기 위한 오랜 여행 끝에, 홍 박사님의 연구실에 도착했습니다. 홍 박사님은 당신에게 자신의 연구실에 있는 총 N 마리의 폰켓몬 중에서 N/2마리를 가져가도 좋다고 했습니다.
홍 박사님 연구실의 폰켓몬은 종류에 따라 번호를 붙여 구분합니다. 따라서 같은 종류의 폰켓몬은 같은 번호를 가지고 있습니다.
예를 들어 연구실에 총 4마리의 폰켓몬이 있고, 각 폰켓몬의 종류 번호가 [3번, 1번, 2번, 3번]이라면 이는 3번 폰켓몬 두 마리, 1번 폰켓몬 한 마리, 2번 폰켓몬 한 마리가 있음을 나타냅니다.
이때, 4마리의 폰켓몬 중 2마리를 고르는 방법은 다음과 같이 6가지가 있습니다.
이때, 첫 번째(3번) 폰켓몬과 네 번째(3번) 폰켓몬을 선택하는 방법은 한 종류(3번 폰켓몬 두 마리)의 폰켓몬만 가질 수 있지만, 다른 방법들은 모두 두 종류의 폰켓몬을 가질 수 있습니다. 따라서 위 예시에서 가질 수 있는 폰켓몬 종류 수의 최댓값은 2가 됩니다.당신은 최대한 다양한 종류의 폰켓몬을 가지길 원하기 때문에, 최대한 많은 종류의 폰켓몬을 포함해서 N/2마리를 선택하려 합니다. N마리 폰켓몬의 종류 번호가 담긴 배열 nums가 매개변수로 주어질 때, N/2마리의 폰켓몬을 선택하는 방법 중, 가장 많은 종류의 폰켓몬을 선택하는 방법을 찾아, 그때의 폰켓몬 종류 번호의 개수를 return 하도록 solution 함수를 완성해주세요.
제한사항
입출력 예
| nums | result |
|---|---|
| [3,1,2,3] | 2 |
| [3,3,3,2,2,4] | 3 |
| [3,3,3,2,2,2] | 2 |
다양한 포켓몬 수에 초점을 둬야 함.
피카츄 3마리, 이상해씨 2마리, 파이리 1마리가 있을 때 나는 총 3마리의 포켓몬을 데려갈 수 있음.
포켓몬을 데려가는 경우의 수는 여러개지만, 나는 포켓몬을 다양하게 데려가고 싶음.
그렇다면 피카츄 1마리, 이상해씨 1마리, 파이리 1마리 데려가는게 다양하게 데려가는 방법일 것임.
→ 이렇게 데려가는 게 지금 내 경우의 수 중에서는 가장 다양한 포켓몬을 데려가는 수임.
나는 총 3마리의 다양한 포켓몬을 데려갈 수 있으며, 이 수는 내 경우의 수 중 가장 다양한 포켓몬을 데려가는 수임.
그래서 답은 3이 됨.
다시 한 번 조건을 정리하면
1) 나는 총 n/2마리의 포켓몬을 데려갈 수 있음.
2) 반환하고자 하는 값은 최대 몇마리의 다양한 포켓몬을 데려오냐임.
class Solution {
public int solution(int[] nums) {
int answer = 0;
int[] check = new int[200001];
for (int i = 0; i < nums.length; i++) {
check[nums[i]]++;
}
for (int i = 1; i < check.length; i++) {
if (check[i] > 0) answer++;
}
return nums.length/2 < answer ? nums.length/2 : answer;
}
}
이 풀이가 맞는지는 모르겠지만..
피카츄 2마리, 이상해씨 1마리, 파이리 1마리, 꼬부기 2마리라면
→ 결국 데려갈 수 있는 포켓몬 수는 n/2(=3)마리로 정해져 있기 때문에 답은 여전히 3일 것임.
(사고 전환) 총 종류가 n/2보다 크면 최댓값을 n/2로 고정시키면 되지 않을까?
그래서 이 부분을 nums.length/2 < answer ? nums.length/2 : answer을 사용해 조절함.
처음에는 난이도 왜이래하면서 프로그래머스 1레벨 난이도 검색해봤는데 생각보다 괜찮다!
결국 로직을 잘 구성하면 순서대로 잘 풀린다!
거기에 내 로직이 맞나 다른 사람들이 풀었던 방식을 살펴보니 맞았다! 자기 풀이에 대해 자신감을 가질 필요가 있을 듯하다. → 대신 배열 부분을 어떻게 다루는 지는 큰 차이가 났다. 리팩토링 단계를 거치게 된다면 수정해볼 필요가 있겠다.
+) 해시 다루는 문제인줄은 몰랐어!
문제 설명
2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각 SUN,MON,TUE,WED,THU,FRI,SAT입니다. 예를 들어 a=5, b=24라면 5월 24일은 화요일이므로 문자열 "TUE"를 반환하세요.
제한 조건
입출력 예
| a | b | result |
|---|---|---|
| 5 | 24 | "TUE" |
우선 확인해야할 것은 2016년이 윤년이라서 2월 29일이 추가된 것이고, 2016년 1월 1일이 금요일이라는 것임.
요일을 배열(0 1 2 3 4 5 6)로 나타낸다고 했을 때, 금요일을 0이라고 설정할 것임.
월과 일이 입력되면 그 입력된 날짜에서 1월 1일과 얼마나 떨어져 있는지를 구할 것이고, 7을 나눈 나머지를 답으로 받을 것임.
[윤년에 대한 월별 일수]
1 3 5 7 8 10 12는 31일, 4 6 9 11은 30일, 2는 29일을 가지고 있음.
이를 배열로 만들면 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}가 될 것임. 배열의 인덱스를 이용하여 월별 일수와 입력된 일을 더하여 1월 1일과의 거리를 나타낼 것임.
EX) 6월 24일 → ((31 + 29 + 31 + 30 + 31 + 24) - 1) % 7
-1을 해야 배열 0부터 출력됨. → (1월 1일을 집어넣는다고 할 때 값이 0부터 나와야 하므로)
class Solution {
public String solution(int a, int b) {
String answer = "";
int[] months = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
String[] dayOfTheWeek = {"FRI", "SAT", "SUN", "MON", "TUE", "WED", "THU"};
int days = 0;
for (int i = 1; i < a; i++) {
days += months[i-1];
}
days = (days + b - 1) % 7;
answer = dayOfTheWeek[days];
return answer;
}
}
옛날 생각난다. C언어 배울 때 윤년 출력하기, 년월일 주어지고 요일 맞추기 문제 많이 풀었는데 이 문제를 또 풀게 됐다. 그 때는 그거 한문제 풀 때 죽을 맛이었는데 지금은 뚝딱하니깐 성장한 느낌이 난다.
dayOfTheWeek가 1월 1일 기준으로 나열됐긴 했는데 이걸 일요일부터 시작하게 하거나 월요일부터 시작하게 할 순 없을까?
문제 설명
단어 s의 가운데 글자를 반환하는 함수, solution을 만들어 보세요. 단어의 길이가 짝수라면 가운데 두글자를 반환하면 됩니다.
제한사항
입출력 예
| s | return |
|---|---|
| "abcde" | "c" |
| "qwer" | "we" |
음.. 가운데 글자를 가져오되 단어의 길이가 짝수가 되면 두 글자를 가져와야 함.
어떤식으로 가져올 수 있을지 생각을 해봤음.
EX) qwer에서 we를 가져와야 한다면 문자열의 길이가 4가되고 1번 인덱스와 2번 인덱스의 내용을 가져와야 함.
→ 4/(1+1) 4/(2+1)을 하면 똑같이 2가 나오므로 이렇게 가져올 수 있지 않을까 싶음.
EX2) 문자열의 길이가 6이라면 2번 인덱스와 3번 인덱스의 내용을 가져와야 할 것임.
→ 6/(2+1) 6/(3+1)을 하면 또 똑같이 2가 나옴.
짝수는 이런 식으로 해결할 수 있다고 가정하면 홀수는 아마 다른 방식으로 해줘야 할 것임.
EX) 문자열의 길이가 5라면 2번 인덱스의 내용을 가져와야 할텐데 아까와 똑같이 5/(2+1)로 계산하면 안될 것임. → (5-1)/2 가 되어야 하지 않을까 싶음.
결론: 홀수와 짝수에 따라 구하는 방식이 달라지므로 조건문으로 분기를 나눠줘야 할 듯.
class Solution {
public String solution(String s) {
String answer = "";
String[] arr = s.split("");
int size = arr.length;
if (size % 2 == 0) answer = arr[size/2-1] + arr[size/2];
else answer = arr[size/2];
return answer;
}
}
문자열 문제나 문자 문제만 만나면 골치가 아파온다. 이렇게 배열로만 해결하는게 좋은 해결방법은 아닌거 같은데..
다른 사람의 코드를 보니 substring으로 풀었다.
return s.substring((s.length()-1) / 2, s.length()/2 + 1);
아예 이 한문장으로 끝내버릴 수 있다고 한다. 처음에는 substring으로 풀었는데 뭔가 확실하지 않은 것 같아서 배열 사용을 했었는데 이제는 계속 경우의 수 만들어가면서 끝까지 작성해봐야겠다.
문제 설명
배열 arr가 주어집니다. 배열 arr의 각 원소는 숫자 0부터 9까지로 이루어져 있습니다. 이때, 배열 arr에서 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하려고 합니다. 단, 제거된 후 남은 수들을 반환할 때는 배열 arr의 원소들의 순서를 유지해야 합니다. 예를 들면,
배열 arr에서 연속적으로 나타나는 숫자는 제거하고 남은 수들을 return 하는 solution 함수를 완성해 주세요.
제한사항
입출력 예
| arr | answer |
|---|---|
| [1,1,3,3,0,1,1] | [1,3,0,1] |
| [4,4,4,3,3] | [4,3] |
처음 중복 제거를 보고는 distinct()를 생각했는데 이거는 배열 전체의 중복을 없애는 거라서 힘들 것 같음.
아무래도 배열을 저장할 때, 전에 저장된 데이터와 현재 위치에 저장된 데이터를 비교해서 둘이 같으면 continue, 같지 않으면 저장하는 방식으로 가야할 것 같음.
import java.util.*;
public class Solution {
public int[] solution(int []arr) {
int[] answer = {};
List<Integer> list = new ArrayList<>();
list.add(arr[0]);
for (int i = 1; i < arr.length; i++) {
if (arr[i-1] == arr[i]) continue;
else list.add(arr[i]);
}
answer = list.stream().mapToInt(Integer::intValue).toArray();
return answer;
}
}
이번 문제에 드디어 출력 기능이 생긴듯 하다. 아마 문제마다 제공하기도 하고 제공 안하는 것 같기도 하다. 마지막에 문제 채점할 때는 그 출력문을 다 지워야 하니 잊지말자.
지금까지 거의 모든 문제에서 리스트에서 배열로 변경하는 것을 stream()을 사용했었는데,
int[] answer = new int[tempList.size()];
for (int i = 0; i < answer.length; i++) {
answer[i] = tempList.get(i).intValue();
}
이런식으로 반복문으로 순회해서 처리하는 게 더 빠르다고 함. 다만 반복문이 들어가서 효율적인지는 잘 모르겠음.. 아직 이런거 판별하는 능력은 없는 듯;
문제 설명
array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.
제한사항
입출력 예
| arr | divisor | return |
|---|---|---|
| [5, 9, 7, 10] | 5 | [5, 10] |
| [2, 36, 1, 3] | 1 | [1, 2, 3, 36] |
| [3,2,6] | 10 | [-1] |
우선 arr에서 divisor로 나누어 떨어지는 애를 다른 리스트로 옮기고 리스트를 정렬함과 동시에 배열로 바꾸면 될 것같음.
import java.util.*;
class Solution {
public int[] solution(int[] arr, int divisor) {
int[] answer = {};
List<Integer> list = new ArrayList<>();
for (int i : arr) {
if (i % divisor == 0) list.add(i);
}
if (list.size() == 0) list.add(-1);
answer = list.stream().sorted().mapToInt(Integer::intValue).toArray();
return answer;
}
}
다른 사람 코드를 보니 람다 한 줄로 끝내버리는 경우가 많았음.
int[] answer = Arrays.stream(arr).filter(e1 -> e1 % divisor == 0).toArray();
...
람다 사용을 자주 해봐야 겠음.
문제 설명
두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수, solution을 완성하세요.예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.
제한 조건
입출력 예
| a | b | return |
|---|---|---|
| 3 | 5 | 12 |
| 3 | 3 | 3 |
| 5 | 3 | 12 |
a와 b의 대소관계가 정해져 있지 않기 때문에 max와 min을 정해준 후 반복문으로 더해주면 될 듯.
class Solution {
public long solution(int a, int b) {
long answer = 0;
int max = Math.max(a, b);
int min = Math.min(a, b);
for (int i = min; i <= max; i++) answer += i;
return answer;
}
}
등차수열의 원리를 사용하기도 하는 듯.
class Solution {
public long solution(int a, int b) {
return sumAtoB(Math.min(a, b), Math.max(b, a));
}
private long sumAtoB(long a, long b) {
return (b - a + 1) * (a + b) / 2;
}
}
(첫항 + 끝항) * (사이 항 개수) / 2
문제 설명
문자열로 구성된 리스트 strings와, 정수 n이 주어졌을 때, 각 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬하려 합니다. 예를 들어 strings가 ["sun", "bed", "car"]이고 n이 1이면 각 단어의 인덱스 1의 문자 "u", "e", "a"로 strings를 정렬합니다.
제한 조건
입출력 예
| strings | n | return |
|---|---|---|
| ["sun", "bed", "car"] | 1 | ["car", "bed", "sun"] |
| ["abce", "abcd", "cdx"] | 2 | ["abcd", "abce", "cdx"] |
공부했던 comparator 써먹는게 좋아보임.
만약 n번째 글자가 같으면 원래 배열에 있던 문자열을 비교하도록 하고, 그렇지 않으면 n번째 글자만 비교하도록 하는 함수를 구현하면 될 것 같음.
import java.util.*;
class Solution {
public String[] solution(String[] strings, int n) {
Arrays.sort(strings, new Comparator<String>() {
public int compare(String e1, String e2) {
if (e1.charAt(n) == e2.charAt(n)) return e1.compareTo(e2);
else return e1.charAt(n) - e2.charAt(n);
}
});
return strings;
}
}
다른 사람들은 생각보다 주어진 자원을 어떻게 활용하느냐가 아니라 어떻게 문제를 접근할까를 가장 연구를 많이 하는 듯함. 가장 평이 좋았던 풀이인데 이 문제의 경우 n번째 문자를 앞으로 끄집어내서 “n번째 문자+문자열” 형태로 만든 후에 정렬하는 방법이었음.
import java.util.*;
class Solution {
public String[] solution(String[] strings, int n) {
String[] answer = {};
ArrayList<String> arr = new ArrayList<>();
for (int i = 0; i < strings.length; i++) {
arr.add("" + strings[i].charAt(n) + strings[i]);
}
Collections.sort(arr);
answer = new String[arr.size()];
for (int i = 0; i < arr.size(); i++) {
answer[i] = arr.get(i).substring(1, arr.get(i).length());
}
return answer;
}
}
굳이 리스트 안써도 될 것 같아서 수정해봄. → 다만 시간을 고려한다면 배열을 쓰는 편이 나음.
import java.util.*;
class Solution {
public String[] solution(String[] strings, int n) {
String[] answer = new String[strings.length];
for (int i = 0; i < strings.length; i++) {
answer[i] = strings[i].charAt(n) + strings[i];
}
Arrays.sort(answer);
for (int i = 0; i < answer.length; i++) {
answer[i] = answer[i].substring(1, answer[i].length());
}
return answer;
}
}
문제 설명
대문자와 소문자가 섞여있는 문자열 s가 주어집니다. s에 'p'의 개수와 'y'의 개수를 비교해 같으면 True, 다르면 False를 return 하는 solution를 완성하세요. 'p', 'y' 모두 하나도 없는 경우는 항상 True를 리턴합니다. 단, 개수를 비교할 때 대문자와 소문자는 구별하지 않습니다.
예를 들어 s가 "pPoooyY"면 true를 return하고 "Pyy"라면 false를 return합니다.
제한사항
입출력 예
| s | answer |
|---|---|
| "pPoooyY" | true |
| "Pyy" | false |
p를 제거한 문자열의 크기 = y를 제거한 문자열의 크기
라는 생각으로 풀어봄.
class Solution {
boolean solution(String s) {
String str = s.toLowerCase();
int p = str.replaceAll("p", "").length();
int y = str.replaceAll("y", "").length();
return p == y ? true : false;
}
}
저번 문제도 그렇고 기존에 주어진 문자열을 변형해서 문제를 푸는 방법이 신선한 듯함.
class Solution {
boolean solution(String s) {
return s.replaceAll("[^yY]", "").length() - s.replaceAll("[^pP]", "").length() == 0 ? true : false;
}
}
이 문제를 한 줄로 바꾸면 이렇게 되는 듯?
정규식을 쓸거면 확실히 써봐야겠음.
문제 설명
문자열 s에 나타나는 문자를 큰것부터 작은 순으로 정렬해 새로운 문자열을 리턴하는 함수, solution을 완성해주세요.s는 영문 대소문자로만 구성되어 있으며, 대문자는 소문자보다 작은 것으로 간주합니다.
제한 사항
입출력 예
| s | return |
|---|---|
| "Zbcdefg" | "gfedcbZ" |
정렬이 큰 것부터 작은 순으로 정렬하는 것이니 내림차순을 하면 될듯함.
import java.util.*;
class Solution {
public String solution(String s) {
String[] arr = s.split("");
Arrays.sort(arr, (e1, e2) -> {
return (int)e2.charAt(0) - (int)e1.charAt(0);
});
return String.join("", arr);
}
}
String.join("", arr): String 배열을 문자열로 만들어줌.
이쯤되니 stream을 공부해야 할것 같기도하고.. stream만 쓰면 가독성이 신경쓰이고.. 애매해진 것 같음.
문제 설명
문자열 s의 길이가 4 혹은 6이고, 숫자로만 구성돼있는지 확인해주는 함수, solution을 완성하세요. 예를 들어 s가 "a234"이면 False를 리턴하고 "1234"라면 True를 리턴하면 됩니다.
제한 사항
s는 길이 1 이상, 길이 8 이하인 문자열입니다.s는 영문 알파벳 대소문자 또는 0부터 9까지 숫자로 이루어져 있습니다.입출력 예
| s | return |
|---|---|
| "a234" | false |
| "1234" | true |
말 그대로 길이가 4 혹은 6이고, 숫자로만 구성되어 있는지 확인하면 될 것 같음.
class Solution {
public boolean solution(String s) {
int length = s.length();
if ((length == 4 || length == 6) && !s.matches(".*[a-zA-Z].*")) return true;
else return false;
}
}
matches(): 문자열에 다음이 포함되어 있는지 확인함. contains와는 달리 정규식 사용이 가능함.
예외 처리로 푼 사람이 많던데 실제로 예외 사용은 좋지 않다고 함!!
1) 참고로 인덱스는 내가 최신순으로 정렬해둔 뒤 맨 마지막부터 붙였다. 그래도 구별은 해야하니깐.
2) 코테 레퍼지토리를 만들었는데 생각보다 관리하기 귀찮다. 그래도 코드 자체는 관리하기 쉬워서 꾸준히 해둬야 겠다.