나와 같은 조의 다른 사람들이 푼 문제 보기
고성범 님(https://velog.io/@davidko)
서유리 님(https://yuricoding.tistory.com/)
김우진 님(https://blog.naver.com/woojin126)
5. 문자열을 정수로 치환하기
class Solution {
public int solution(String s) {
int answer = Integer.parseInt(s);
return answer;
}
}
문제의 요구사항을 보니 그냥 Integer.parseInt()를 알고 있는지 물어본 문제였던 것 같다.
만약 parseInt 쓰지 말고 하라고 한다면
class Solution {
public int solution(String s) {
int answer = 0;
// 곱해줄 자릿수
int digits = 1;
// 일의자리부터 연산 시작
for(int i = s.length()-1; i >= 0; i--){
char c = s.charAt(i);
// 맨 앞글자가 부호면 탈출
if(c == '-' || c == '+'){
break;
}
// char은 아스키코드표에 기반하여 값을 보관하기 때문에
// 정수로 치환할 때는 그 값만큼 빼줘야함.
// 숫자 0이 아스키코드표 기준 48인가 그런데 그냥 '0'으로 빼버려도 됨.
answer += (c - '0') * digits;
// 자릿수 up
digits *= 10;
}
// 마이너스 부호일 경우 부호 전환
if(s.charAt(0) == '-'){
answer *= -1;
}
return answer;
}
}
이렇게 하면 될 것이다.
9. 핸드폰 번호 가리기
class Solution {
public String solution(String phone_number) {
String answer = "";
int v = 4;
int pointer = phone_number.length() - v;
for(int i = 0; i < pointer; i++){
answer += "*";
}
answer += phone_number.substring(pointer, pointer + v);
return answer;
}
}
할 말이 없다. 자유롭게 풀었다.
아래는 가장 추천이 많았던 코드다.
class Solution {
public String solution(String phone_number) {
// String to char
char[] ch = phone_number.toCharArray();
// 뒤에 네 글자 제외하고 전부 *로 바꾸기
for(int i = 0; i < ch.length - 4; i ++){
ch[i] = '*';
}
return String.valueOf(ch);
}
}
String을 char형으로 변경한 뒤 그 자리를 치환해버린다는 발상이 인상적이었다. 게다가 문자열이 4글자보다 작을 때 에러가 발생할 가능성이 생기는 내 코드보다 대처가 잘 되어있었고, 코드 자체가 직관적이다. 전체적으로 훨씬 좋은 코드인 것 같다.
다음으로 regexp 사용한 사례가 있던데, 써본적이 없어서 이해하지 못 했다. 정규식을 알기 전까지는 쓰지 않는 것으로.
13. 2016년
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
class Solution {
public String solution(int a, int b) {
String answer = "";
LocalDate targetDate = LocalDate.of(2016,a,b);
// .ofPattern("E") : 한국일경우 월, 화, 수, ... 형식으로 출력
// .withLocale(Locale.forLanguageTag("en") : 언어를 영어로 설정. Mon, Tue, Wed, ... 형식으로 출력
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("E").withLocale(Locale.forLanguageTag("en"));
// 문제의 조건은 MON, TUE, WED, ... 형식으로 출력하는 것이었기 때문에 toUpperCase 적용
answer = dateTimeFormatter.format(targetDate).toUpperCase();
return answer;
}
}
지금까지는 Date 클래스를 써왔는데, JDK 버전이 몇인데 아직도 안 쓸 수는 없을 것 같아서 LocalDate를 이용해서 적용해봤다. 어떤것이 비교적 우월해서 이렇게 새로 나온것인지는 잘 모르겠지만, 새로 나온건 일단 써 봐야지.
DateTimeFormatter는 그대로 먹혔다.
날짜 관련 클래스의 메소드들은 굳이 외울 필요 없다. 어떤 클래스를 쓸 지만 알아놓으면 될 것 같다. 그게 객체지향이지.
17. 문자열 다루기 기본
class Solution {
public boolean d(String s){
boolean result = false;
if(s.length() == 4 || s.length() == 6){
try{
int test = Integer.parseInt(s);
result = true;
}catch(NumberFormatException e){
}
}
return result;
}
public boolean solution(String s) {
boolean answer = d(s);
return answer;
}
}
try ~ catch 구문을 이용해서 풀어봤다. 특별할 건 없었던 것 같다. 근데 이렇게 푸는게 바람직한지는 잘 모르겠다. 이게 생각나서 그냥 이렇게 해봤다.
21. 이상한 문자 만들기
class Solution {
public String solution(String s) {
String answer = "";
String[] str = s.split("");
int cnt = 0;
for (String ss : str) {
if (ss.contains(" ")) {
cnt = 0;
} else {
cnt++;
}
if (cnt % 2 == 1) {
answer += ss.toUpperCase();
}else{
answer += ss.toLowerCase();
}
}
// 이게 왜 안 될까.....?
// String[] strs = s.split(" ");
// for(int i = 0; i < strs.length; i++){
// for(int k = 0; k < strs[i].length(); k++){
// if(k % 2 == 0) {
// answer += Character.toUpperCase(strs[i].charAt(k));
// }else{
// answer += Character.toLowerCase(strs[i].charAt(k));
// }
// }
// if(i != strs.length-1){
// answer += " ";
// }
// }
return answer;
}
}
처음에 시도한게 주석의 내용이었다. 근데 작동이 제대로 안 돼서 카운터를 집어넣어서 주먹구구식으로 풀었다. 왜 아직도 주석한 게 안 되는지 모르겠다. 생각을 많이 해봐야 할 것 같다.
25. 정수 제곱근 판별
class Solution {
public long solution(long n) {
long answer = 0;
long sqrt = (long)Math.sqrt(n);
if(Math.pow(sqrt, 2) == n){
answer = (long)Math.pow(sqrt+1, 2);
}else{
answer = -1;
}
return answer;
}
}
솔직하게 말해서 이 문제는 Math 클래스 사용하지 말라고하면 어떻게 풀어야할지 잘 모르겠다. 제곱근을 구하는 특별한 방법이 있는걸까? 물론 이렇게 가혹하게 문제를 설정할 것 같진 않지만.....
29. 3진법 뒤집기
class Solution {
public int solution(int n) {
int answer = 0;
String str = "";
int digit = 3;
// 3으로 나눈 나머지 = 첫번째 자리
// 값을 3으로 나눔
// 3으로 나눈 나머지 = 두 번째 자리
// 값을 3으로 나눔
// 3으로 나눈 나머지 = n 번째 자리
// 값을 3으로 나눔
// ...
// 0이면 종료
while(n != 0){
str += String.valueOf(n%digit);
n /= digit;
}
str = str.substring(0, str.length());
// answer = Integer.parseInt(str, 3); 하면 끝남
long num = Long.parseLong(str);
for(int i = 1; num != 0; i*=digit){
answer += num % 10 * i;
num /= 10;
}
return answer;
}
}
3진수 변환을 어떻게 할지 고민한 흔적이 보인다.
str 처리같은경우 방법이 여러가지가 있는데,
1. str +=를 이용해 처음부터 역순으로 값을 받아온 뒤 맨 마지막값(0)을 지워주는 방법
2. str = ... + str 을 이용해 뒤에 붙여주면서 값을 받아온 뒤 str = new StringBuilder(str).reverse().toString() 사용하기
등등 방식으로 처리하면 된다.
3진법으로 다시 변환하는건 parse 시리즈 메소드에 다 달려있기 때문에 그냥 Integer.parseInt(str, 3)하면 끝나지만 한 번 직접 손으로 짜봤다. 3진수로 바꾸면 자릿수가 워낙 길어져 long 변수를 사용했다.
33. 로또의 순위
class Solution {
// 로또의 순위를 출력해주는 메소드
public int getRank(int num) {
int result = 6;
switch (num) {
case 6:
result = 1;
break;
case 5:
result = 2;
break;
case 4:
result = 3;
break;
case 3:
result = 4;
break;
case 2:
result = 5;
break;
}
return result;
}
public int[] solution(int[] lottos, int[] win_nums) {
int[] answer = {};
int win_cnt = 0;
int zero_cnt = 0;
// 1. 로또 숫자가 0일경우 zero_cnt를 증가시킨다.
// 2. 로또 숫자가 당첨 숫자와 일치할 경우 win_cnt를 증가시킨다.
// 3. 당첨된 숫자의 개수 + 0인 숫자의 개수로 나온 등수를 알아낸다.
// 4. 당첨된 숫자의 개수로만 나온 등수를 알아낸다.
// 5. 알아낸 두 개의 값을 answer 배열에 넣어준다.
for (int i = 0; i < lottos.length; i++) {
if (lottos[i] == 0) {
zero_cnt++;
continue;
}
for (int k = 0; k < win_nums.length; k++) {
if (lottos[i] == win_nums[k]) {
win_cnt++;
}
}
}
answer = new int[]{getRank(win_cnt + zero_cnt), getRank(win_cnt)};
return answer;
}
}
너무 오랜만에 자바를 써서 배열 사용법을 다 까먹었다. 그래서 꽤나 애를 먹었다. 그래도 결국 해냈다. 문제 자체는 어렵지 않았다.
아래는 추천을 많이 받은 코드이다.
import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] solution(int[] lottos, int[] win_nums) {
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
int zeroCount = 0;
for(int lotto : lottos) {
if(lotto == 0) {
zeroCount++;
continue;
}
map.put(lotto, true);
}
int sameCount = 0;
for(int winNum : win_nums) {
if(map.containsKey(winNum)) sameCount++;
}
int maxRank = 7 - (sameCount + zeroCount);
int minRank = 7 - sameCount;
if(maxRank > 6) maxRank = 6;
if(minRank > 6) minRank = 6;
return new int[] {maxRank, minRank};
}
}
코드 모양새 자체가 정말 예쁘다. 0 자체가 맵에 들어가는 경우가 없고 그 외엔 중복값을 허용하지 않으니 대신 Set을 써줘도 문제가 없을 것 같다.
속도 자체는 내가 작성한 코드가 더 빠르긴 하지만 그 차이가 매우 작기 때문에 읽기 훨씬 편하면서 중첩 반복문으로 인해 내재된 속도상의 변수가 존재하지 않는 이 코드가 낫다는 생각이 든다.
37. 소수 만들기
class Solution {
public boolean isPrime(int num){
boolean result = true;
// 소수 : 2 ~ (자기자신-1) 까지 나눈 나머지가 0인 경우가 없으면 소수
for(int i = 2; i < num; i++){
if(num % i == 0){
result = false;
break;
}
}
return result;
}
public int solution(int[] nums) {
int answer = 0;
// 삼중 for문을 보니 마음이 너무나도 불편하다.....
for (int i = 0; i < nums.length - 2; i++) {
for (int k = i + 1; k < nums.length - 1; k++) {
for (int m = k + 1; m < nums.length; m++) {
int sum = nums[i] + nums[k] + nums[m];
// 소수일 경우 개수 증가
if(isPrime(sum)){
answer++;
}
}
}
}
return answer;
}
}
로직이 전체적으로 많이 비효율적인 것 같다. 소수를 알아오는데 필요한 로직이나, 반복문을 3중첩한 것이나... 별로 마음에 들지 않는 코드다. 당장은 개선 방안이 별로 떠오르지 않아서 생각나는 방법대로 한 건데 이렇게 하면 안 될 것 같다. 개선이 많이 필요해보인다.
..... 프로그래머스에 제출한 다른 사람들의 답을 봐도 같은 모양인걸로 봐서 개선은 어려워보인다. 사실 문제 모양새 자체가 그렇게 생기긴 했다.
40. 신규 아이디 추천
import java.util.ArrayList;
import java.util.List;
class Solution {
public void removeFullStop(List<Character> list) {
if(list.size() > 0 && list.get(0) == '.'){
list.remove(0);
}
if(list.size() > 0 && list.get(list.size()-1) == '.'){
list.remove(list.size() - 1);
}
}
public String solution(String new_id) {
String answer = new_id;
List<Character> list = new ArrayList<>();
StringBuilder builder = new StringBuilder();
// 1단계: new_id의 모든 대문쟈를 대응되는 소문자로 치환
answer = answer.toLowerCase();
// 2단계: 알파벳 소문자, 숫자, 하이픈, 언더바, 마침표를 제외한 모든 문자 제거
char[] chars = answer.toCharArray();
for (char c : chars) {
if ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '.') {
list.add(c);
}
}
// 3단계: 마침표가 두 번 이상 연속되면 하나의 마침표로 치환
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i) == '.') {
if (list.get(i) == list.get(i + 1)) {
list.remove(i);
i = -1;
}
}
}
// 4단계: 마침표가 처음이나 끝에 있으면 제거
removeFullStop(list);
// 5단계: 빈 문자열일 경우 new_id에 a를 대입
if (list.size() == 0) {
list.add('a');
}
// 6단계: 문자열의 길이가 16자 이상일 경우 15문자를 제외하고 전부 제거
// 이후 5단계 한 번 더 시행
if(list.size() >= 16){
list = list.subList(0, 15);
removeFullStop(list);
}
// 7단계: 길이가 2자 이하인 경우 마지막 문자를 길이가 3이 될 때까지 반복
if(list.size() <= 2){
while(list.size() < 3){
list.add(list.get(list.size()-1));
}
}
for (Character ch : list) {
builder.append(ch);
}
return builder.toString();
}
}
원래 내 담당이 아닌 문제였는데, 문제가 너무 흥미로워서 직접 해봤다. list를 조금 많이 썼는데, char 배열로도 할 수 있을 것 같다. 하지만 내가 보기엔 list가 더 깔끔해보여서 이게 나은 것 같다. 난이도는 평범한 수준이었다.
아래 코드는 다른 사람이 작업한건데 너무나도 마음에 들어서 가져와봤다.
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class Solution {
public String solution(String new_id) {
return NewIdFactory.createFrom(new_id)
.getNewId();
}
private static class NewIdFactory {
public static NewId createFrom(String newId) {
// 모든 기능을 수행한 인스턴스 생성 후 return
return new NewId(newId)
.toLowerCase() // 1단계
.removeInvalidLetters() // 2단계
.replaceMultipleDots() // 3단계
.removeSideDotsIfPresent() // 4단계
.replaceIfEmpty() // 5단계
.removeOverloads() // 6단계-1
.removeBackDotsIfPresent() // 6단계-2
.appendInsufficientLetters(); // 7단계
}
}
private static class NewId {
private static final String REMOVAL_REGEX = "[^a-z0-9\\-_.]";
private static final String DEFAULT_ID = "a";
private static final Integer MAX_LENGTH = 15;
private static final Integer MIN_LENGTH = 3;
private final String newId;
public NewId(String newId) {
this.newId = newId;
}
public NewId toLowerCase() {
return new NewId(newId.toLowerCase());
}
public NewId removeInvalidLetters() {
return new NewId(newId.replaceAll(REMOVAL_REGEX, ""));
}
public NewId replaceMultipleDots() {
StringBuilder builder = new StringBuilder();
for (int i = 0, length = newId.length(); i < length; i++) {
if (newId.charAt(i) == '.') {
while (i < length && newId.charAt(i) == '.') {
i++;
}
builder.append(".");
i--;
continue;
}
builder.append(newId.charAt(i));
}
return new NewId(builder.toString());
}
public NewId removeSideDotsIfPresent() {
return removeFrontDotsIfPresent().removeBackDotsIfPresent();
}
public NewId removeFrontDotsIfPresent() {
if (newId.startsWith(".")) {
return new NewId(newId.substring(1));
}
return this;
}
public NewId removeBackDotsIfPresent() {
if (newId.endsWith(".")) {
return new NewId(newId.substring(0, newId.length() - 1));
}
return this;
}
public NewId replaceIfEmpty() {
if (newId.isEmpty()) {
return new NewId(DEFAULT_ID);
}
return this;
}
public NewId removeOverloads() {
if (newId.length() > MAX_LENGTH) {
return new NewId(newId.substring(0, MAX_LENGTH));
}
return this;
}
public NewId appendInsufficientLetters() {
if (newId.length() < MIN_LENGTH) {
String appendedId = IntStream.range(0, MIN_LENGTH - newId.length())
.mapToObj(i -> String.valueOf(newId.charAt(newId.length() - 1)))
.collect(Collectors.joining());
return new NewId(newId.concat(appendedId));
}
return this;
}
public String getNewId() {
return newId;
}
}
}
메소드명의 직관성, 내용의 간략함, 객체지향스러움까지 모두 가지고 있는 모습이 너무 예뻤다. 이게 마치 자바프로그래밍이다 라는 느낌이 드는 좋은 코드인 것 같다. 이렇게 작성하는 습관을 들여놔야 자바 개발자라는 말을 할 수 있지 않을까 싶다.
'내가 배운 것들 > 알고리즘' 카테고리의 다른 글
항해99 11/10(수) 알고리즘 - 알아서 푼 것들 (0) | 2021.11.10 |
---|---|
항해99 11/9(화) 알고리즘 (0) | 2021.11.09 |
항해99 11/9(화) 알고리즘 - 알아서 푼 것들 (0) | 2021.11.09 |
항해99 11/8(월) 알고리즘 - 알아서 푼 것들 (0) | 2021.11.08 |
항해99 11/8(월) 알고리즘 - 고성범님 담당 분량 (0) | 2021.11.08 |
댓글