[TIL] Algorithm, Class, Inheritance

Jay Mild Lee·2022년 11월 12일
0

TIL

목록 보기
2/7
post-thumbnail

I. 푸드 파이트 문제

https://school.programmers.co.kr/learn/courses/30/lessons/134240

1. 문제 설명

수웅이는 매달 주어진 음식을 빨리 먹는 푸드 파이트 대회를 개최합니다. 이 대회에서 선수들은 1대 1로 대결하며, 매 대결마다 음식의 종류와 양이 바뀝니다. 대결은 준비된 음식들을 일렬로 배치한 뒤, 한 선수는 제일 왼쪽에 있는 음식부터 오른쪽으로, 다른 선수는 제일 오른쪽에 있는 음식부터 왼쪽으로 순서대로 먹는 방식으로 진행됩니다. 중앙에는 물을 배치하고, 물을 먼저 먹는 선수가 승리하게 됩니다.

이때, 대회의 공정성을 위해 두 선수가 먹는 음식의 종류와 양이 같아야 하며, 음식을 먹는 순서도 같아야 합니다. 또한, 이번 대회부터는 칼로리가 낮은 음식을 먼저 먹을 수 있게 배치하여 선수들이 음식을 더 잘 먹을 수 있게 하려고 합니다. 이번 대회를 위해 수웅이는 음식을 주문했는데, 대회의 조건을 고려하지 않고 음식을 주문하여 몇 개의 음식은 대회에 사용하지 못하게 되었습니다.

예를 들어, 3가지의 음식이 준비되어 있으며, 칼로리가 적은 순서대로 1번 음식을 3개, 2번 음식을 4개, 3번 음식을 6개 준비했으며, 물을 편의상 0번 음식이라고 칭한다면, 두 선수는 1번 음식 1개, 2번 음식 2개, 3번 음식 3개씩을 먹게 되므로 음식의 배치는 "1223330333221"이 됩니다. 따라서 1번 음식 1개는 대회에 사용하지 못합니다.

수웅이가 준비한 음식의 양을 칼로리가 적은 순서대로 나타내는 정수 배열 food가 주어졌을 때, 대회를 위한 음식의 배치를 나타내는 문자열을 return 하는 solution 함수를 완성해주세요.

2. 제한 사항

  • 2 ≤ food의 길이 ≤ 9
  • 1 ≤ food의 각 원소 ≤ 1,000
  • food에는 칼로리가 적은 순서대로 음식의 양이 담겨 있습니다.
  • food[i]는 i번 음식의 수입니다.
  • food[0]은 수웅이가 준비한 물의 양이며, 항상 1입니다.
  • 정답의 길이가 3 이상인 경우만 입력으로 주어집니다.

3. 풀이

음식은 가운데 물을 두고, 이에 대칭되도록 칼로리가 적은 순서대로 음식을 배치되어야 한다. 양 선수가 동일한 양의 음식을 먹어야하기 때문에, 준비된 음식은 2의 배수가 아닐 경우 하나를 버려야한다. 출력은 String의 형태이기 때문에, "0"의 양쪽으로 칼로리가 높은 음식의 번호부터 추가해야한다.

결론적으로, 다음과 같이 진행했다.
1-1. 가장 칼로리가 높은(배열의 가장 마지막에 저장된) 음식을 선택한다.
1-2. 해당 음식의 수를 2로 나눈다.
1-3. 나눈 몫 만큼 "0"의 양 옆에 해당 음식의 번호(배열 내에서 순서)를 추가한다.
2-1. 다음으로 칼로리가 높은 음식을 선택한다.
2-2. 해당 음식의 수를 2로 나눈다.
2-3. 나눈 몫 만큼 "0"의 양 옆에 해당 음식의 번호(배열 내에서 순서)를 추가한다.
n-1~3. 가장 칼로리가 적은 음식(배열[1]에 저장된 음식)까지 위 과정을 반복한다.

4. 소스 코드

	// String answer의 양 옆에 음식의 번호를 추가
    public static String addnum(String answer, int count, int foodnum){
        for (int i = 0; i < count; i++) {
            answer = foodnum + answer + foodnum;
        }
        return answer;
    }
    // String answer 초기화, addnum()에 음식의 숫자 및 번호 적용
    public static String solution(int[] food){
        String answer = "0";
        for (int i = food.length-1 ; i > 0 ; i--){
            int count = food[i]/2;
            answer = addnum(answer, count, i);
        }
        return answer;
    }

II. Class

1. Constructor overloading(생성자 오버로딩)

외부에서 제공되는 다양한 데이터들을 이용해 객체를 초기화하기 위해서는 생성자도 다양화될 필요가 있다. Java는 다양한 방법으로 객체를 생성할 수 있도록 지원하는데, 이를 생성자 오버로딩이라고 한다.

1) 예시

아래는 field가 주어지는 여부에 따라 구분된 생성자들이다.

public class Car {
    // field
    String company;
    String model;
    String color;
    int maxSpeed;
    int speed;

    // constructor, Overloading
    Car() {

    }
    Car(String company) {
        this.company = company;
    }
    Car(String company, String model) {
        this.company = company;
        this.model = model;
    }
    Car(String company, String model, String color) {
        this.company = company;
        this.model = model;
        this.color = color;
    }
    Car(String company, String model, String color, int maxSpeed) {
        this.company = company;
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
}

2) 다른 생성자 호출 : this()

생성자 오버로딩이 많아질 경우, 생성자 간의 중복된 코드가 발생하게 된다. this() 메소드는 Class의 다른 생성자를 호출함으로써, 중복된 코드를 간결하게 개선할 수 있다.

public class Car {
    // field
    String company;
    String model;
    String color;
    int maxSpeed;
    int speed;

    // constructor, Overloading
    // constructor #1
    Car() {
        this("현대자동차", "그랜저", "회색", 250); 	// 2번 생성자 호출
    }
    
    // constructor #2
    Car(String company) {
        this(company, "그랜저", "회색", 250);		// 3번 생성자 호출
    }
    
    // constructor #3
    Car(String company, String model) {
        this(company, model, "회색", 250);		// 4번 생성자 호출
    }
    
    // constructor #4
    Car(String company, String model, String color) {
        this(company, model, color, 250);		// 5번 생성자 호출
    }
    
    // constructor #5
    Car(String company, String model, String color, int maxSpeed) {
        this.company = company;
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
}

2. method의 매개 변수를 모를 경우

일반적으로 메소드의 매개 변수는 그 숫자가 정해져있다. 하지만 특정 상황에서는 메소드의 매개 변수의 수를 알 수 없는 경우도 있다. 예를 들어, 여러 원소를 합산하는 메소드를 선언해야 한다면 몇 개의 변수가 입력될 지 알 수 없다. 이럴 땐, 매개 변수를 배열 타입으로 선언함으로써 해결할 수 있다.

int sum(int[] values){
	int result = 0;
    for (int i = 0; i < values.length ; i++){
    	result += values[i];
    }
    return result;
}

2. Method Overloading(메소드 오버로딩)

클래스 내에 같은 이름을 가진 메소드를 여러 개 선언하는 것. 메소드 오버로딩은 매개 변수의 ✔타입, ✔개수, ✔순서 중 하나가 달라져야 한다.

예를 들어 다음과 같은 메소드가 있다고 가정하자.

int plus(int x, int y){
	int result = x + y;
	return result;
}

동일한 로직으로 double의 값을 계산하고 리턴하는 메소드가 필요한 경우 굳이 다른 메소드를 선언할 필요 없이, 같은 이름으로 리턴 타입과 변수 타입만 변경해주면 된다.

double plus(double x, double y){
	double result = x + y;
	return result;
}

오버로딩된 메소드들은 JVM에 의해서 변수 값의 타입을 보고 적용된다.

1) JVM의 위대함(?)

위의 plus() 메소드를 다음과 같이 호출하여 사용한다고 가정하자.

int x = 10;
double y = 15.3;
plus(x, y)

int와 double로 매개 변수가 실행되기 때문에 컴파일 에러가 날 것 같지만, 위대한 JVM은 매개 변수의 타입 변환을 통해 오버로딩된 메소드들 중 적용 가능한 메소드가 있는지 검사한다.
때문에 위의 코드는 x를 double로 타입변환을 하고, 이후 double plus() 메소드가 적용된다.

III. Inheritance(상속)

1. Class Inheritance

Class 선언 시, 중복되는 코드를 줄이고 유지보수를 간편하게 하기 위해 상속을 선언할 수 있다. 선언 방법은 다음과 같다.

class [자식 Class] extends [부모 Class]{
	// field
    // constructor
    // method
}

1) 부모의 생성자 호출

1-1) 부모의 기본 생성자 호출

public [자식 Class]() {
	super();
}

1-2) 부모의 기본 생성자가 없는 경우

public class People {
	public String name;
    public String ssn;
    
    public People(String name, String ssn){
    	this.name = name;
        this.ssn = ssn;
    }
}        

위 People 클래스의 경우, 기본 생성자 없이 변수 2개(name, ssn)를 받아 생성된다. 이런 경우 People을 상속하는 클래스는 동일하게 2개의 변수(name, ssn)를 받을 수 있도록 구성해야 한다. 그 예시는 다음과 같다.

public class Student {
	public int studentNum;

    public Student(String name, String ssn, int studentNum){
    	this.name = name;
        this.ssn = ssn;
        this.studentNum = studentNum;
    }
}        

2) Method Overriding (메소드 오버라이딩)

상속받은 메소드가 자식 클래스에서 사용하기 힘든 상황이 있을 수 있다. Java는 이런 경우 메소드를 자식 클래스 내에서 간단하게 변경할 수 있는 기능을 제공한다.

2-1) Method Overriding의 규칙

  • 부모의 메소드와 동일한 시그니쳐(✔리턴 타입, ✔메소드 이름, ✔매개 변수 목록)를 가져야 한다.
  • 접근 제한을 더 강하게 정의할 수 없다.
  • 새로운 예외(Exception)을 throws 할 수 없다.

2-2) 예시

public class Calculator {
	double area Circle(double r){
    	return 3.14159 * r * r;
    }
}
public class Precise_Calculator extends Calculator{
	@Override
	double area Circle(double r){
    	return MATH.PI * r * r; 	//Math API 사용
    }
}

@Override : 컴파일러가 해당 메소드가 정확히 재정의된 것인지 확인

2-3) 부모 메소드 호출

자식 클래스의 내부에서 재정의된 부모 클래스의 메소드를 호출해야 하는 상황이 발생할 수도 있다. 이 때, super 키워드를 이용해 부모 메소드를 호출할 수 있다.

super.[메소드 이름]()		// 부모 메소드 호출

0개의 댓글