728x90

[문제링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 


 

import java.util.*;
class Solution {
    public int solution(int[] elements) {
        //중복 제거를 위해 set 사용
        Set<Integer> set = new HashSet<>();
        
        //원형구조 반영하여 수열의 합 구하기
        for(int i = 0 ; i < elements.length ; i++){
            int answer = 0;
            for(int j = 0 ; j < elements.length ; j++){
                answer += elements[(i+j)%elements.length];
                set.add(answer);
            }
            //System.out.println(set);
        }
        return set.size();
    }
}

[접근법]

  1. 수열의 합을 담을 set 을 생성한다.
    • 이때, 중복 제거를 위해 Set을 사용한다.
  2. 수열의 합을 구하기 위해 이중 포문을 활용하고,
  3. 원형 구조를 반영하기 위해 (인덱스를 초과하는 수를 처리하기 위해) (i+j)%elements.length 를 활용한다.
    • 인덱스가 초과해도 elements.length 안에서 인덱스를 처리할 수 있다.
  4. set에 수열의 합을 모두 저장하고 최종적으로 set의 크기를 반환한다. 

 


 

Set이란?

Collection 인터페이스를 기반으로 구현한 클래스로 비선형 자료를 구현한 클래스이다.

 

 

 

📍Set의 특징

  • 중복 값을 허용하지 ❌
  • 저장된 순서를 유지하지 ❌ 
    • 순서 유지⭕️ -> LinkedHashSet 클래스 이용
  • 빠른 검색이 필요할 때 사용하는 클래스

 

📍Set 사용법

  • 객체 생성
    Set은 인터페이스 이므로 구현체인 HashSet을 통해 객체를 생성한다.
Set<String> set = new HashSet<String>(); //String 타입 / 타입 지정 ⭕️
Set<Integer> set = new HashSet<>(); //타입을 생략하여 사용 ⭕️ -> 빈 HashSet생성 시 사용

 

  • 데이터 삽입   set.add()
Set<Integer> set = new Hashset<>();

set.add(1) //1 삽입
set.add(2) //2 삽입 

System.out.println(set); //set 출력

결과 : [1, 2]

 

  • 데이터 삭제   set.remove()
    삭제 1처럼 작성 시, 원소를 삭제하고 set을 반환한다. 
    삭제 2처럼 작성 시, 원소를 삭제하고 true를 반환한다. 만약, 없는 원소라면 false를 반환한다. 
//객체 생성
Set<Integer> set = new HashSet<>();
	// 데이터 삽입
        set.add(1);
        set.add(2);

	//데이터 삭제 1
        set.remove(2);
       	System.out.println(set);
        
 결과: [1]
        
        //데이터 삭제 2
        System.out.println(set.remove(4));
        
 결과: false

	//데이터 모두 삭제
        set.clear();

 

  • 특정 원소 존재 확인  set.contains()
    존재 ⭕️ : true   /   존재 ❌ : false
//객체 생성
Set<Integer> set = new HashSet<>();
	//데이터 삽입
        set.add(1);
        set.add(2);
        
	//원소 존재 확인
        System.out.println(set.contains(3));
        
결과: fasle //존재 ❌

 

  • set 빈 상태인지 확인  set.isEmpty()
    비었으면 true   /  원소 존재하면 false 반환
	//객체 생성
        Set<Integer> set = new HashSet<>();
        //데이터 삽입
        set.add(1);
        set.add(2);

        //set 비었는지 확인
        System.out.println(set.isEmpty());
        
 결과: false //[1,2]로 원소 존재

 

  • set의 크기 확인   set.size()
    set의 크기를 반환한다.
	//객체 생성
        Set<Integer> set = new HashSet<>();
        //데이터 삽입
        set.add(1);
        set.add(2);

        //set 크기 확인
        System.out.println(set.size());
   
 결과: 2

 

 


 

처음에 (i+j)%elements.length를 생각하기 전까지 꽤 많이 애를 먹었다.

이를 통해 원형 구조, 반복 수열 등을 많이 안다뤄본 것이 티가 난다고 생각했고,

문제해결력을 더 키우고 다양한 문제를 접해야겠다고 생각했다.

 

 

 

 

 

728x90
728x90

[문제링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 


 

 

class Solution
{
    public int solution(int n, int a, int b)
    {
        int cnt = 1;
        while((a+1)/2 != (b+1)/2){
            cnt++;
            //라운드에서 만났을 때
            if((a+1)/2 == (b+1)/2) break;
            //안만났을 때
            a = (a+1)/2;
            b = (b+1)/2;
        }
        return cnt;
    }
}

[접근법]

  1. 1라운드부터 시작하며, 반복문이 돌 때마다 라운드 수를 추가한다.
  2. 한 라운드 승리 후, (n+1)/2번으로 번호를 부여하므로 
    1. (a+1) / 2와 (b+1) / 2의 값이 같으면 라운드 수를 반환한다.
    2. 그렇지 않으면, a와 b의 값을 갱신하며 계속 비교한다.

 

 


오랜만에 간단한 문제인 것 같다.

728x90
728x90

[문제 링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

 


 

import java.util.*;
class Solution {
    public int[] solution(int n, String[] words) {
        //중복되지 않은 단어 저장 할 리스트
        ArrayList<String> wordlist = new ArrayList<>();
        //처음 시작
        wordlist.add(words[0]);

        for(int i = 1; i < words.length; i++){
            //중복 단어 찾기
            if(wordlist.contains(words[i])) {
                return new int[] {(i%n) + 1,(i/n) + 1};
            }
            else {wordlist.add(words[i]);}
            
            //틀린 끝말잇기 찾기
            if(words[i-1].charAt(words[i-1].length() - 1) != words[i].charAt(0)){
                return new int[] {(i%n) + 1,(i/n) + 1};       
            }
        }
        //탈락자 생기지 않는 경우
        return new int[] {0,0};
    }
}

[접근법]

  1. 중복되지 않은 단어를 저장 할 리스트(wordlist) 생성 후, 맨 처음 단어를 저장한다.
  2. 리스트에 단어가 포함되어 있는지 확인한다. 즉, 중복을 체크한다.
    • 중복되지 않으면, 리스트에 추가하여 계속 중복 체크를 한다.
    • 중복된다면, 결과를 반환한다.
  3. 이전 인덱스 단어의 마지막 글자와 현재 인덱스의 첫번 째 글자를 비교한다.
    • 같지 않다면, 규칙을 어긴 것이므로 결과를 반환한다.
  4. 2와 3번에 모두 걸리지 않다면, 탈락자가 없는 것이므로 [0,0]을 반환한다.
  5. 결과는 탈락자가 발생한 시점(i)을 인원 수(n)로 나누고,
    • 번호는 나머지 +1, 
    • 차례는 몫 +1 을 반환한다.

 


 

규칙을 잘 찾고,

charAt()에 대해 알고있다면 

쉽게 풀 수 있는 문제이다.

 

 

 

728x90
728x90

 

더보기

cs 면접 준비를 하며 공부했던 내용을 정리한 것입니다.

설명이 미흡할 수 있고, 순서가 뒤죽박죽인 점, 중복 개념이 있을 수 있는 점 양해 부탁드립니다🙂

 

✅  JAVA의 OOP(객체지향 프로그래밍) 원칙은 무엇인가요?

   

   OOP(Object-Oriented Programming)의 4대 원칙:

  1. 캡슐화 (Encapsulation) → 데이터 보호 및 정보 은닉 (getter/setter 활용)
  2. 상속 (Inheritance) → 코드 재사용성 증가 (extends, super 활용)
  3. 다형성 (Polymorphism) → 하나의 인터페이스로 다양한 구현 가능 (오버로딩/오버라이딩)
  4. 추상화 (Abstraction) → 중요한 정보만 노출, 불필요한 세부 사항 숨김 (interface, abstract class 활용)
더보기

✚ 

1. 캡슐화 ➡️ 객체가 맡은 역할 수행을 위한 하나의 목적을 위해 <데이터 + 기능> 묶는 것 / 외부에서 직접 접근하지 못하도록 제한 / 즉, 데이터 무결성 유지

2. 상속 ➡️ 부모 클래스 기능 -> 자식 클래스도 사용 ⭕️ / 유지보수 용이 / 재사용성 ⬆️

3. 다형성 ➡️ 하나의 객체가 여러가지 타입 가지는 것 / 하나의 기능 다양하게 사용⭕️

4. 추상화 ➡️ 객체들의 공통된 특징 (데이터 및 기능) 뽑아내는 것 / 중요한 속성 드러내고, 불필요한 내용 숨김

 

 

✅  JAVA의 객체지향 설계 원칙은 무엇인가요?

   

    SOLID 원칙:

  1. SRP(Single Responsibility Principle): 단일 책임 원칙
    • 모든 클래스(객체)는 단 하나의 책임만 가져야한다.
    • 즉, 하나의 클래스는 하나의 기능 담당하여 하나의 책임만 가지도록 클래스를 여러개 따로 설계하라는 것
  2. OCP(Open Closed Priciple): 개방 폐쇄 원칙
    • 확장에는 개방적이며, 수정에는 폐쇄적이야 한다.
    • 기능 추가 요청 시 클래스를 확장을 통해 손쉽게 구현하며, 확장에 따른 클래스 수정은 최소화한다.
    • 즉, 다형성과 확장 가능하게 함
  3. LSP(Listov Substitution Priciple): 리스코프 치환 원칙
    • 서브 타입은 언제나 기반(부모) 타입으로 교체할 수 있다.
    • 다형성의 특징을 이용하기 위해 상위 클래스 타입으로 객체를 선언하여 하위 클래스의 인스턴스를 받으면, 업캐스팅된 상태에서 부모의 메서드를 사용해도 동작이 의도대로 흘러가야 하는 것
    • 즉, 다형성 원리를 이용하기 위한 원칙 개념
  4. ISP(Interface Segregation Principle): 인터페이스 분리 원칙
    • 이용하지 않는 메소드에 의존하지 않아야 한다. (= 인터페이스 단일 책임)
    • 인터페이스를 사용하는 클라이언트를 기준으로 분리함으로써, 클라이언트의 목적과 용도에 적합한 인터페이스 만을 제공하는 것
  5. DIP(Dependency Inversion Principle): 의존 역전 원칙
    • 상위 클래스는 하위 클래스에 의존하지 않는다.
    • 의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것보다는, 변화하기 어려운 것 거의 변화가 없는 것에 의존하라는 것
    • 즉, 구현 클래스에 의존하지 말고, 인터페이스에 의존

 

 

 

✅  Java에서 final 키워드의 역할은?

  1. 변수에 사용 → 값 변경 불가 (final int x = 10;)
  2. 메서드에 사용 → 오버라이딩 불가 (final void method() {})
  3. 클래스에 사용 → 상속 불가 (final class MyClass {})

 

 

Spring MVC 구조와 동작 방식에 대해 설명해주세요.

 

    Spring MVC 구조:

  1. DispatcherServlet → 요청을 받아 컨트롤러로 전달
  2. Controller → 비즈니스 로직 처리 후 서비스 호출
  3. Service → 실제 로직을 처리 후 DAO에 전달
  4. DAO (Repository) → 데이터베이스와의 연결
  5. View (Thymeleaf, JSP 등) → 사용자에게 결과 반환

 

 

Spring Boot에서 DI(의존성 주입)와 IoC(제어의 역전)의 개념을 설명해주세요.

  • DI (Dependency Injection) → 객체 생성을 개발자가 직접 하지 않고, Spring이 자동으로 관리
  • IoC (Inversion of Control) → 객체의 생성과 생명주기를 컨테이너(Spring)가 관리

 

 

JPA와 MyBatis의 차이점은?

 

 

 

RESTful API란 무엇이며, 좋은 API 설계 원칙은?

  • RESTful API → 자원을 URL로 표현하고, HTTP 메서드(GET, POST, PUT, DELETE)를 활용하는 API 설계 방식
  • 좋은 API 설계 원칙 6가지:  
    1. URL 구조 설계에 맞게 동사 사용 ❌ / 리소스 나타내는 명사 ⭕️
    2. 리소스에 대한 행위는 HTTP 메서드로 올바르게 표현
    3. 슬래시 구분자(/)는 계층 관계를 나타내는데 사용
    4. URI 마지막 문자로 슬래시(/)를 포함 ❌
    5. 하이픈(-)은 URI 가독성을 높이는데 사용
    6. 언더바(_)는 URI에 사용 ❌
    7. URI 경로에는 소문자를 사용
    8. 파일 확장자는 URI에 포함

 

더보기

✚ REST 특징

  1. 일관된 인터페이스 규칙
  2. 클라이언트 - 서버 분리: REST 서버는 API 제공 / 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보) 등을 직접 관리하는 구조로 각각의 역할을 확실하게 구분 / 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로 간 의존성 ⬇️
  3. 무상태성 유지 : 이전 정보 저장 ❌ / 매 요청마다 필요 정보 포함 / ex) JWT 인증을 위에 헤더에 인증 토큰 ⭕️
  4. 캐싱 가능하게 설계
  5. 계층화된 시스템 구조: 다중 계층 구성 ⭕️ / 보안, 로드 밸런싱, 암호화 계층 추가해 구조 상의 유연성 ⭕️ / PROXY, 게이트웨이 같은 네트워크 기반의 중간 매체 사용 ⭕️
  6. Self-descriptiveness : REST API 메시지만 보고도 이를 쉽게 이해할 수 있는 자체 표현 구조
더보기

REST API

: HTTP 메소드를 사용해서 자원에 대한 CRUD 오퍼레이션 적용하는 것을 의미

 

 JAVA의 HashMap과 ConcurrentHashMap의 차이는 무엇인가요?

  • 단일 스레드 환경 ➡️ HashMap 사용 
  • 멀티스레드 환경 (웹 서버, 캐싱 등) ➡️ ConcurrentHashMap 사용

 

 

 String과 StringBuilder, StringBuffer의 차이점은?

  • 문자열 변경이 적은 경우 ➡️ String 사용
  • 성능이 중요한 경우 (단일 스레드) ➡️ StringBuilder 사용
  • 멀티스레드 환경 ➡️ StringBuffer 사용

 

더보기

  • String : 한 번 값이 할당 -> 공간 변하지 ❌ -> 불변객체
  • StringBuffer: 값 변경 ⭕️ / 동기화 지원 ⭕️ -> 멀티스레드 환경에서 사용
  • StringBuilder: 동기화 지원❌ -> 싱글 스레드 환경에서 사용

 

불변객체

  • 재할당 가능 
  • 한 번 할당 -> 내부 데이터 변경 ❌
  • 문자열 값 바꾸는 것 ❌ -> 보안 유리
  • 동기화 고려

 

 Spring에서 Bean이란 무엇이며, 싱글톤 패턴과의 관계는?

  • 스프링 컨테이너가 관리하는 객체
  • @Component, @Service, @Repository 등을 사용하면 자동으로 Bean으로 등록됨

🔹 싱글톤 패턴과의 관계

  • Spring의 기본 Bean 스코프는 싱글톤(Singleton)
  • 즉, 스프링 컨테이너가 한 개의 인스턴스를 생성하고, 여러 곳에서 재사용

 


 

-------- 데이터베이스 관련 ---------

 

MySQL과 MariaDB의 차이는?

  • MariaDB는 MySQL의 오픈소스 대체 버전
  • MySQL은 Oracle이 관리, MariaDB는 커뮤니티 중심
  • MariaDB가 성능 면에서 일부 개선됨

 

 

트랜잭션과 ACID 원칙이 무엇인가요?

  • 트랜잭션(Transaction): 데이터의 일관성을 보장하기 위한 작업 단위
  • ACID 원칙:
    1. Atomicity (원자성) ➡️ 트랜잭션이 모두 완전히 실행되거나, 전혀 수행되지 않음.
    2. Consistency (일관성) ➡️ 데이터베이스가 일관된 상태 유지 / 트랜잭션 수행 전과 후가 같음.
    3. Isolation (고립성) ➡️  동시 실행 시 다른 트랜잭션에 영향을 주지 않음.
    4. Durability (지속성) ➡️ 트랜잭션이 성공할 시, 영구적으로 반영됨.

 

 

Index란? 어떻게 작동하며, 언제 사용해야 하나요?

  • Index → 검색 속도를 향상시키는 데이터베이스 구조
  • 사용 시점: WHERE, JOIN, ORDER BY가 자주 사용될 때
  • 단점: 인덱스가 많아지면 INSERT/UPDATE 속도 저하

📌 즉, 자주 조회되는 데이터 & Join 연산 많은 테이블 & 검색 성능 높이고 싶은 컬럼에 적용

 

 

 

JOIN과 UNION의 차이점은?

JOIN은 두 개 이상의 테이블을 연결할 때 사용 / UNION은 같은 컬럼 구조의 데이터를 결합할 때 사용

성능 면에서는 JOIN이 일반적으로 더 효율적이며, UNION은 중복 제거를 위해 추가 연산이 필요할 수 있어 성능이 저하될 수 있음.

 

 

 

정규화는 무엇이며, 장점과 단점은?

🔹 정규화 (Normalization)란?

  • 데이터베이스 설계에서 데이터 중복을 최소화하고, 일관성을 유지하기 위한 과정
  • 데이터를 작은 논리적 단위로 분리하여 데이터 무결성을 보장

🔹 정규화의 단계 (1NF → 2NF → 3NF → BCNF)

  1. 제1정규형(1NF) → 중복된 열을 제거, 모든 컬럼이 원자값(Atomic Value)만 가지도록 함
  2. 제2정규형(2NF) → 부분 함수 종속 제거 (기본 키가 아닌 컬럼은 기본 키 전체에 종속)
  3. 제3정규형(3NF) → 이행적 함수 종속 제거 (A → B, B → C일 때 A → C 관계 제거)
  4. BCNF → 모든 결정자가 후보 키가 되도록 보장

🔹 정규화의 장점

⭕️ 데이터 중복 감소 → 저장 공간 절약
⭕️ 데이터 무결성 보장 → 데이터 변경 시 일관성을 유지
⭕️ 데이터 삽입/삭제 이상(Anomaly) 방지

 

🔹 정규화의 단점

JOIN 연산 증가 → 테이블이 세분화되면서 조인 성능 저하 가능
복잡성 증가 → 설계와 쿼리가 복잡해질 수 있음

 

 


 

JAVA: 객체지향 프로그래밍 언어  

특징

  1. JVM(자바 가상 머신) 위에서 동작하기 때문에 운영체제 독립적
  2. 가비지 콜렉터를 통한 메모리 관리 ⭕️
  3. 멀티스레드 지원
  4. 상속, 추상화, 캡슐화, 다형성 특징 ⭕️
더보기

  • 가비지 컬렉션 : 힙 메모리 관리를 위해 참조되고 있지 않은 객체들을 메모리에서 삭제하는 것
    (힙 영역: 객체 저장 / 스택 영역: 이를 가리키는 주소값 저장)
    => 힙 영역에서 자신들 가르키는 주소값이 없으면 참조하지 않은 것으로 판단 => 삭제ㄷ

 

 

생성자: 클래스와 같은 이름의 메소드로 객체가 생성도리 때 호출되는 메소드

  • static
    : 클래스가 로딩될 때 메모리 공간 할당 ⭕️ -> 처음 설정된 메모리 공간이 변하지 ❌  -> 인스턴스 생성없이 바로 사용 ⭕️ -> 공통으로 사용되는 데이터 관리할 때 사용함
  • final
    : 한 번 초기화되면 그 이후 변경 ❌ => 한 번만 할당하고 싶을 때 사용함

 

 

멀티 프로세스와 멀티 스레드 차이점

  • 멀티 프로세스
    📍장점: 하나의 프로세스가 죽어도 다른 프로세스에 영향 끼치지 ❌ (리소스 공유) 
    📍단점: 멀티 스레드보다 많은 메모리 공간과 시간 차지 ⭕️
  • 멀티 스레드
    📍장점: 멀티 프로세스보다 적은 공간 및 시간 차지 ⭕️
    📍단점: 교착 상태에 빠지거나 동기화의 문제 ⭕️

 

 

교착상태 (데드락) : 하나 또는 그 이상의 프로세스나 스레드가 서로 자원을 기다리면서 무한히 기다리게 되는 상태

 

4가지 필요조건

  1. 상호배제 : 한 자원에 대한 여러 프로세스가 동시 접근 ❌
  2. 점유와 대기: 하나의 자원을 소유한 상태에서 다른 자원에 대한 접근 권한을 요구하는 것
  3. 비선점: 다른 프로세스에서 자원을 사용하는 동안 자원을 강제로 가져올 수 ❌
  4. 환형대기: 각 프로세스가 다른 프로세스가 요구하는 자원 가지고 있는 상태

상호배제 / 점유와 대기 / 환형 대기

 

 

 

해결법

  1. 예방
  2. 회피
  3. 탐지
  4. 복구 : 프로세스 중지, 자원 선점 하는 것
더보기

✚ 기아상태 : 영원히 자원 할당 ❌ 
    해결 : 우선순위 변경 또는 큐 활용

 

 

동기화와 비동기화 차이

  • 동기화 
    : 하나의 자원을 여러 데스크가 사용하려 할 때, 한 시점에서 하나의 테스크만이 사용될 수 있게 하는 것.
    (작업 -> 순차적으로 진행 ⭕️ / 다음 작업 -> 이전 작업의 완료를 기다림)
  • 비동기화
    : 한 작업이 시작되면 다른 작업이 완료되지 않아도 기다리지 않고 다음 작업 진행
    ex) UI 이벤트 처리, 파일 다운

 

✅ 오버로딩과 오버라이딩 차이

  • 오버로딩
    : 같은 클래스 내에서 메소드 이름은 같지만, 매개변수의 개수나 데이터 형식을 다르게 정의하는 것.
  • 오버라이딩
    : 부모 클래스 메소드가 자식 클래스에서 재정의 되는 것  (-> 매개변수 개수 & 데이터 형식 같아야 함)

 

 

 

✅ DAO와 DTO 차이

  • DAO
    : DB의 데이터에 접근하기 위한 객체 / DB에 접근하기 위한 로직과 비즈니스 로직 분리하기 위해 사용 ⭕️
  • DTO
    : 각 계층간의 데이터 교환하기 위한 JAVA Bean을 말함 / 프로젝트 시 엔터티에서 필요한 데이터만 추출하기 위해 사용 ⭕️

 

 

 

✅ 접근제한자

: 변수 또는 메소드의 접근 범위 설정을 하기 위함

 

  • Public : 제한 ❌
  • Private: 같은 클래스 내 허용⭕️
  • Protected: 같은 패지키 내 허용 ⭕️ / 다른 패키지 자손 클래스에서 접근 ⭕️
  • default: 같은 패키지 내에서 허용 ⭕️

 

 

✅ 값에 의한 호출과 참조에 의한 호출 차이

  • 값에 의한 호출
    : 인자로 받은 값 복사하여 처리 
    📍장점: 복사하여 처리 -> 원본 값 변경 ❌ -> 안전
    📍단점: 복사 -> 메모리 사용량 ⬆️
  • 참조에 의한 호출
    :
    인자로 값은 값의 주소 참조해서 전달

    📍장점: 복사 ❌ -> 직접 참조 -> 빠름
    📍단점:
    직접 참조 -> 원본 값 영향 ⭕️

 

 

✅ Error과 Exception 차이

  • Error
    : 실행 중 일어날 수 있는 치명적 오류로 발생 -> 비정상적 종료 ⭕️
  • Exception
    : Error 보다 경미한 오류 / try - catch를 이용해 비정상적 종료 막을 수 있음 -> 비정상적 종료 ❌

 

 

✅ RuntimeException과 Exception 차이

  • RuntimeException
    : 예외 처리 ❌ / 프로그래머 실수
  • Exception
    : 반드시 예외 처리 ⭕️  / 외부 영향

 

 

✅ throw와 throws 차이

  • throw
    : 강제로 예외 발생 / 개발자 판단으로 처리 ⭕️ / 상위 블럭이나 catch문으로 예외 던짐
  • throws
    : 자신 호출하는 메소드에 예의 처리 책임 떠넘기는 것 / 상위메서드로 예외를 던짐

 

 

✅ 추상클래스와 인터페이스 (➡️ 추상적인 설계 정의하는 데 사용)

  • 추상클래스
    : 일부 메서드 구현되어 있고, 일부는 추상 메서드 / 생성자 ⭕️ / 단일 상속만 ⭕️
    is-a 관계일 때 사용 / 주로 공통된 기능 제공하는 부모 클래스 역할
    💡공통 기능 정의 & 상속 통해 재사용 할 때 사용

  • 인터페이스
    : 기능을 정의하는 추상적 개념 / 구현된 메서드 포함 ❌ / 다중 구현 ⭕️ (= can-do 관계) 
    변수 public, static, final 상수만 선언 ⭕️
    💡다양한 클래스에서 동일한 기능을 구현해야 할 때 사용

 

 

✅ MVC 패턴

  • Model : 동작 수행   ex) @Service, @Repository(db table)
  • View : 모델로부터 값 가져와 사용자에게 보여줌
  • Controller: 사용자 요청에 맞는 데이터를 모델에 요청, 데이터를 뷰에 반영 ➡️ 어떻게 모델이 처리할지 정의

📍장점 : 유연 & 확장 쉬움 / 동시 다발적 개발 가능 ⭕️

📍단점 : 모델과 뷰 사이 의존성 ⬆️ / 설계 단계에 클래스 수 ⬆️ 

 

 

 

✅ JSP (Java Server Pages)

: HTML 내부에 자바 코드를 삽입하여 동적 웹 페이지를 생성하는 웹애플리케이션 도구

 

  • JSP 가 실행되면 자바 서블릿(Servlet) 으로 변환되며 웹 어플리케이션 서버에서 동작되면서 필요한 기능을 수행하고 그렇게 생성된 데이터를 웹페이지와 함께 클라이언트로 응답한다.
    • JSP
      : HTML 내부에 JAVA 소스코드가 들어감으로 인해 HTML 코드를 작성하기 간편 ⭕️
    • 서블릿
      : HTML 코드가 있어서 읽고 쓰기가 굉장히 불편하므로 작업 효율성 ⬇️

더 자세하고 설명이 잘 되어 있는 블로그 링크 첨부 

 

 

 

✅ final 변수, 메서드, 클래스 차이

  • final 변수 : 값 변경없는 상수 / 한 번 초기화되면 변경 ❌
  • final 메서드 : 오버라이딩 불가능한 메서드 (자식 클래스에서 변경 ❌)
  • final 클래스 : 상속할 수 없는 클래스 ( 자식 클래스를 만들 수 ❌)
더보기

오버라이딩
: 부모 클래스 메서드 자식 클래스에서 재정의 ⭕️ / 매개변수 개수 & 데이터 형식 같아야 함

 

 

 

✅ Stack과 Heap 비교

-  자바에서 메모리는 크게 Stack(정적 메모리)과 Heap(동적 메모리) 영역으로 나뉨 

-  다른 방식으로 데이터 저장하고 관리함 

 

  •  Stack
    • LIFO (Last In First Out)
    • 메모리 높은 주소 ➡️ 낮은 주소 방향으로 할당 
    • 지역 변수 & 함수 호출 정보(메서드 실행 정보) 저장
    • 메서드 종료 시 자동 해제 ( = 할당 해제 할 필요 ❌)
    • 빠른 접근 속도 ( = 빠른 액세스 = 할당 & 해제 빠름)
    • 메모리 크기 제한 ⭕️
  • Heap
    • 동적으로 객체 생성
    • 메모리 낮은 주소 ➡️ 높은 주소 방향으로 할당
    • 객체 & 인스턴스 변수 저장
    • 전역변수 다룸
    • GC(가비지 콜렉터): 더이상 사용되지 않는 객체 탐색하여 자동으로 메모리 정리하는 기능
    • 프로그램 종료까지 유지 -> 자동으로 해제 되지 않음 -> 사용자가 메모리 관리 해야 함 (변수 할당 & 해제 책임 ⭕️)
    • 상대적으로 접근 속도 느림 ( 할당, 해제 느림)
    • 운영체제마다 메모리 관리다 달라서 어려움
더보기

✚  Stack [LIFO] ↔️ Queue [FIFO]

 -------------------------------------

장점 / 단점

 

 

 

✅ List, Set, Map 비교

  • List : 순서있는 데이터 저장 / 중복 허용 ⭕️
  • Set : 중복 허용 ❌ / 순서 ❌
  • Map : 키 - 값 쌍으로 저장 / 키 중복 ❌

 

✅ ArrayList, LinkedList 비교

  • ArrayList : 동적 배열 기반 리스트
    • 검색속도 ⬆️ (인덱스 사용) / 중간 삽입 & 삭제 시 성능 저하 발생 (요소들을 이동시켜야 하므로)
      💡데이터 접근 빈번 & 삽입, 삭제가 상대적으로 적은 경우 적합
  • LinkedList : 이중 연결 리스트 기반 리스트
    • 요소가 이전 요소 가리키는 포인터 포함 / 중간 삽입 & 삭제 빠름 (링크만 조정하면 됨) / 검색 속도 ⬇️ (링크를 따라가야 하므로)
      💡데이터 삽입, 삭제 빈번 & 데이터 순서가 자주 변경되는 경우 적합

 

 

728x90
728x90

[문제 링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr


import java.util.*;
class Solution {
    public int solution(int[] arr) {
        int answer = 1;
        int num = 2;
        
        Arrays.sort(arr);
        int max = arr[arr.length -1];
        
        if(max == 1) return max;
        while (max >= num) {
            boolean bool = false;
            
            for(int i = 0; i < arr.length; i++){
                if(arr[i]%num == 0){
                    arr[i] = arr[i]/num;
                    bool = true;
                }
            }
            if(bool) answer *= num;
            else num++;
        }
        
        for(int i = 0; i < arr.length; i++){
            answer *= arr[i];
        }
        return answer;
    }
}

[접근법]

  1. arr 배열을 정렬하여 가장 큰 값을 max로 지정한다.
  2. max의 값이 1이면 모든 값이 1이므로 max를 반환한다.
  3. 그 외의 수는 소인수를 구하는 방식을 이용하여 나머지가 0인 값을 구하고 몫으로 배열의 값을 업데이트한다
  4. 이후 나머지가 0이 되는 num 값을 answer에 곱한다. 
    • 이때, bool 값을 사용하여 모두 나머지가 0인 값이 없을 때, num 값을 ++하기 위함이다.
  5. max 값까지 반복한 후, 업데이트한 값의 arr 배열의 값들을 answer에 곱한다. 

 


 

최소 공배수를 구하는 방법은 여러가지 있으나, 

가장 기본적인 방법인 공약수와 서로소를 곱하는 방법을 사용했다.

 

bool을 사용하는 방법을 생각하지 못했다면

코드가 지저분하고 효율성이 떨어졌을 것 같다.

 

하지만, 최대 공약수를 구하는 gcd()라는 함수와 

gcd() 함수를 이용하여 최소 공배수를 구하는 lcm() 함수를 사용했으면

훨씬 간단하고, 빠르게 구현했을 것 같다.

728x90
728x90

[문제 링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 


 

class Solution {
    public long solution(int n) {
        int[] dp = new int[n+2];
        dp[1] = 1;
        dp[2] = 2;
        
        for(int i = 3; i <= n; i++){
            dp[i] = (dp[i - 1] + dp[i - 2]) % 1234567;
        }

        return dp[n];
    }
}

 

[접근법]

  1. dp 배열을 생성하여 1과 2값을 저장한다.
    • 이는 1칸은 한 가지, 2칸은 두 가지의 경우의 수만 존재하고, 이 수를 이용할 것이기 때문이다. (1) / (1,1) (2)
  2. 반복문을 사용하여 피보나치 수열을 계산하고 그 값에 1234567을 나눈 나머지를 해당 dp 인덱스에 저장한다.
  3. n만큼 반복하고 dp[n]의 값 반환한다.

 


Dynamic Programming(동적 계획법)이란,
하나의 큰 문제를 여러 개의 작은 문제로 나누어 그 결과를 저장하여 다시 큰 문제를 해결할 때 사용하는 것이다.
즉, 재사용성이 뛰어나 시간 복잡도가 재귀함수보다 효율적인 알고리즘이다.

위 그림을 보면 이해가 더 빠를 것이다.

멀리 뛰기의 경우, 1칸과 2칸만을 이용하므로 f(1) = 1, f(2) = 2로 저장했다. 

f(3) = f(2) + f(1) 이다.

즉, 2+1 = 3 이다.

f(4) = f(3) + f(2) 이다.

즉, 3+2 = 5 이다.

 

이런 식으로, 이전에 미리 계산했던 값을 재사용하여

다음의 수를 계산하는 방법이 DP이다.


 

처음엔 조합을 이용하여 해결하려 했지만, 오버플로우가 발생하여 해결하지 못했다.

이후, 피보나치 방법을 반복문으로 코드를 짜는 도중에

동적계획법을 사용해서 푸는 것이 더 코드가 간결하고

반복문 외에 다른 알고리즘법을 익숙하게 하고자 동적계획법으로 바꿔서 코드를 짰다.

그 결과, 훨씬 깔끔하고 간결하게 작성하여 통과했다.

728x90
728x90

[문제링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Solution {
    public int solution(int k, int[] tangerine) {
        int answer = 0;
        int cnt = 0;
        
        List<Integer> intList = new ArrayList<>();
        int[] count = new int[10000001];
        
        //귤 크기별 갯수 세기
        for(int i = 0; i < tangerine.length; i++){
            count[tangerine[i]]++; 
        }
        
        //갯수 배열 생성
        for(int i = 0; i < count.length; i++){
            if(count[i] > 0) {
                intList.add(count[i]);
            }
        }
        
        //최솟값 찾기
        intList.sort(Collections.reverseOrder());
        for (int i = 0; i < intList.size(); i++) {
            cnt += intList.get(i);
            answer++;
            if (cnt >= k) {
                break;
            }
        }
        return answer;
    }
    
}

접근법

  1. 귤의 크기별로 갯수를 센다.
  2. 갯수만 저장한 배열을 생성한다.
  3. 갯수 배열을 내림차순으로 정렬하여 서로 다른 귤의 수를 최소화하여 반환한다.

 


 

import java.util.*;
class Solution {
    public int solution(int k, int[] tangerine) {
        int answer = 0;
        int[] count = new int[tangerine.length];
        int cnt = 0;
        
        for(int i = 0; i < tangerine.length; i++){
            for(int j = 0; j < tangerine.length; j++) {
                if(tangerine[j] == i+1) {
                    cnt++;
                }
            }
            count[i] = cnt;
            cnt = 0;
        }
        
        Arrays.sort(count);
        for(int i = count.length -1; i >= 0; i--){
            if(k <= count[i]) {
                answer++;
                break;
            }
            
            else if(k > count[i]){
                k = k-count[i];
                answer++;
            }
        } 
        return answer;
    }
}

 

처음엔 위와 같이 단순하게 짰으나

효율성 문제로 통과하지 못했다.

int 배열을 list로 변환하여 작성하는 것이 코드도 간결해지고,

데이터를 넣고, 읽고, 가져오고, 역순 정렬하기도 편하다는 것을 깨달았다.

 

728x90
728x90

[문제링크]

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 


import java.util.*;

public class Solution {
    public int solution(int n) {
        int ans = 0;

        while(n > 0) {
            if(n % 2 == 1){
                ans++;
            }
            n = n/2;
        }

        return ans;
    }
}

접근법

  1. n을 2로 나눈 나머지가 1일 때 점프를 한다. (즉, ans = 점프한 수)
  2. 그 다음 n을 2로 나눈다.
  3. n이 0이 될 때까지 반복하고, ans 값 (점프한 수)를 리턴한다.

 


 

문제가 너무 길어서 당황했으나,

3개의 경우의 수를 보여주는 부분에서 사실상 정답을 알려주었다.

 

문제를 풀고 다른 사람의 풀이를 보았을 때, 

적잖이 충격을 먹었다...

이 문제는 비트카운트를 하는 문제였다🫢

 

 

 

728x90

+ Recent posts