[항해99] 2회차 WIL - 3일을 고민한 알고리즘 해결과 함께

LIHA·2023년 1월 22일
0

항해99

목록 보기
20/54

이번 주차의 주된 고민 - 문풀 속도와 방법


문제풀이 방법과 수단에 대한 고민 - 혼자 앓으며 터득? 빠른 도움 받기?

2일차 과제를 아직까지 완성하지 못한 나. 혼자서 끙끙대고 고민해보려니 시간이 아주아주 오래 걸린다.

  • 관건은 '얼마나 걸리든 혼자 고민해서 답을 내볼 것인가', 아니면 '빨리 도움을 받아서 푸는 법을 익힐 것인가' 인듯 하다.
    ->주어진 시간이 많지 않으니, 20분 이상 고민해도 모르겠다면 일단 짜인 코드를 보고 도움을 받자.
  • 현재 사용중인 방법 - 내가 원하는 결과를 도출해낸 코드를 보고, 어떤 부분의 코드가 해당 기능을 나타내는지 고민중. 그러나 너무 혼자 해보려고 애쓰는 것이 문제라면 문제. 주어진 항해 시간을 생각하자. 수료때는 혼자 적절한 시간 안에 방법 찾아 해결할 수 있는 수준이어야 함.
  • 복붙은 할 수 없다 -> 나와 코드 구조가 다르기 때문에 어차피 작동하지 않음.

난수 문제 고민에 도움을 준 블로그1
도움을 준 블로그 2


조건문과 반복문


조건문을 쓸때는 - 그냥 if if if 보다는 else if를 써보자.

원빈 매니저님의 팁이기도 했던 else if 사용에 대하여.

if if if ~ 연속은 위의 if가 참이든 아니든 다음 if들이 실행된다.
하지만 else if로 이어지는 구문은 위의 if가 참이면 아래의 else if 들은 아예 실행되지 않는다.

스파르트랜짓 만들때 JS에 else if 구문을 계속 걸었던 것이 생각난다.
else if는 '아니면~' 이므로, 위의 조건문이 거짓일때만 아래로 내려오고 참이면 실행되고 끝난다.
그래서 회원가입 과정에서 공백 입력 방지용으로 사용했었다.

 if (signup_id.trim() == 0 || signup_id.trim() == null) {
            alert("아이디는 공백일 수 없습니다");
            $('#id').focus();
            return;
        }
        else if (signup_name.trim() == 0 || signup_name.trim() == null) {
            alert("이름은 공백일 수 없습니다");
            $('#name').focus();
            return;
        }
        else if (signup_pwd.trim() == 0 || signup_pwd.trim() == null) {
            alert("비밀번호는 공백일 수 없습니다");
            $('#passwd').focus();
            return;
  • 그리고 가능하면 else 문은 쓰지 말라는 조언을 들었던 것이 생각난다.
    이에 대해선 의견이 갈린다. switch문처럼 default를 설정해줘야 할 필요가 있다면 else도 필요하다는 것.
    그러나, 아래 코드에서 상단부 구조보단 하단부 구조가 낫다는 얘기가 대세인듯 하다.
 if (A) {
 return 1;
 } else {
 return 2;
 }
//여기까지 상단부

 if (A) {
 return 1;
 } 
 return 2;
 
 //여기까지 하단부
  • ESLint에 따르면, 핵심은 if블럭 안에서 return할 경우 else는 불필요하다고.
    ESLint 링크

for문 길이를 (배열).length - 1만 쓰는 것은 아니었다. length도 필요하다.

        int[] arr = {10, 20, 30, 40, 50};
        int sum = 0;
        int i;
        for (i = 0; i < arr.length ; i++) {
            sum += arr[i];
        }
        System.out.println(sum);

->얘는 arr 내의 모든 값을 다 더해서 결과에 찍어줘야 하는데, 후위연산자라서 length - 1만큼만 돌면 끝에서 두번째 값 까지만 찍히고, ++된 다음값은 sout에 찍히지 않는다.
그래서 모든 값을 다 찍어주려면 length-1이 아니라 그냥 length를 해야 한다.

변수 선언 위치가 바뀌니 별찍기도 실패 - 누가 별찍기를 쉽다고 했는가

        int i =0;
        while (i <= 10) {
            int j = 0;
            while (j <= i) {
                System.out.print("*");
                j++;
            }
            System.out.println();
            i++;
        }

이 코드는 일단 성공한 코드. 그러나 변수 위치 하나로 계속 실패했었다.
int j 를 int i 옆에 같이 선언하고 초기화했더니, 내부 while문이 j를 찾지 못했는지 j++; 가 반영되지 않았다. 계속 한개만 찍히고 끝.

  • 줄이 바뀌었는데도 * 갯수가 늘지 않았다는건 j++; 블럭을 빠져나가 i++; 블럭을 도는데도 j는 ++ 되지 않았다는 말이므로, j를 찾지 못해서 갯수반영이 안됐나보다 싶었다.

이 문제도 도저히 하다하다 안되겠어서 건호님이 같이 봐주셨는데, 건호님도 처음 보시는 현상이라며 원인 찾기에 시간이 꽤 걸렸다. JAVA는 역시 쉽지 않구먼. 🤔
나 QA 처음 했을때 생각했던, 아무것도 모르는 초짜가 얼마나 기상천외한 실수를 할 수 있는지가 새삼 떠올랐다.


배열


처음보는 2차원 배열. index를 여전히 틀리고 있는게 문제.

다음과 같은 배열이 있을 때, arr[3].length의 값은?
int[][]arr ={
    {5,5,5,5,5}, //index 0번
    {10,10,10}, //index 1
    {20,20,20,20}, //index 2
    {30,30} //index 3
};

여기서 아주 당연하게 4라고 썼는데 sout 해보니 2가 나왔다.
[i]와 i번째를 아직도 헷갈리고 있는 듯 하다.
i번째 배열의 j번째 요소를 찾으려면 row[i][j]라고 쓸테니, 약간 행렬식같은 느낌도 든다.

2차원 배열에서 row와 column 구하기

int[][] arr = {
	{1, 7, 2, 9, 4}
    {3, 1}
    {9, 7, 6}
	{5, 3, 6, 8}

row는 뭔데요? -> 내부배열 갯수. 저 한줄 한줄이 row다. 대충 곶감 꿰미라 생각하자.

  • row의 갯수 구하는 법 = arr.length -> 하면 4 나온다. 곶감 꿰미 몇줄? 4줄.
    i번째 row의 column 갯수 = arr[i].length 하면 된다. 0번 꿰미에 곶감 몇개? 5개.

-> 저 데이터들이 왜 column 속성인지 헷갈리면, 데이터가 에반게리온 엔트리 플러그처럼 천장에서 떨어져서 row에 세로로 퍽 박힌다고 생각하자.


객체지향


변수의 static과 함수의 static. 뭐가 다를까?🤔

  • static 붙은 변수 = 클래스 변수. 인스턴스 없이도 존재. 아무데서나 호출가능!
  • static 붙은 함수(메서드) = 객체의 생성 없이도 호출 가능. But 객체에서는 얘를 호출할 수 없다.
    또한, static 메서드 안에서는 static 변수에만 접근 가능하다. 인스턴스 변수는 호출 불가.

참고 - 변수와 함수의 static

함수와 메서드

메서드 = 클래스 내에 정의된 함수!

매개변수

메서드에서 괄호안에 받아오는 파라미터. 생성자도 오버로딩 시 매개변수를 받을 수 있다!

생성자 - 인스턴스를 초기화 해주기 위한 것!

아니 그래서 인스턴스가 대체 뭐냐고!?!?

<인스턴스>

  • 설계도(클래스)를 통해서 구현해야할 대상(객체)이 실제로 구현된 구체적인 실체
  • 실제로 메모리로 할당된 상태
  • 개념적으로 인스턴스는 객체와 같거나 객체에 포함된다고 봐도 틀린말이 아님

public class Phone {
	
	public String os;
	public Long memory;
	public Long pixel;
	public boolean is5GPossible;
	
	public void call(String number){
		...
	}
	
	public void takeAPicture() {
		...
	}
		...
}

public class Main {
  public static void main(String[] args) {
    Phone Galaxy20, IPhone11; // '객체'

    // 인스턴스화
    Galaxy20 = new Phone(); // Galaxy20은 Phone 클래스의 '인스턴스'
    // (객체를 메모리에 할당)
    IPhone11 = new Phone(); // IPhone11은 Phone 클래스의 '인스턴스'
    // (객체를 메모리에 할당)
  }
}
[출처] [Java] 클래스, 객체, 인스턴스 차이 구분|작성자 Devmin

그 외의 정보들.

Single responsibility (단일책임 원칙) - 하나의 클래스는 하나의 기능만, 그 클래스가 제공하는 모든 서비스도 하나의 기능을 수행하는데만.
Open close (개방 폐쇄 원칙) - 구성요소의 확장에는 열려있고, 변경에는 닫혀있어야 한다.
-> 즉, 기존 코드 수정없이 기능의 수정/추가가 가능해야 함. 이를 가능하게 하는건 추상화와 다형성.
Liskov substitution (리스코프 치환 원칙) - 서브타입은 언제나 기반타입으로 대체할 수 있어야 한다.
-> 상위타입 객체를 하위타입 객체로 치환해도, 상위타입을 사용하는 프로그램은 정상적으로 동작해야 한다는 것. 이 원칙이 지켜지지 않으면 개방 폐쇄 원칙 또한 자동으로 위반되는 것이다. 다형성이 지켜지지 않은 것이기 때문!
Interface segregation (인터페이스 분리 원칙) - 인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 잘게 분리되어야 한다.
-> 즉, 사용하지 않는 인터페이스는 변경되어도 클라이언트에 영향이 없어야 한다는 얘기.
Defendency inversion (의존 역전 원칙) - 구체화된 클래스보다는 추상 클래스나 인터페이스에 의존해야 한다.
-> 즉, 고수준 모듈이 저수준 모듈에 의존하면 안되고, 저수준 모듈이 고수준 모듈에서 정의된 추상 타입에 의존해야 한다는 얘기.
이는, 저수준 모듈이 변경되어도 고수준 모듈에는 영향이 없는 형태가 이상적이라는 것.

  • 맥에서 cmd + d 를 누르면 메모장이 두개가 되네. 난 맥이 아니지만 :/

  • 노드몬? nodemon. Node.js 쓸때 코드 수정시 자동 반영을 도와주는 툴. NODE 서버는 원래 코드 변경 확인하려면 서버를 껐다가 다시 켜야하기 때문에 이런게 필요하다.

profile
갑자기 왜 춤춰?

0개의 댓글