재귀
함수가 자기 자신을 호출하는 프로그래밍
public class Test {
public static void main(String[] args) {
int n=10;
printNos(n);
}
public static void printNos(int n) {
if(n>0) {
printNos(n-1);
System.out.print(n+" ");
}
}
코드 동작 과정
1. JVM이 Test 클래스를 Method Area에 load
2. 메인 제외 static 멤버 초기화 (Method Area영역 내부의 static영역에 printNos() 저장)
3. 상속관계 파악
4. main 수행
5. n이 printNos()의 local data이므로 stack 영역 할당(4byte 크기)
6. printNos()에 n값을 copy해서 전달(리터럴은 값이 copy(=pass by value), 레퍼런스는 객체의 주소를 copy(=pass by reference))
7. 재귀 호출 진행 => printNos(10) >> printNos(9) >> ... >> printNos(1) >> printNos(0)
8. 각 재귀 호출 시 n은 stack영역에 새롭게 공간이 할당되고, main의 n이 copy of value가 되어 값을 전달. 이 과정이 if에 부합되지 않을 때까지 반복됨
9. 부합되지 않는 경우(n=0) 이전 호출 시점으로 되돌아감 printNos(0) 종료 >> printNos(1)의 실행위치로 돌아감. 이 과정이 반복됨. 실행이 끝난 메서드 값은 GC에 의해 스택에서 제거됨
재귀 vs 반복문
반복문을 대신할 수 있고 코드를 간결하게 작성가능. 하지만 반복문보다 성능은 bad (함수 호출 시마다 시스템 스택 메모리를 사용하므로 스택오버플로우가 발생될 수 있음)
몇 번 돌아야 할 지 아는 경우에는 loop를 사용하는게 가장 좋음
Serialization (직렬화)
통신을 할 때 데이터만 나열해서 보내는 것. 서로 다른 시스템에 pass by reference를 하게 되면 주소를 보내게 되는데 전송을 받는 쪽에서 주소를 받아서 할 수 있는게 없으므로 value를 전송 해줘야 함.
하나의 시스템 내에서 pass by reference를 하면 값 전달은 가능하지만 주소를 전달해주는 방식은 비용측면에서 bad
배열
1) 투포인터
배열이나 리스트같은 선형 자료구조에서 포인터 두 개로 합을 찾거나 중복을 제거할 때 사용. copy 안하므로 공간복잡도, 시간복잡도 good
2) 투포인터 응용 - 슬라이딩 윈도우
슬라이딩 윈도우(Sliding Window) 기법은 주로 배열이나 리스트와 같은 선형 자료 구조에서 연속적인 부분 배열이나 부분 문자열을 처리하는 데 유용한 알고리즘 기법. 이 기법은 특정 범위를 효율적으로 탐색하고, 계산할 수 있음.
기본 개념
슬라이딩 윈도우는 두 개의 포인터 또는 인덱스를 사용하여 데이터의 일부를 선택하고, 이 선택된 범위를 "윈도우"라고 부름. 이 윈도우는 데이터의 특정 부분을 나타내며, 필요에 따라 크기나 위치를 조정할 수 있음.
주요 특징
연속성: 윈도우 내의 요소들은 항상 연속적.
효율성: 윈도우의 크기를 변경하면서 반복적으로 계산할 수 있어, 중복 계산을 피하고 시간 복잡도를 줄임.
상태 유지: 각 윈도우의 상태를 유지하면서 필요한 계산을 수행할 수 있음.
시간 복잡도 감소: O(n)
간결한 코드: 복잡한 중첩 루프를 줄이고, 코드의 가독성을 높임.
사용 예시
최대/최소 합의 부분 배열 찾기: 연속된 K 개의 요소의 최대 합을 찾는 문제.
문자열 문제: 주어진 문자열에서 특정 조건을 만족하는 부분 문자열의 길이나 개수를 찾는 문제.
중복 제거: 특정 조건을 만족하는 부분 배열에서 중복 요소를 제거하는 문제.
슬라이딩 윈도우의 유형
고정 크기 윈도우: 윈도우의 크기가 고정되어 있는 경우 (예: K 개의 요소).
가변 크기 윈도우: 윈도우의 크기가 동적으로 조정되는 경우 (예: 조건에 따라 요소를 추가하거나 제거).
슬라이딩 윈도우 기법의 장점
Exception
Exception 처리 기법 2가지
1) try-catch : try블록에서 예외 발생 시 catch 블록에서 예외 처리
2) throw : 예외 발생 시 호출한 쪽으로 예외를 던짐
User define Exception (사용자 정의 예외)
RuntimeException ==> Checked Exception : Runtime보다 Checked가 더 명확하게 클라이언트 개발자에게 전달 가능. 런타임의 경우에는 오류 메세지 전체를 전달하기 때문에 공격 받을 수 있음.
Exception Message는 간단, 명확 전달
ArrayIndexOutOfBoundsException e : 배열 인덱스 초과
ArithmeticException e : 0으로 나누기
NumberFormatException e : 문자열을 숫자로 변환 시 형식 오류
Exception e : 예외 처리 강제
예외 발생 시 적절한 반환 방식
예외 발생 시 return 0을 하면 연산 결과가 정상적인것 처럼 보일 수 있어서 이건 좋은 프로그램이 아님.
public static int divide(int x, int y) throws AriathmeticException{
return x/y;
} // 에러 발생 시 객체 자체를 리턴함.
상세한 에러 메세지는 공격의 빌미를 제공할 수 있음.
그래서 서버에서 사용자에게 텍스트로 단순한 요구 메세지를 제공하도록 변경
public static void main(String[] args) throws Exception {
divide(10, 0);
}
main메서드자체에서 throws를 하면 예외가 JVM까지 전달되어 JVM이 뻗어버림(에러 처리를 안하겠다는 것과 동일)
public static void main(String[] args) {
try {
System.out.println(divide(10, 0));
} catch (ArithmeticException e) {
System.out.println("0을 입력하지 마세요");
}
}
main메서드 내부에서 try catch문으로 Exception 받기.
class MyException extends Exception{
public MyException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
}
exception 클래스를 만들어서 텍스트로 간단하게 보여주고 Serialization 하면 비용이 비싸지만 그만큼 대비할 가치가 있음.
프로그래머스 코딩테스트 스터디
[기초][JAVA][02.13] 프로그래머스 코딩테스트
문자열 붙여서 출력하기class Solution { public int[] solution(int[] num_list) { int[] answer = new int[num_list.length]; int count=0; for(int i = num_list.length-1; i >= 0; i--){ answer[count++] = num_list[i]; } return answer; }}flag에 따라 다
leeemingyu.tistory.com
[입문][JAVA][02.13] 프로그래머스 코딩테스트
몫 구하기class Solution { public int solution(int num1, int num2) { int answer = num1/num2; return answer; }}나머지 구하기class Solution { public int solution(int num1, int num2) { int answer = num1%num2; return answer; }}두 수의 차class Solu
leeemingyu.tistory.com