
char → int 변환 (char - ‘0’)
array를 채워주는 문법
버블정렬은 첫번재와 두번를 비교함 왼쪽이 오른쪽보다 크면 교환(swap)함
그리고 두번째와 3번째를 비교함 이걸 계속 반복함 그걸 패스쓰루라고함 더이상 반복하지 않으면 정렬이 끝남
버블 정렬은 원소 N개가 있을때 N^2번의 단계가 필요하고
빅오 표기법은 버블 정렬의 효율성을 O(N^2)라고 하고 이를 이차 시간이라고도 부름
Key Value 형태로 데이터를 저장하는 자료구조
빠르게 찾고 싶을때 사용함 O(1)중복 key 불가능 함
아이디 찾기 , 캐시, 카운팅에 주로 사용됨
계층적 구조의 노드기반 자료구조
루트 - 자식 노드 형태로 뻗어감 중복 안됨
BST기준 O(logN)
정렬된 자료보관, 탐색 트리 에 사용됨
HyperTextTransferProtocol
클라이언트(브라우저,앱)와 서버가 서로 데이터를 주고받기 위한 약속된 통신 규칙
클라이언트 -> 요청(Request) -> 서버
서버 -> 응답(Response) -> 클라이언트
GET /todos HTTP/1.1 // 요청라인 : 메서드 + 경로 + 버전
Host: example.com
User-Agent: Chrome/...
Content-Type: application/json // 헤더 : 부가정보
(빈 줄) // 본문과 헤더 구분
{"task":"청소하기","done":false} 바디 :실제데이터
HTTP/1.1 200 OK // 상태라인 : 버전+상태 코드 + 메세지
Content-Type: application/json //헤더 부가 정보
Content-Length: 37
(빈 줄) // 본문과 헤더 구분
{"id":1,"task":"청소하기","done":false} //바디 :응답 데이터
GET 데이터 조회
POST 새 데이터 생성
PUT 데이터 전체 수정
PATCH 데이터 일부 수정
DELETE 삭제
200 OK 성공 요청 정상 처리
201 Created 생성됨 POST 성공 시
400 Bad Request 잘못된 요청 파라미터 오류
401 Unauthorized 인증 실패 로그인 필요
403 Forbidden 접근 금지 권한 없음
404 Not Found 없는 자원 잘못된 URL
500 Internal Server Error 서버 에러 코드 오류 발생 시
REpresentational State TransferApplication Programming Interface
HTTP 기반으로 동작하는
규칙이 정해진 방식의 URL과 메서드 설계
클라이언트가 자원(Resource) 에 요청(Request) 을 보내고, 서버가 응답(Response) 하는 구조
자원 : 데이터의 대상 (/todos,users/1)
행위 : 어떤 동작인지 (GET,POST,PUT,DELETE)
표현 : 주고받는 데이터 형식 ( Json,Xml등)
uri는 자원을 표현함 /todos,/todos/1 동사는 안씀 /getTodo,/addTodo
HTTP 메소드로 행위를 구분함 GET,POST,PUT,DELETE
요청 간 서버가 상태 저장을 하지 않음
일관된 구조를 사용함
영어 대소문자와 공백으로 이루어진 문자열이 주어진다. 이 문자열에는 몇 개의 단어가 있을까? 이를 구하는 프로그램을 작성하시오. 단, 한 단어가 여러 번 등장하면 등장한 횟수만큼 모두 세어야 한다.
첫 줄에 영어 대소문자와 공백으로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 공백 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한 문자열은 공백으로 시작하거나 끝날 수 있다.
첫째 줄에 단어의 개수를 출력한다.
The Curious Case of Benjamin Button
6
The first character is a blank
6
The last character is a blank
6
package string;
import java.util.Scanner;
public class BOJ_1152_WordCount {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine().trim();
if(str.isEmpty()){
System.out.println(0);
}else{
String[] strArr = str.split("\\s+");
System.out.println(strArr.length);
}
}
}
Trim으로 앞뒤 공백 제거 .split \s+로 여러 공백도 한번에 나눔
입력이 공백으로 시작하거나 끝나는 경우도 고려하는 문자열 전처리 실력 평가
상근이의 동생 상수는 수학을 정말 못한다. 상수는 숫자를 읽는데 문제가 있다. 이렇게 수학을 못하는 상수를 위해서 상근이는 수의 크기를 비교하는 문제를 내주었다. 상근이는 세 자리 수 두 개를 칠판에 써주었다. 그 다음에 크기가 큰 수를 말해보라고 했다.
상수는 수를 다른 사람과 다르게 거꾸로 읽는다. 예를 들어, 734와 893을 칠판에 적었다면, 상수는 이 수를 437과 398로 읽는다. 따라서, 상수는 두 수중 큰 수인 437을 큰 수라고 말할 것이다.
두 수가 주어졌을 때, 상수의 대답을 출력하는 프로그램을 작성하시오.
첫째 줄에 상근이가 칠판에 적은 두 수 A와 B가 주어진다. 두 수는 같지 않은 세 자리 수이며, 0이 포함되어 있지 않다.
첫째 줄에 상수의 대답을 출력한다.
734 893
437
221 231
132
839 237
938
package string;
import java.util.Scanner;
public class BOJ_2908_ReverseCompare {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int c = (a/100)+((a%10)*100)+(((a/10)%10)*10);
int d = (b/100)+((b%10)*100)+(((b/10)%10)*10);
if(c<d){
System.out.println(d);
}else {
System.out.println(c);
}
}
}
import java.util.Scanner;
public class BOJ_2908_ReverseCompare {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String [] INT = sc.nextLine().split(" ");
int a = Integer.parseInt(new StringBuilder(INT[0]).reverse().toString());
int b = Integer.parseInt(new StringBuilder(INT[1]).reverse().toString());
if(a > b){
System.out.println(a);
}else{
System.out.println(b);
}
}
}
StringBuilder.reverse() 또는 수학적으로 자리수 뒤집기 능력 평가
int ↔ String 변환 능력 및 비교 로직 구현
상근이의 할머니는 아래 그림과 같이 오래된 다이얼 전화기를 사용한다.

전화를 걸고 싶은 번호가 있다면, 숫자를 하나를 누른 다음에 금속 핀이 있는 곳 까지 시계방향으로 돌려야 한다. 숫자를 하나 누르면 다이얼이 처음 위치로 돌아가고, 다음 숫자를 누르려면 다이얼을 처음 위치에서 다시 돌려야 한다.
숫자 1을 걸려면 총 2초가 필요하다. 1보다 큰 수를 거는데 걸리는 시간은 이보다 더 걸리며, 한 칸 옆에 있는 숫자를 걸기 위해선 1초씩 더 걸린다.
상근이의 할머니는 전화 번호를 각 숫자에 해당하는 문자로 외운다. 즉, 어떤 단어를 걸 때, 각 알파벳에 해당하는 숫자를 걸면 된다. 예를 들어, UNUCIC는 868242와 같다.
할머니가 외운 단어가 주어졌을 때, 이 전화를 걸기 위해서 필요한 최소 시간을 구하는 프로그램을 작성하시오.
첫째 줄에 알파벳 대문자로 이루어진 단어가 주어진다. 단어의 길이는 2보다 크거나 같고, 15보다 작거나 같다.
첫째 줄에 다이얼을 걸기 위해서 필요한 최소 시간을 출력한다.
WA
13
UNUCIC
36
package string;
import java.util.Scanner;
public class BOJ_5622_DialTimeCalc {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String dial = sc.nextLine().toUpperCase();
int time = 0;
for (int i = 0; i < dial.length(); i++) {
char ch = dial.charAt(i);
if (ch >= 'A' && ch <= 'C') {
time += 3;
} else if (ch >= 'D' && ch <= 'F') {
time += 4;
} else if (ch >= 'G' && ch <= 'I') {
time += 5;
} else if (ch >= 'J' && ch <= 'L') {
time += 6;
} else if (ch >= 'M' && ch <= 'O') {
time += 7;
} else if (ch >= 'P' && ch <= 'S') {
time += 8;
} else if (ch >= 'T' && ch <= 'V') {
time += 9;
} else if (ch >= 'W' && ch <= 'Z') {
time += 10;
}
}
System.out.println(time);
}
}
조건문, 반복문, 또는 배열/맵 자료구조를 활용한 처리
모든 영문자를 대문자로 만드는 메소드
선택정렬은 각 셀을 왼쪽부터 오른쪽 방향으로 확인하면서 어떤 값이 최솟값인지 결정함
한 셀씩 이동하면서 현재까지 가장 작은 값을 변수에 저장함 현재 변수값보다 작은 값이들어있는 셀을 만나면
변수가 새인덱스를 가르키도록 값을 대체함
처음엔 인덱스 0 이 최솟값으로 변수에 들어간 후 한번의 패스스루를 거쳐 인덱스0을 최솟값으로 만들고
인덱스1부터 다시 반복함
선택정렬은 비교와 교환 두 종류의 단계를 포함함 N개의 원소가 있을때
(N-1)+(N-2)+(N-3)…의 비교를 실행함
교환은 한 패스스루 당 최소 한 번 일어남 버블 정렬과 달리 최악의 시나리오에선 빠짐없이 교환을 한번 해야함
선택 정렬은 버블 정렬보다 단계수가 반정도 적음 즉 두배 정도 빠름
선택 정렬은 버블 정렬의 반 즉 O(N^2/2)로 설명할 수 있지만 선 정렬은 빅오로 표현하면 똑같이 O(N^2)이다
빅 오 표기법은 지수가 아닌 수는 포함하지 않기 때문이다
빅오는 특정 시점부터 어느 유형이 다른 유형보다 속도가 빨라지는지 중요하지 않다
빅 오는 데이터가 많을때 한 알고리즘이 어떤 시점부터 빠르다는걸 보장하기 대문에
어떤 알고리즘을 서야하는지 대체로 알 수 있다
HyperTextTransferProtocol Secure
HTTP의 +보안(암호화)방식
서버와 클라이언트가 데이터를 주고받을때 누군가 훔쳐보지 못하게 암호화 해주는 통신 방식
저장소 추상화란 ?
"데이터를 어디에 저장하든지, 사용하는 쪽(TodoService)은 그걸 몰라도 되게 만드는 구조"
저장방식 등을 숨기고 공통된 인터페이스만 보고 쓰게하는것
이 클래스는 이런 기능을 할것이다라고 미리 정해놓은 약속
기능은 정의하지만 구현은 나중에 알아서 함
예시)
인터페이스 선언 소리와 움직임을 정의해놓고
Interface
public interface Animal {
void sound();
void move();
}
나중에 구현함
Implement
public class Dog implements Animal {
public void sound() {
System.out.println("멍멍");
}
public void move() {
System.out.println("네 발로 뛰어다님");
}
TodoService ← TodoRepository (인터페이스 의존)
↳ MemoryTodoRepository
↳ JsonTodoRepository
import java.util.Scanner;
public class TodoController {
private final TodoService service;
public TodoController(TodoService service){
this.service = service;
}
private int extractId(String uri) {
try {
String[] parts = uri.split("/");
return Integer.parseInt(parts[2]);
} catch (Exception e) {
return -1;
}
}
public String handleRequest(String method,String url){
if(method.equals("GET")&&url.equals("/todos")){
return service.getAllTodos();
} else if(method.equals("POST")&&url.equals("/todos")){
Scanner sc = new Scanner(System.in);
System.out.println("할일 입력");
String task = sc.nextLine();
System.out.print("카테고리 입력: ");
String category = sc.nextLine();
System.out.print("마감일 입력 (yyyy-MM-dd): ");
String inputDate = sc.nextLine();
return service.createTodo(task,category,inputDate);
} else if(method.equals("GET")&&url.startsWith("/todos/")){
int id = extractId(url);
return service.getTodoById(id);
} else if(method.equals("PUT")&&url.startsWith("/todos/")){
int id = extractId(url);
Scanner sc = new Scanner(System.in);
System.out.println("변경된 일 입력");
String task = sc.nextLine();
System.out.print("카테고리 입력: ");
String category = sc.nextLine();
String inputDate = sc.nextLine();
System.out.print("마감일 입력 (yyyy-MM-dd): ");
return service.updateTodo(id,task,category,inputDate);
} else if(method.equals("PATCH")&&url.startsWith("/todos/")&&url.endsWith("/done")){
int id = extractId(url);
return service.markDone(id);
} else if(method.equals("DELETE")&&url.startsWith("/todos/")){
int id = extractId(url);
return service.deleteTodo(id);
}
return "404 Not Found";
}
}
사용자의 요청이 들어오면 Controller는 전부 여기로 넘겨서 처리를 함
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;
import java.util.stream.Collectors;
public class TodoService {
private final TodoRepository repository;
private final Stack<Todo> deleteStack = new Stack<>();
public TodoService(TodoRepository repository) {
this.repository = repository;
}
public String createTodo(String task, String category, String inputDate) {
LocalDate dueDate;
try {
dueDate = (inputDate == null || inputDate.isBlank())
? LocalDate.now()
: LocalDate.parse(inputDate);
} catch (DateTimeParseException e) {
dueDate = LocalDate.now();
}
if (category == null || category.isBlank()) {
category = "기타";
}
Todo todo = new Todo(task, false, category, dueDate);
repository.save(todo);
return "할일이 추가 되었습니다";
}
public String getAllTodos() {
List<Todo> list = repository.findAll();
if (list.isEmpty()) {
return "할일이 없습니다";
}
return list.stream()
.map(Todo::toString)
.collect(Collectors.joining("\n"));
}
public String deleteTodo(int id) {
Todo todo = repository.findById(id);
if (todo ==null){return"해당일이 없습니다";}
deleteStack.push(todo);
repository.delete(id);
return"삭제완료";
}
public String updateTodo(int id, String task, String category, String inputDate) {
Todo old = repository.findById(id);
if (old == null) {return "해당일이 없습니다";}
LocalDate dueDate;
try{
dueDate = (inputDate==null ||inputDate.isBlank())
? LocalDate.now()
: LocalDate.parse(inputDate);
}catch (DateTimeParseException e){
dueDate = old.getDueDate();
}
Todo updated = new Todo(task, old.isDone(),category, dueDate);
repository.update(id, updated);
return"할일이 수정되었습니다";
}
public String getTodoById(int id) {
Todo todo = repository.findById(id);
if (todo == null) {
return "해당 할 일이 없습니다";
}
return todo.toString();
}
public String markDone(int id) {
Todo todo = repository.findById(id);
if(todo == null){return"해당 할일이 없습니다";}
todo.markDone();
return"완료처리 되었습니다";
}
public String undoDelete(int id) {
if(deleteStack.isEmpty()){return"삭제된 항목이 없습니다";}
Todo restored =deleteStack.pop();
repository.save(restored);
return"복구완료";
}
public String getIncompleteTodos() {
List<Todo> list = repository.findAll().stream()
.filter(todo -> !todo.isDone())
.collect(Collectors.toList());
if (list.isEmpty()) return " 완료할 일이 없습니다.";
return list.stream()
.map(Todo::toString)
.collect(Collectors.joining("\n"));
}
public String searchByKeyword(String keyword) {
List<Todo> result = repository.findAll().stream()
.filter(todo -> todo.getTask().toLowerCase().contains(keyword.toLowerCase()))
.collect(Collectors.toList());
if (result.isEmpty()) return " 검색 결과가 없습니다.";
return result.stream()
.map(Todo::toString)
.collect(Collectors.joining("\n"));
}
public boolean isEmpty() {
return repository.findAll().isEmpty();
}
}
규칙을 정함 (할일 저장소는 이런 기능을 가져야 함)
import java.util.List;
public interface TodoRepository {
List<Todo> findAll();
Todo findById(int id);
void save(Todo todo);
void delete(int id);
void update(int id,Todo updateTodo);
}
실제 구현하는 MemoryTodoRepository
TodoRepository의 기능들을 실제로 구현시키는 클래스
import java.util.*;
public class MemoryTodoRepository implements TodoRepository {
private final List<Todo> todos = new ArrayList<>();
@Override
public List<Todo>findAll() {
return new ArrayList<>(todos);
}
@Override
public Todo findById(int id) {
return todos.stream().filter(t -> t.getId() == id).findFirst().orElse(null);
}
@Override
public void save(Todo todo){
todos.add(todo);
}
@Override
public void delete(int id){
todos.removeIf(t ->t.getId() == id );
}
@Override
public void update(int id,Todo updateTodo){
delete(id);
save(updateTodo);
}
}
자료구조를 공부하다 보니 알고리즘에 대해서 조금씩 알아가고 있다 버블정렬 선탤정렬
빅오 표기법 빅오를 알고나니 효율적인 코드를 써야겠다는 생각은 들었는데
이게 뭐가 효율적인지코테를 할때도 생각을 해야하는지 고민이 많아졌다
Java Spring에들어가기 앞서 RestApi의 구조를 이해하고
MVC구조를 이해하기 위해 전체 리팩토링 저장소 추상화를 했다
http 메소드들도 이해가 좀 됐고 api가 뭔지도 조금 알거같다
이제 gpt가 코드를 짜주면 애가 뭘이야기하는지 조금은 알거같다
요즘 많이 해이해졌는데 포기하지말고 계속하자 Spring가자!