Backend
home

[Java] Java 알고리즘 최적화

생성일
2024/11/15 03:11
태그
Algorithm
게시일
2025/01/22
최종 편집 일시
2025/04/15 04:34
입력을 받기 위해서는 Scanner보다 BufferedReader를 사용하는 것이 좋다.
한 줄 입력이 여러 번 들어오는 경우에는 split보다 StringTokenizer를 사용하여 파싱하는 것이 좋다.
여러 번 출력해야 하는 경우에는 StringBuilder를 사용해 한번에 출력하는 것이 좋다. Array를 사용하는 것보다 ArrayList를 사용하는 것이 좋다.
ArrayList를 정렬하기 위해서는 Collections.sort()를 사용한다.
배열을 초기화하기 위해서는 java.util.Arrays의 Arrays.fill(배열, 초기화값)을 사용한다.

ArrayList

고정 크기 배열에 기반한 리스트
ArrayList는 배열 최대 크기만큼 요소를 추가할 수 있으며, 요소를 더 추가할 수 없는 경우 더 큰 배열을 새로 할당한 다음 기존 값을 복사한다.
ArrayList에 초기 용량값을 설정하지 않으면 처음에 빈 배열로 시작하고 요소가 추가될 때 용량 10인 기반 배열을 할당한다.
ArrayList 크기를 정확히 결정하고 시작하는 게 성능은 더 낫다.
랜덤 액세스가 필요한 알고리즘을 구사할 때는 ArrayList를 권장한다.
@Benchmark public List<String> properlySizedArrayList() { List<String> list = new ArrayList<>(1_000_000); for (int i = 0; i < 1_000_000; i++) { list.add(item); } return list; } @Benchmark public List<String> resizingArrayList() { List<String> list = new ArrayList<>(); for (int i = 0; i < 1_000_000; i++) { list.add(item); } return list; }
Java
복사
Benchmark Mode Cnt Score Error Units ResizingList.properlySizedArrayList thrpt 10 287.388 ± 7.135 ops/s ResizingList.resizingArrayList thrpt 10 189.510 ± 4.530 ops/s
Java
복사

BufferedWriter

import java.io.BufferedWriter; import java.io.OutputStreamWriter; BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); // 선언 String s = "abacdefg" bw.write(s+"\n"); // 버퍼에 값을 씀 bw.flush(); // 남아 있는 데이터 모두 출력 bw.close(); // 스트림 닫음
Java
복사
BufferedWriter 경우 버퍼를 잡아 놓았기 때문에 반드시 flush() / close()를 반드시 호출해 뒤처리 필요하다.
write(); 경우 자동 개행 기능이 없어 개행 필요시 따로 처리 필요하다.
"\n" 또는 newLine(); 이용
메서드
close() : 스트림 닫음. 닫기 전 flushing 필수
flush() : 스트림 비우기
newLine() : 개행역할
wirte(char[] cbuf, int offset, int length) : 버퍼 offset 위치부터 length크기만큼 write 씀
write(int c) : 한 글자 쓰기
wirte(String s, int offset, int lnegth) : 문자열에서 offset부터 일정 길이만큼 write

System.out.println을 최대한 줄이고 StringBuilder 을 활용하자

오버헤드가 쌓여 성능 저하를 초래한다.
StringBuilder는 문자열을 더할 때 새로운 객체를 생성하는 것이 아닌 기존의 데이터를 더하는 방식을 사용하기 때문에 속도도 빠르며 상대적으로 부하가 적다.
StringBuilder 생성자
()생성자는 초기 용량을 16bytes로 지정
(int capacity)생성자는 파라미터로 초기 용량 지정
(String str)생성자는 str.length + 16bytes로 초기 용량 지정
(Charsequence seq)생성자는 seq.length + 16bytes로 초기 용량 지정
Charsequence는 인터페이스로 구현 클래스로는 String, StringBuffer, StringBuilder가 있다.
capacity()와 length()는 다름.
capacity()는 버퍼 크기 length()는 문자 시퀀스 개수를 나타낸다.
만약 버퍼가 가득 차면 (기존 capacity +1) * 2 버퍼 크기로 변경된다.
.toString()을 이용해 String으로 변환할 수 있다.

java.util 패키지를 되도록 사용하자

정렬 등과 같은 것들을 최대한 이미 만들어져 있는 것들을 사용하는 것이 좋다. 내가 작성한 코드보다 일단 최적화는 입증된 것일 뿐만 아니라 그 외의 문제에 대한 시간을 투자하는 것이 훨씬 보다 더 효율적이기 때문이다.

while문, do~while 문 대신 for 문을 주로 사용하자

for문 조건식에서 .length; 또는 .length(); 사용을 하게 되면 매 반복 호출되어 느려진다. 그렇기에 .length(); 값을 변수에 저장해 사용하자.

if문 조건 내부에 2개 이상 조건이 주어질 때, 조건의 순서를 생각하자

"&&"일 때 False 값이 많이 오는 조건을 앞으로, "||"일 때 True 값이 많이 오는 조건을 앞으로 작성하자.
가장 먼저 동작할 수 있는 것을 우선순위로 정해서 적용하기