코딩테스트/코딩 테스트 합격자 되기 : 자바편

[코딩 테스트 합격자 되기 : 자바 편] 4. 코딩 테스트 Java 필수 문법

yujinius 2024. 5. 31. 14:41

 

<프리미티브 타입과 레퍼런스 타입>

프리미티브 타입(Primitive type)

  • int, long, float, double 등

레퍼런스 타입(Reference type)

  • Integer, Long, Float, Double 등
★ 기억하기
: 레퍼런스 타입은 참조형 변수이므로 프리미티브 타입보다 연산 속도가 더 느립니다.

 

정수형

  • 나누기, 모듈러 연산 모두 소수점 버림

부동소수형

System.out.println(10.0 % 3.2) // 모듈러 / 0.39999999999~47
  • 10.0 % 3.2 의 결과값이 0.4가 아니라 0.3999999~47

 

앱실론을 포함한 연산에 주의하기

  • 위와 같은 결과의 원인: 자바는 부동소수형 데이터를 이진법으로 표현하기 때문 ⇒ 표현 과정에서 오차 발생 ⇒ 이를 앱실론(epsilon)이라고 함.
  • 코테 부동소수형 데이터 다룰 때 앱실론 항상 생각하기
  • 앱실론 때문에 0.3을 3번 더한 a의 값에서 0.3을 빼면 0이 아님!!

관련 포스팅 글 참고▼

[Java] 자바에서 앱실론(Epsilon)과 부동소수점 오차 검사

 

[Java] 자바에서 앱실론(Epsilon)과 부동소수점 오차 검사

부동소수점(Floating-Point) 수는 컴퓨터에서 실수를 표현하는 방식 중 하나입니다. 그러나 부동소수점은 근본적으로 정확하지 않기 때문에 미세한 오차가 발생할 수 있습니다. 이로 인해 두 부동소

yujinius45.tistory.com

 

  • 부동소수형 데이터를 활용하는 문제는 오차 허용 범위를 언급하는 경우가 많으니 꼭 체크하기
public class EpsilonExample {
    public static void main(String[] args) {
        double a = 0.1 + 0.2;
        double b = 0.3;
        double epsilon = 1e-10; // 10의 -10승, 아주 작은 값
				// ==로 비교하면 다른값으로 나옴 아래와 같이 비교하기
        if (Math.abs(a - b) < epsilon) {
            System.out.println("a와 b는 같은 값으로 간주됩니다."); // 이 코드가 출력됨
        } else {
            System.out.println("a와 b는 다른 값입니다.");
        }
    }
}

 

<컬렉션 프레임워크>

컬렉션 프레임워크란?

  • 여러 개의 값을 저장하고 그 값을 쉬우면서 효율적으로 처리해주는 표준화 클래스의 집합
  • 대표적 컬렉션 프레임워크: 리스트 ArrayList, 스택 Stack, 큐 Queue, 데크 ArrayDeque, 해시맵 HashMap 등이 있음

배열

  • Arrays 클래스의 toString() 메서드 사용해 배열 요소 쉽게 출력하여 디버깅
System.out.println(Arrays.toString(array)); // [1,2,3]

배열의 인덱스

  • 배열은 생성 후 크기 변경 불가
  • 배열 생성 후 새 데이터 삽입, 삭제 불가, 기존 데이터만 변경 가능
  • 인덱스를 이용한 배열 요소에 대한 접근, 변경 시간 복잡도는 O(1)

리스트

  • 코테 기준으로 ArrayList 
  배열 리스트
크기 고정 가변
삽입, 삭제 불가능 가능
  • ArrayList 맨 뒤 새 데이터 추가 평균 시간 복잡도 O(1)
  • 기존 데이터의 삭제, 중간에 데이터 삽입할 때 시간 복잡도 O(N)까지 커질 수 있음
// 리스트 객체 생성
ArrayList<Integer> list = new ArrayList<>();
// 값 추가
list.add(1);
list.add(2);
list.add(4);

System.out.println(list.get(2)); // 4, 인덱스로 값 접근
System.out.println(list); // [1, 2, 4]

 

    • 리스트 출력은 바로 해도 됨! 배열에서는 Arrays.toString(arr) 썼는데

 

해시맵 hashmap

  • key - value 쌍을 저장하는 해시 테이블로 구성
  • 키를 사용하여 값을 검색하는 자료구조

해시맵 초기화

HashMap<String, Integer> map = new HashMap<>();

해시맵의 데이터 삽입과 출력

map.put("apple", 1);
map.put("banana", 2);
map.put("oragne", 3);
// 해시값 출력
System.out.println(map); // {banana=2, orange=3, apple=1}

해시맵의 데이터 검색

String key = "apple";

if(map.containsKey(key)){
	int value = map.get(key);
	System.out.println(key + ": " + value); // apple :1
}else{
	// 키가 없는 경우 예외가 발생하므로 예외처리를 해줘얗 ㅏㅁ
	System.out.println(key +"는 해시맵에 없음");
}
  • 참고: 자바에는 해시맵과 유사하지만 키-쌍 저장 말고 값 없이 키만 저장하는 해시셋도 있음

 

문자열

  • 문자열은 문자들을 배열의 형태로 구성한 이뮤터블 객체

문자열 초기화

  • 자바에서 문자열은 이뮤터블 객체
  • 이뮤터블 객체: 값을 변경할 수 없는 객체 의미
  • 시간 복잡도 관점에서 이뮤터블 객체 사용은 주의해야 함
String str = "hello";

 

💡 기억하기!!!!
문자열은 문자들을 배열의 형태로 구성한 이뮤터블 객체
- 이뮤터블 객체: 값을 변경할 수 없는 객체 의미
- 시간 복잡도 관점에서 이뮤터블 객체 사용은 주의해야 함

 

문자열 추가, 삭제

  • 문자열은 Immutable 객체이므로 기존 객체를 수정하는 것이 아닌 새로운 객체를 반환함
  • 문자열 길이 N일 때 O(N)이 됨
String string = "He";
string += "llo";
System.out.println(string); // Hello

문자열 수정

string.replace("수정할 것", "수정되어 들어갈 것");

 

StringBuffer & StringBuilder

  • StringBuffer, StringBuilder 클래스는 뮤터블하므로 값을 변경할 때 시간복잡도 더 효율적
long start = System.currentTimeMillis();

StringBuilder s = new StringBuilder();
for(int i = 1; i <=10000; i++){
	s.append(i);
}

long end = System.currentTimeMillis();

System.out.println(((end - start) / 1000.0)+"초");
  • String으로 수행했다면 O(N^2)
  • String 값을 변경하는 연산이 많을 때는 효율이 높은 StringBuilder, StringBuffer 사용
  • 두 클래스의 차이는 멀티 스레드 환경에서 Thread-Safe 여부로 나눔
  • 코테에서는 다수의 스레드 생성 필요 x ⇒ Thread-Safe가 없는 StringBuilder 클래스가 속도 측면에서 미세하지만 더 빠르므로 StringBuilder 사용하기
  • Thread-Safe한 클래스는 동기화를 통해 데이터의 일관성을 유지합니다.   
    특성 String StringBuffer StringBuilder
    Immutable 아니요 아니요
    Thread-Safe 아니요
    성능 상대적으로 느림 상대적으로 빠름 가장 빠름

 

StringBuilder 클래스의 활용 방법 ★

  • String 값을 변경하는 연산이 많을 때는 시간 초과가 발생하지 않도록 꼭 String 대신 StringBuilder 사용하기!
// StringBuilder 객체 생성
StirngBuilder sb = new StringBuilder();

// 문자열 Add
sb.append(10);
sb.append("ABC");

// 출력
System.out.println(sb); // 10ABC
sb.deleteCharAt(3); // 3번째 인덱스 문자 제거 
System.out.println(sb); // 10AC
sb.insert(1, 2); // 1번째 인덱스에 2라는 문자 추가
System.out.println(sb); // 120AC

 

<메서드>

메서드 정의

public int fun_name(int param1, int param2){
	// 실행 코드
	return result; // 반환값
}

메서드 호출

public static void main(String[] args){
	int ret = add(2, 3);
}

 

<람다식>

  • 람다식(lambda expression)은 자바 1.8버전에서 추가됨
  • 람다식은 다른 말로 익명 함수(anonymous function)이라고도 함
  • 익명 함수란?
    • 이름이 없는 함수
    • 코드에서 딱 한 번 실행할 목적으로 사용하거나 함수 자체를 다른 함수의 인수로 전달할 때 사용

람다식의 정의와 사용

private static class Node{
	int dest, cost;
	
	public Node(int dest, int cost){
		this.dest = dest;
		this.cost = cost;
		}
}

public static void main(String[] args){
	Node[] nodes = new Node[5];
	node[0] = new Node(1, 10);
	node[1] = new Node(2, 20);
	node[2] = new Node(3, 15);
	node[3] = new Node(4, 5);
	node[4] = new Node(5, 25);
	
	Arrays.sort(nodes, (o1, o2) -> Integer.compare(o1.cost, o2.cost)); // ①
	
	Arrays.sort(nodes, new Comparator<Node>(){
		@Override
		public int compare(Node o1, Node o2){
			return Integer.compare(o1.cost, o2.cost);
		}
	}); // ②
}
  • 위 코드에서 ①, ② 동일 로직 수행, 정렬 API 사용할 때 좋음

 

Integer.compare(int x, int y) 메서드

  • x < y 면 -1 반환
  • x > y 면 1 반환
  • x == y면 0 반환
  • 간혹 정렬 조건 구현시 [x-y]와 같이 뺄셈하는 경우 오버플로우 위험이 있으므로 compare()메서드 사용이 좋음

 

<코딩 테스트 코드 구현 노하우>

조기 반환 early return

  • 코드 실행 과정이 함수 끝까지 도달 전 반환하는 기법
  • 가독성 up, 예외 처리 good, 깔끔

보호 구문 guard clauses

  • 로직 진행하기 전 예외 처리 코드를 추가하는 기법
  • 조건문을 이용해 초기 입력값이 유효한지 검사하고 그렇지 않으면 바로 함수 종료하는 보호 구문 쓸 수 있음
import java.util.List;

static double calculateAverage(List<Integer> numbers){
	if(numbers == null){
		return 0; // null이면 종료
	}
	if(numbers.isEmpty()){
		return 0; // 데이터 없으면 종료
	}
	
	int total = numbers.stream().mapToInt(i->i).sum(); //예외처리 후 기능 구현
	return (double) total / numbers.size();
}

제네릭 generic

  • 빌드 레벨에서 타입 체크를 하여 타입 안정성을 제공
  • 타입 체크와 형변환을 생략할 수 있게 해주어 코드를 간결하게 만들어주는 기능
List list = new ArrayList()
list.add(10);
list.add("abc");

int sum1 = (int) list.get(0) + (int) list.get(1); // 런타임 오류 

List<Integer> genericList = new ArrayList<>();
// ▲ 리스트 정의할 때 타입 강제하는 것이 제네릭
// 제네릭은 타입에 맞지 않는 데이터 추가할 때 문법 오류를 발생시킴
genericList.add(10);
genericList.add("abc"); // 문법(빌드 레벨) 오류 발생

int sum2 = genericList.get(0) + genericList.get(1);
  • 제네릭으로 작성했는데 문제가 있으면 빌드 자체가 안되므로 런타임 버그 방지 가능
  • 또한, 데이터 접근하여 사용할 때 형변환 할 필요 없어 코드 간결해짐

💡 코테에서는 여러 타입의 데이터를 하나의 컬렉션에 넣어야 하는 경우는 거의 없으므로 제네릭 타입을 강제하여 실수를 방지하는 것이 좋음

 

기억하기

  1. 자바의 데이터 타입에는 프리미티브 타입과 레퍼런스 타입이 있다. 프리미티브 타입의 연산 속도가 레퍼런스 타입에 비해 더 빠르기 때문에 가능함녀 프리미티브 타입 사용하는 것이 좋다.
  2. 자바의 컬렉션 프레임워크의 리스트, 해시맵은 코딩 테스트에서 자주 사용하므로 꼭 알아두면 좋다.
  3. 자바에서 String 클래스의 객체는 Immutable 객체이다. 값을 변경할 수 없기 때문에 + 연산 등으로 값을 변경할 경우 효율이 좋지 않다. String의 + 연산이 자주 발생한다면 StringBuilder를 사용하자.
  4. 메서드는 길어질 수 있는 코드를 논리적으로 분리할 수 있게 해준다. 잘 활용하면 코드의 중복을 줄이고 가독성을 높일 수 있다.
  5. 조기 반환, 보호 구문, 제네릭 등의 기법을 활요하면 코드의 가독성과 효율성을 높일 수 있다.

 

 

 


해당 글은 다음 책을 참고하여 공부하며 정리한 글입니다. 

https://ebook-product.kyobobook.co.kr/dig/epd/ebook/E000006973689

 

코딩 테스트 합격자 되기: 자바 편 | 김희성 | 골든래빗(주)- 교보ebook

자료구조, 알고리즘, 빈출 97 문제로 대비하는 코테 풀 패키지(모의고사, 엄친아 손노트, 온라인 학습 지원 제공) , ★ 빈출문제 97개면 코딩 테스트 합격할 수 있어요! ★ 자료구조, 알고리즘 이론

ebook-product.kyobobook.co.kr