Algorithm/프로그래머스 LV 1 (Day 4)

[JAVA] 알고리즘 LV.1 추가 학습 정리

pwoogi 2022. 7. 18. 19:37

학습 출처 : 프로그래머스

 

모든 문제가 프로그래머로써 입문단계라는게 놀라웠다
기초단계는 아직 시작도 안했다는 것..
문제도 아직 남았지만 CS지식도 학습해야하기 때문에
마무리 겸 복습을 해보자.

 

 

스킬체크

  • 입력 받은 문자열을 공백을 포함하여 함께 나누고 인덱스 짝수번째, 홀수번째의 문자를 대문자, 소문자로 치환하기

받은 문자열을 문자배열에 하나씩 넣어줄 때

String[] str = s.split("");

그 중에 공백을 찾아서 변수를 리셋해주고 나머지 글자가 짝수번째인 경우에는 대문자, 홀수번째인 경우에는 소문자로 바꿀 때

for(int i=0; i<str.length; i++) {
            if(str[i].equals(" ")) {
                idx = 0;
            } else if(idx % 2 == 0) {
                str[i] = str[i].toUpperCase();
                idx++;
            } else {
                str[i] = str[i].toLowerCase();
                idx++;
            }
            answer += str[i];

 


 

  • 입력받은 숫자를 문자열로 반환하고 각 요소들을 더해서 다시 정수로 반환해주기

매개변수를 문자열로 반환할 때 

public int solution(int n) {
        String str = Integer.toString(n);

문자열로 받은 정수들을 반복문을 통해 더하고 다시 정수값으로 결과를 반환할 때

for(int i = 0; i < str.length(); i++){
            answer += Integer.parseInt(str.substring(i, i+1));
        }

Wrapper class가 가지고 있는 toString, parseInt, parseDouble 등 받은 값을 원하는 형태로 바꿔주는 메소드이고 자주 사용하니 사용법을 익혀두자

 


 

  • 받은 자연수 값의 순서를 뒤집어서 배열로 만들기
class Solution {
    public int[] solution(long n) {
        
        long num = n;
        int cnt = 0;
        
        while(num != 0){
            num /= 10;
            cnt++;
        }
        
        int[] answer = new int[cnt];
        
        num = n;
        for(int i = 0; num != 0; i++){
            answer[i] = (int)(num % 10);
            num /= 10;
        }
        
        return answer;
    }
}
  1. num /= 10, num % 10 은 while, for 문에서 자주 등장한다.
  2. n = 12345일 때 answer = [5,4,3,2,1]로 바꿔주려면 각 요소를 10으로 먼저 나누고 반복문을 통해 변수 num에 대입
 while(num != 0){
    num /= 10;
    // 12345 = 1234
    // 1234 = 123
    // 123 = 12
    // 12 = 1
    // 1 = 0 ( 0.1 )
    cnt++;

3. cnt를 이용하여 새로운 길이의 배열을 만든다.

4.num 변수를 다시 입력받은 값 n으로 초기화 시킨 후 10으로 나눈 나머지 값을 answer [ i ] 의 요소에 대입해주고 위에서 10을 나눈 방식으로 num에 대입해서 반복문을 실행시키면 원하는 [5,4,3,2,1] 형태의 배열을 반환할 수 있다.

num = n;
    for(int i = 0; num != 0; i++){
        answer[i] = (int)(num % 10);
        num /= 10;
    }
// 1) 12345 % 10 = 5
// 2) 1234 % 10 = 4
// 3) 123 % 10 = 3
// 4) 12 % 10 = 2
// 5) 1 % 10 = 1

 

다른 사람의 풀이

문자열을로 숫자를 "" 를 이용해서 바로 치환하니까 코드가 훨씬 가독성이 좋고 간소해졌다. 어쨌든 핵심은 10으로 나눈값, 10으로 나눈 나머지값이 어떻게 활용되는지를 꼭 기억해두자.

class Solution {
  public int[] solution(long n) {
      String a = "" + n;
        int[] answer = new int[a.length()];
        int cnt=0;

        while(n>0) {
            answer[cnt]=(int)(n%10);
            n/=10;
            System.out.println(n);
            cnt++;
        }
      return answer;
  }
}

 


 

  • 받은 정수값을 큰수에서 작은수 순서로 리턴해주기

입력받는 매개변수 n의 요소를 뽑아내서 split을 통해 list 배열에 한 문자씩 담는다.

그리고 Arrays 클래스 sort함수를 이용하고 Collections 클래스의  reverseOrder 메소드를 이용하여 역순으로 정렬한다.

import java.util.*;

String[] list = String.valueOf(n).split("");
Arrays.sort(list, Collections.reverseOrder());

StringBuilder 객체를 만들고 반복문을 통해 list에 각 요소를 추가한다. 

그 후, StringBuilder객체 list에 있는 문자열을 꺼내어 parseLong 메소드를 이용하여 Long타입으로 변환해준다.

StringBuilder sb = new StringBuilder();
    for(String s:list) {
        sb.append(s);
    }
    return Long.parseLong(sb.toString());

전체적인 알고리즘 풀이 순서를 기억하자(논리적 구조)

 


 

  • 정수 제곱근 판별 + 응용
// Double wrapper class에 있는 intValue()로 정수형 숫자로 바꾼다.
// 바꾸기 전 숫자와 바꾼 후 숫자가 같으면 정수다.
Double sqrt = Math.sqrt(n);
if(sqrt == sqrt.intValue())

 

위에서 자주 등장하는 parseInt() 와 intValue()의 차이는 무엇일까?

parseInt()

static 이다, 그러므로 Integer 생성안하고 parameter만 넣어주면 메소드를 수행할 수 있다.   
쉽게 말하자면 String형 객체에서 int형 값을 뽑아내는 메소드이다. 
Integer 객체 생성하지 않는다

즉, Integer(Object) 라는 박스를 만들지 않고 (래퍼 클래스와 언박싱,오토박싱)
내용물(String) -> 내용물(int) 교체한다.
intValue()

static이 아니며 Integer 객체에서 int형 값을 뽑아내는 메소드이다
Integer는 (int Value와 String Value) 두 가지가 있다.
 
즉, Object -> int 
객체란 박스에서 내용물을 꺼내야 int 라는 내용물로 옮길 수 있다.
언박싱 해줘야 한다.
 
Integer -> (언박싱) -> int 변환

상황에 맞는 메소드 쓰기

1.내용물 -> 내용물 형변환 Integer.parseInt();

2.객체 -> 내용물 변환 intValue();

 

그렇다면 다시 문제로 돌아오자

    Double sqrt = Math.sqrt(n);

        if(sqrt == sqrt.intValue()){
        return (long)Math.pow(sqrt + 1, 2);
        } else return -1;
    }
}

sqrt, pow는 모두 double 타입의 값을 반환하기 때문에 sqrt == squrt.intValue 를 비교해서 정수값과 실수값이 같은 경우를 비교해서 제곱근을 만들어줄 수 있는지를 확인이 필요하다.

 

예를 들어 121 이라는 정수를 n에 넣었다면 sqrt == 11.0을 반환해주고 squrt.intValue == 11을 반환해준다. (형변환 가능)

하지만 155 이라는 정수를 n에 넣으면 sqrt == 12.4498을 반환하고 squrt.intValue == 12를 반환할 것이다.

이하 설명은 생략하겠다. (혹시나 제가 잘 못 알고 있다면.. 댓글부탁합니다 행님,누님들)

 


 

  • 제일 작은수 제거하기

배열에 가장 작은 수를 제거하고 나머지 요소를 반환해보는 작업이다. 만약에 비교할 대상이 없는 배열인 경우에는 -1을 반환해주면 된다.

[-1]을 반환하는 것은 매우 간단하다.

if(arr.length == 1){
    int[] answer = {-1};
    return answer;
}

그렇다면 이제 새로운 대열이 필요할 것이다.{ arr[0], arr[1], arr[2], arr[3] }길이 4인 배열을 갖고 있는 배열이라면

{arr[0], arr[1], arr[2]}의 길이를 만들어야한다.

길이를 줄이고 변수 min의 값을 최소값으로 변환하여 arr[0]에 담는다.

int[] answer = new int[arr.length-1];

int min = arr[0]; 
for(int i=1; i<arr.length; i++){
    min = Math.min(min, arr[i]);
}

그리고 하나의 변수를 선언해주고 원래 4개 길이의 arr[ ] 배열의 요소들이 min의 변수가 가르키는 arr[ 0 ]의 요소와 같은지 비교하여 continue문으로 빠져나가게 해주고 값이 같지 않은 요소가 있다면 answer [ ] 배열에 인덱스를 증감하여 값을 넣어주면 된다.

int index = 0;
       
    for(int i=0; i<arr.length; i++){
        if(arr[i] == min){
            continue;
        }
        answer[index++] = arr[i];
    }

 


 

이제 왠..수학자들이 등장한다
😇

 

 

  • 콜라츠 추측

1937년 Collatz란 사람에 의해 제기된 이 추측은, 주어진 수가 1이 될 때까지 다음 작업을 반복하면, 모든 수를 1로 만들 수 있다는 추측

 

1-1. 입력된 수가 짝수라면 2로 나눕니다. 
1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다. 
2. 결과로 나온 수에 같은 작업을 1이 될 때까지 반복합니다. 

 

작은 함정으로 시작되는 문제다. 

주어진 수를 받아서 짝수면 2로 홀수면 3을 곱하고 1을 더하면 모든 수를 1로 만들어 보는 문제이며 아래의 조건을 살펴보자. 

  • 입력된 수, num은 1 이상 8,000,000 미만인 정수입니다.
  • 주어진 수가 1인 경우에는 0을, 작업을 500번 반복할 때까지 1이 되지 않는다면 –1을 반환해 주세요.

 

public int solution(int num) {
        long n = num;

여기엔 작은 함정이 있다.

만약 626331이라는 정수값을 아래 parameter 변수타입을 int 타입으로 받게 되면 Overflow가 되어 기대하던 값을 받지 못하게 된다.

그렇기 때문에 long 타입으로 매개변수를 받아줄 수 있는 변수를 선언해야한다.

그리고 while 반복문안에 짝수일 때와 홀수 일때의 조건식을 써주고 answer++ 증감시킨다. 

answer값이 500일 때는 반복문을 빠져나와 -1을 return하게 해주면 된다.

int answer = 0;

while(n!=1){
    if(n % 2 == 0){
        n/=2;
    }else {
        n = 3*n+1;
    }answer++;
    if(answer == 500){
        answer = -1;
        break;
    }
}
return answer;

 


 

  • 하샤드 수인지 검사하기

정의 : 만약 정수 x가 하샤드 수이려면 x의 자릿수의 합으로 x가 나누어져야함.

예시 : 예를 들어 18의 자릿수 합은 1+8=9이고, 18은 9로 나누어 떨어지므로 18은 하샤드 수

 

풀이 : 

1. 매개변수 x 값을 저장할 수 있는 임의의 harshard 변수를 선언

2. 이전에 자리수 뒤집어서 배열에 넣었던 것 처럼 나누어 떨어지는 수를 구할 때 + while 조건문을 사용할 때 n/10, n%10을 자주 이용한다.

3. if문에서는 x의 값을 받았던 harshar 변수가 아닌 매개변수 x를 기준으로 sum의 나머지가 0이라는 조건을 만족할 때 하샤드 수임이 증명된다.

class Solution {
    public boolean solution(int x) {
        int sum = 0;
        int harshard = x;
        
        while(harshard >= 1){
            sum += harshard % 10;
            harshard /= 10;
        }
        if(x % sum == 0){
            return true;
        }else
        return false;
    }
}

 

 

속도보단 방향이라는 말이 있다.
하지만 때로는 방향보다 속도를 올려서
옳지 않은 방향으로 회전할 수 없도록 해야하는 경우도 있다.
나에겐 그게 지금인 것 같다. 학습은 while문처럼 😇