위 내용들을 한번에 정리하려고 욕심내니 힘들어서

class에 관해서는 정리해야할 내용이 많은 것 같아 나눠서 포스팅하려고 합니다.

 

자바에서 class(이하 클래스)는 프로그램의 최소단위라고 할 수 있습니다다.

클래스는 하나의 패키지 안에서는 중복해서 이름을 지을 수 없죠.

그리고 생성자(Constructor)(이하 생성자)는 클래스의 이름과 같다는 특징을 가지고 있는데,

class clothes{
    private int shorts;
    private int longs;
    private [] int closet;
	
    // 디폴트 생성자의 모습입니다. 
    clothes(){
    	// 두 변수를 담아줄 옷장을 배열화했습니다.
    	closet = new int[2]
    }
	
    // int형인 shorts와 longs를 매개변수로 받는 경우를 오버로딩했습니다.
    clothes(int shorts, int longs){ 
    	// this의 첫번째 사용법입니다. 
        // 생성자 혹은 메서드(결국 생성자도 메서드이긴합니다만) 맨 위에 this() 형식으로
        // this에서 하는 역할을 중복해서 쓸 수고를 덜 수 있습니다.
        // 매개변수를 받지 않는 디폴트 생성자를 호출한 모습입니다. closet를 초기화합니다.
        this();
        this.shorts = shorts;
        this.longs = longs;
    }
    void prn( /* clothes this */){
        System.out.println("반팔티는" + this.shorts + "개, 긴팔티는" + this.longs + "개 있군요");
    }
    public void init(int shorts, int longs) {
    	// this의 두번째 사용법입니다.
        // 클래스에서 선언한 멤버 변수 자체를 지칭할 때 사용합니다.
        this.shorts = shorts;
        this.longs = longs;		
    }
    public clothes add(clothes c) {  // this<-c1   매개변수 c<-c2
        // c1과 c2더해서 새로운 객체에 저장하고 리턴
        clothes temp = new clothes();
        temp.shorts = this.shorts + c.shorts;
        temp.longs = this.longs + c.longs;
        return temp;
    }
    public clothes subtract(clothes c) {
        clothes temp = new clothes();
        temp.shorts = this.shorts - c.shorts;
        temp.longs = this.longs - c.longs;
        return temp;
    }
}

위의 예시에서 생성자의 간단한 모습과 this의 사용법을 알아보았습니다.

보통 this는 레퍼런스변수, 참조변수의 역할을 하며

this() 의 경우는 조금 분류가 달라집니다만 오버로딩된 자기 자신을 호출한다는 점에서 같이 알아보았습니다.

this 변수는 따로 기술하지 않은 숨어있는 변수라는 특징도 가지고 있으며

this 에는 현재 메서드를 호출한 객체의 참조변수값이 전달되어 저장됩니다.

※ 본 포스팅은 프로그래머스에 있는 연습문제 풀었던 내역을 아카이빙하기 위해 작성했습니다.

 

처음에 이 문제를 접하고 정말 어려웠었는데

 

"이게 왜 도대체 난이도 0이란 말인가?" 라는 생각을 했는데

 

최종 답안이 통과되는 순간에는

 

"아 이 정도면 난이도를 높게 설정할 수는 없겠구나"라는 생각이 들었다.

 

결론을 먼저 이야기하자면

 

Java의 "문자열 배열"과 문자열에서 특정한 문자를 "삭제하는 방법"을 알 수 있었다면

 

훨씬 접근이 간단해지는 문제였다.

 

(혹시나 답이 필요해서 여기까지 오신 분은 밑에 스크롤하지 마시고 다시 풀러가보세요)

 

 

 

            /*
            1. "aya", "ye", "woo", "ma" 네가지 발음이 들어가있다면
            처음 들어간 문자열을 지워냅니다. (replaceFirst)
            1-1. 여기에서 문자열을 비교했을 때 1번을 실행한 문자라면 같은 문자만 연속해서 존재하는지 
            (연속해서 존재한다면 지워내고 indexOf가 0인지 체크하면 되지 않을까?)
            1-2. 전 단계에서 indexOf로 실행한 결과가 0이 나오는 애들은 카운팅을 안하고 비활성화하고 싶다.
            (연속해서 같은 발음을 하는 것을 어려워한다.)
            비활성화하고 싶다고? 최후에 문자열 배열이 0이 되는 애들만 출력하고 싶다면
            aya ye woo ma 네가지로는 지워지지 않는 문자열을 끝에 삽입하면 되지 않을까?
            
            2. 위의 단계를 전부 다 통과했다면 
            aya ye woo ma 에 해당하는 문자열을 " 전 부 " 지워준다.
            
            3. 위의 단계를 전부 다 통과했다면 
            문자열의 길이가 0인지 체크하여 여기에서 0이라면 answer를 +1 해준다!
            */

 

이렇게 프로그램들이 할 기능들을 정리해주니 머리속이 한결 좋아졌다.

 

그래도 처음에 냈던 답안은 너무나도 길었었는데 처음에 냈던 답안은 다음과 같다.

 

class Solution {
    public int solution(String[] babbling) {
        int answer = 0;
        int i = 0;
        for(i = 0; i<babbling.length; i++){
            if(babbling[i].indexOf("aya") != -1 ){
                babbling[i] = babbling[i].replaceFirst("aya","");
                if(babbling[i].indexOf("aya")==0) {
             	  babbling[i] = babbling[i].concat("z");
             	}
            }
            if(babbling[i].indexOf("ye") != -1){
               babbling[i] = babbling[i].replaceFirst("ye","");
               if(babbling[i].indexOf("ye")==0) {
            	  babbling[i] = babbling[i].concat("z");
               }
            }
            if(babbling[i].indexOf("woo") != -1){
                babbling[i] = babbling[i].replaceFirst("woo","");
                if(babbling[i].indexOf("woo")==0) {
             	  babbling[i] = babbling[i].concat("z");
                }
            }
            if(babbling[i].indexOf("ma") != -1){
                babbling[i] = babbling[i].replaceFirst("ma","");
                if(babbling[i].indexOf("ma")==0) {
             	   babbling[i] = babbling[i].concat("z");
                }  
            } 
            
            babbling[i] = babbling[i].replace("aya","");       
			babbling[i] = babbling[i].replace("ye","");	        
			babbling[i] = babbling[i].replace("woo","");  
			babbling[i] = babbling[i].replace("ma","");
            if(babbling[i].length()==0) answer++;
		}

        return answer;
    }
}

 

위의 코드는 정말이지 단순무식하게 모든 과정을 하나하나 그려가면서 프로그램을 짰던 흔적이 보인다(...)

다시 보니 코드가 중복되는 문구가 너무 많기도 하고 비효율적이었다.

 

그렇게 복잡한 코드로 해도 일단 테스트는 통과였다

이미 정답은 맞췄지만 더 짧고 간결하게 수정하기로 했다.

 

 

 

class Solution {
    public int solution(String[] babbling) {
        int answer = 0;
        int i = 0;
        String [] bab = {"aya", "ye", "woo", "ma"};
        for(i = 0; i<babbling.length; i++){
            for(int j = 0;j<bab.length;j++){
                if(babbling[i].indexOf(bab[j]) != -1 ){
                    babbling[i] = babbling[i].replaceFirst(bab[j],"");
                    if(babbling[i].indexOf(bab[j])==0) {
                      babbling[i] = babbling[i].concat("z");
                    }
                }
                babbling[i] = babbling[i].replace(bab[j],"");
            }
            if(babbling[i].length()==0) answer++;
		}

        return answer;
    }
}

 

역시 고대의 티스토리 블로거들과

스택 오버플로우는 너무나도 최고다...

 

여러 도움을 얻어서 여기까지 코드를 줄이는데 성공했다.

 

위 코드에서 문자열을 전부 bab 이라는 문자열 배열을 생성해서 넣고

각 문자는 문자열 bab을 호출해서 반복문에 넣어서 차례대로 비교할 수 있도록 변경했다.

 

그렇게 해서 모든 과정을 다 거치고 조건을 만족한 입력값만 answer 값을 증가시키도록 하면 된다.

본 포스팅은 프로그래머스

https://programmers.co.kr/

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

에서 풀었던 문제 아카이빙 용 입니다.

 

 

문제:

머쓱이네 피자가게는 피자를 일곱 조각으로 잘라 줍니다. 피자를 나눠먹을 사람의 수 " n " 이 주어질 때, 모든 사람이

피자를 한 조각 이상 먹기 위해 필요한 피자의 수를 return 하는 solution 함수를 완성해보세요.

 

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

int solution(int n) {
    int answer = 0;
    int pan = 1; // 1명이 먹어도 피자 1판은 필요하니 1부터 시작합니다.
    while(7/n < 1){ // 7조각을 인원으로 나눴을 때 0.xxxx로 될 경우에 지속되는 반복문입니다
        n-=7; // 반복이 시행될 때마다 입력된 값에서 7이 빠져나갑니다.
        pan++; // 7명이 1판을 먹으러 간 이후에 다음 판을 생성합니다.
    }
    answer = pan;
    return answer;
}

 

이렇게 입력하면 n에 7을 입력해서 반복문 자체가 실행이 되지 않더라도

pan의 기본값을 1로 초기화했기 때문에

1판이라는 결과를 얻을 수 있습니다.

for

while

이 둘은 반복 실행문(이하 반복문)이라고 부른다.

 

사용 양식은 다음과 같다

for(  ;  ;  ){ 
//반복시킬 명령
}

 

괄호(  )안에 반복의 횟수를 조절할수 있는 문구들를 ';' 으로 구분해서 입력하고
그리고 그 조절된 횟수만큼 {  }안의 내용을 반복 실행한다.

 

위의 예제처럼 아무런 조건도 넣지 않을 경우 무한 루프가 발생한다.

 

1부터 10까지의 숫자를 곱하는 행위를 for문으로 표현해본다면

 

int i, a=1;
for(i = 1; i <= 10; i++){
	a *= i;
}

이런 식으로 표현할 수 있겠다 (이 코드가 정답은 아니고 그냥 예제일 뿐입니다.)

 

그렇다면 이 코드를 볼 때

i와 a라는 변수가 존재하고, i가 1에서부터 10까지 무엇인가를 하는 명령이겠구나

라는 생각을 할 수 있다.

 

이는 for문을 선언할 때나 코드를 해석할 때 구조적인 파악을 좀 더 쉽고 빠르게 할 수 있다는 장점으로 작용한다.

 

그러면 1부터 10까지의 숫자를 곱하는 행위를 while문으로 표현해보자.

 

int i = 1, a = 1;

while( i<=10 ) {
    a *= i;
    i++;
}

줄 수는 더 길어진 것처럼 보이지만

while문은 for문에 비하여 선언할 때는 조건만 확실히 하면 돼서 그 점은 더 간편하다고 할 수 있다.

while문은 확실히 i<=10 이라는 조건이 잘 보인다.

조건만 참이라면 계속해서 반복을 하기 때문에 for문에 비하여 더 간편한 점도 존재한다.

이는 while의 장점으로 작용한다.

 

while에 넣는 조건으로 true 혹은 1을 넣으면 무한히 반복하게 된다.

// 입력 받은 정수의 구구단을 출력하는 문구 
int a;
Scanner sc = new Scanner(System.in);
while(true) { // true 대신에 1을 넣어도 된다.
    System.out.printf("출력할 단을 입력하세요(끝내려면 0 입력) : ");
    dan = sc.nextInt();
    if(a == 0) break; // 0을 입력하면 반복이 끝나지만, 
    int i = 1;		//0을 입력하지 않으면 계속 위로 돌아가서 단 입력부터 반복하게 됩니다.
    while(i<=9) {
        System.out.printf(" %d x %d = %d\n", a, i, a*i);
        i++;
    }
}
System.out.println("프로그램이 종료됩니다");

 

하지만 동시에 생기는 단점으로는

적절한 시기, 혹은 적절한 데이터를 정확하게 사용해야한다는 점이 있다.

 

 

1. for와 while의 장단점

(1) for의 장점과 단점

장점 : 선언시 혹은 코드 읽을 때 그 구조를 좀 더 확실하게 구상할 수 있다.

단점 : while에 비해 코드가 길어지고 더러워질 가능성이 높다.

 

(2) while의 장점과 단점

장점: for에 비해 구문이 간결하고 조건 중심으로 코드를 짤때에는 강력하다.

단점: 좀 더 정교하고 정확하게 시기와 데이터를 파악해서 사용해야만한다.

 

 

 

 

 

 

반복문에 사용되는 break나 continue 등은 둘다 공통적으로 사용할 수 있다.

 

break나 continue는 

 

"특정한 조건을 만나면 반복을 끝내라"는 뜻이라고 보면 된다.

 

 

1부터 특정한 정수까지 짝수의 합을 출력하는 과정을 예제로 그 둘을 비교해보려고 한다.

 

// i가 1부터 10까지 늘어나면서 i가 홀수일 경우에는 밑에 실행해야하는 조건들을 실행하지 않고 
// 바로 i에 +1을 한 다음 조건으로 들어갑니다.
sum = 0;
for(i=1; i<=10; i++) {
    if( i%2 == 1)
        continue;   // 반복실행안에서 남아있는 아래 명령들을 실행하지 않고 다음 반복으로 이어지는 명령
    sum = sum + i;
    System.out.println("1부터 " + i + "까지의 합 : " + sum);
}


// i가 100까지 반복하게 되어 있지만 특정한 조건을 만족하면 100이 되어버리기 전에 반복이 종료됩니다.
sum = 0;
for(i=0; i<=100; i+=2) {
    if( i == 12)
        break;   // 특정 조건이 되었을 때 가장 가까운 반복문을 종료해버리는 명령
    sum = sum + i;
    System.out.println("1부터 " + i + "까지의 합 : " + sum);
}

둘 모두 1부터 10까지의 합은 30으로 정상출력되는 모습을 볼 수 있다.

 

추가적으로 주의해야할게 있다면

 

이중 for문으로 반복을 실행할 경우 break를 사용했을 때

반복문 전체가 끝나는게 아니라,

 

break를 중괄호로 감싸고 있는 반복만 종료된다는 점이다.

 

for( ; ; ){
	for( ; ; ){
    break; // 여기에 break를 사용할 경우 가장 가까운 for문만 종료되며
    }
    // 바깥의 for문은 계속 돌아가게 됩니다.
}

 

// 비교를 할 대상이 되는 문장
String level = "과장";

// 다음의 세가지 String 중에 하나랑만 맞다면 어떤 값이 반환될까
String kg = "과장";
String dr = "대리";
String sw = "신입";

 

Java 에서 String을 비교할 수 있는 기능으로는 compareTo와 equals가 있는데

 

실제 예제에 사용하면서 헷갈린 점이 있어서 확실히 구분하고자 간단히 남겨본다.

 

먼저 결론을 이야기하자면 compareTo의 반환값은 Int 이다.

굳이 int로 형변환을 거치지 않더라도

예를 들어서 저 위에 정의한 둘을 비교하자면

 

kg.compareTo(level)

kg.equals(level));

이런 식으로 level과 kg를 비교할 수 있게 되었다.

그러면 이 둘의 출력 값을 비교해보자.

 

System.out.println(kg.compareTo(level));
System.out.println(dr.compareTo(level));

System.out.println((int)kg.compareTo(level));
System.out.println((int)dr.compareTo(level));

System.out.println(kg.equals(level));
System.out.println(dr.equals(level));

이런 식으로 출력값을 본다면

 

0
1540

0
1540

true
false

 

console. 출력값

은 이런 식으로 나오게 된다.

 

 

compareTo는 형변환을 거치지 않아도 그 자체로 int이며

 

equals는 진위형(boolean)의 형태로 반환되는 것을 볼 수 있다.

 

이를 이용해서 equals는 반환값이 boolean 인 것을 이용해서 그 자체를 조건문의 조건에 대입해도 괜찮지만

 

compareTo는 == 0 과 같이 비교연산자를 붙여줘야 조건문에 사용할 수 있게 된다.

 

 

필자가 Java에서 배운 개념들을 조건문에 사용해보려다가 겪은 시행 착오 덕분에 이 포스팅을 하게 되었습니다...

 

+ Recent posts