import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
sc.nextLine(); // 개행문자제거
StringBuilder result = new StringBuilder(); // 결과 저장
for (int i = 0; i < N; i++) {
String S = sc.nextLine();
int length = S.length();
result.append(S.charAt(0)).append(S.charAt(length - 1)).append("\n");
}
System.out.println(result); // 한 번에 출력
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 숫자의 개수
String numbers = sc.next(); // 공백 없이 쓰인 숫자들
int sum = 0;
// 숫자 문자열의 각 문자를 정수로 변환하여 합산
for (int i = 0; i < N; i++) {
System.out.println("numbers.charAt(i) = " + numbers.charAt(i));
sum += numbers.charAt(i) - '0'; // char을 int로 변환
}
System.out.println(sum); // 합 출력
}
}
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String S = sc.nextLine();
StringBuilder result = new StringBuilder();
/* 'a' 부터 'z' 까지 반복
S.indexOf(c):
c가 S에 포함되어 있으면 첫 등장 위치를 반환
포함되어 있지 않으면 -1을 반환*/
for (char c = 'a'; c <= 'z'; c++) {
result.append(S.indexOf(c)).append(" ");
}
// 마지막 공백을 제거한 뒤 출력
System.out.println(result.toString().trim());
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 입력받기
int A = sc.nextInt();
int B = sc.nextInt();
// 숫자 뒤집기
int reversedA = reverseNumber(A);
int reversedB = reverseNumber(B);
// 결과 출력
System.out.println(Math.max(reversedA, reversedB));
}
// 숫자를 거꾸로 만드는 메서드
private static int reverseNumber(int num) {
int reversed = 0;
while (num > 0) {
reversed = reversed * 10 + (num % 10); // 가장 오른쪽 자리를 추가
num /= 10; // 오른쪽 자리 제거
}
return reversed;
}
}
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
// 1. Scanner를 사용하는 경우
while (sc.hasNextLine()) { // 입력이 더 있는 동안 반복
String line = sc.nextLine(); // 한 줄 읽기
System.out.println(line); // 그대로 출력
}
// 2. BufferedReader를 사용하는 경우
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null) { // 입력이 null(EOF)일 때 종료
System.out.println(line); // 그대로 출력
}
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
int[] baskets = new int[N];
for (int m = 0; m < M; m++) {
int i = sc.nextInt();
int j = sc.nextInt();
int k = sc.nextInt();
for (int b = i - 1; b < j; b++) {
baskets[b] = k;
}
}
for (int b = 0; b < N; b++) {
System.out.print(baskets[b] + " ");
}
}
}
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
// 바구니 초기화
int[] baskets = new int[N];
for (int i = 0; i < N; i++) {
baskets[i] = i + 1;
}
for (int a = 0; a < M; a++) {
int i = sc.nextInt();
int j = sc.nextInt();
// i번 바구니와 j번 바구니의 공을 교환 (인덱스는 0부터 시작하므로 i-1, j-1)
int temp = baskets[i - 1];
baskets[i - 1] = baskets[j - 1];
baskets[j - 1] = temp;
}
for (int b = 0; b < N ; b++) {
System.out.print(baskets[b] + " ");
}
}
}
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
boolean[] submitted = new boolean[31];
for (int i = 0; i < 28; i++) {
int N = sc.nextInt();
submitted[N] = true;
}
for (int i = 1; i <= 30; i++) {
if (!submitted[i]) {
System.out.println(i);
}
}
}
}
* HashSet은 중복 값을 허용하지 않는 자료구조
* 시간 복잡도는 O(1) 삽입 연산
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
HashSet<Integer> remainders = new HashSet<>(); // 나머지를 저장할 HashSet
for (int i = 0; i < 10; i++) {
int num = sc.nextInt();
remainders.add(num % 42); // 42로 나눈 나머지를 HashSet에 추가
}
// HashSet의 크기가 서로 다른 나머지 값의 개수
System.out.println(remainders.size());
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 바구니 개수
int M = sc.nextInt(); // 뒤집기 명령 수
// 바구니 초기화
int[] baskets = new int[N];
for (int i = 0; i < N; i++) {
baskets[i] = i + 1;
}
for (int a = 0; a < M; a++) {
int i = sc.nextInt(); // 시작 바구니
int j = sc.nextInt(); // 끝 바구니
reverse(baskets, i - 1, j - 1);
}
// 결과 출력
for (int num : baskets) {
System.out.print(num + " ");
}
}
// 배열의 부분 구간 [start, end]를 역순으로 뒤집는 함수
private static void reverse(int[] arr, int start, int end) {
while (start < end) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 시험 본 과목의 갯수
double[] scores = new double[N];
double maxScore = 0;
for (int i = 0; i < N; i++) {
scores[i] = sc.nextDouble();
if (scores[i] > maxScore) {
maxScore = scores[i]; // 최댓값 갱신
}
}
// 새로운 점수 계산
double sum = 0; // 변환 점수의 합
for (int i = 0; i < N; i++) {
sum += (scores[i] / maxScore) * 100;
}
// 새로운 평균 계산
double newAverage = sum / N;
System.out.println(newAverage);
}
}
[ StringBuilder ]
- 가변 객체(Mutable Object)
- 문자열이 변경될 때 새로운 객체를 생성하지 않고, 기존 객체 내부에서 내용을 변경
- 성능과 메모리 측면에서 매우 효율적
1. 가변성:
• 문자열의 추가, 삭제, 변경 작업을 기존 객체에서 수행
2. 효율성:
• 반복적인 문자열 수정 작업에서 메모리를 덜 사용하고, 속도가 빠름
3. 메서드 제공:
• 문자열 추가 (append), 삭제 (delete), 삽입 (insert), 반전 (reverse) 등의 다양한 메서드를 제공
* Scanner와 System.out.println 대신 BufferedReader와 BufferedWriter를 사용
[ BufferedReader와 BufferedWriter ]
1. BufferedReader 사용:
• BufferedReader는 입력을 버퍼링하여 대량의 입력을 효율적으로 처리
• readLine()을 사용하여 한 줄씩 읽음
2. BufferedWriter 사용:
• BufferedWriter는 출력 스트림을 버퍼링하여 출력 작업을 최적화
• write()를 사용하여 출력 내용을 기록하고, \n으로 줄바꿈을 추가
4. 출력 최적화:
• 반복문 안에서 출력할 내용을 BufferedWriter에 기록
• 출력 스트림을 비우기 위해 마지막에 flush()를 호출
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine());
for (int i = 0; i < T; i++) {
String[] input = br.readLine().split(" ");
int A = Integer.parseInt(input[0]);
int B = Integer.parseInt(input[1]);
bw.write((A + B) + "\n");
}
bw.flush();
bw.close();
br.close();
}
}
for (int i = 1; i <= N; i++) {
// 공백 출력 (N - i 개)
for (int j = 1; j <= N - i; j++) {
System.out.print(" ");
}
// 별 출력 (i 개)
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
// 줄바꿈
System.out.println();
}
(0 ≤ H ≤ 23, 0 ≤ M ≤ 59)
// 45분 앞당기기
M -= 45;
// 만약 분(M)이 음수라면
if (M < 0) {
M += 60; // 60분을 더해서 양수로 만듦
H -= 1; // 한 시간을 빼줌
}
// 만약 시간이 음수라면
if (H < 0) {
H += 24; // 24를 더해서 하루의 끝으로 되돌림
}
// 총 분 계산
B += C; // 현재 분에 요리 시간을 더함
A += B / 60; // 총 분에서 시간을 추가
B %= 60; // 남은 분 계산
A %= 24; // 24시간 기준으로 시간 계산
1. 현재 분과 요리 시간 더하기:
B += C: 현재 분(B)에 요리 시간(C)을 더합니다.
2. 시간 계산:
A += B / 60: 분(B)을 60으로 나눈 몫을 시간(A)에 추가합니다.
B %= 60: 분(B)에서 60으로 나눈 나머지를 계산하여 남은 분을 구합니다.
3. 24시간 기준으로 시간 계산:
A %= 24: 24시간을 초과하면 시간을 다시 0시부터 계산합니다.
// 첫 번째 세 자리 자연수 입력받기
int num1 = sc.nextInt();
// 두 번째 세 자리 자연수 입력받기
int num2 = sc.nextInt();
// (3) 두 번째 숫자의 1의 자리와 첫 번째 숫자를 곱한 값
System.out.println(num1 * (num2 % 10));
// (4) 두 번째 숫자의 10의 자리와 첫 번째 숫자를 곱한 값
System.out.println(num1 * ((num2 / 10) % 10));
// (5) 두 번째 숫자의 100의 자리와 첫 번째 숫자를 곱한 값
System.out.println(num1 * (num2 / 100));
// (6) 두 숫자의 곱
System.out.println(num1 * num2);
"OS kernel"에서의 backlog는 주로 네트워크 프로그래밍의 컨텍스트에서 사용됩니다. 이는 소켓 프로그래밍에서 서버가 클라이언트로부터의 연결 요청을 얼마나 많이 대기열에 둘 수 있는지를 나타내는 값입니다.
먼저, 간단한 네트워크 연결 과정을 이해하면 좋습니다:
서버는 특정 포트에서 클라이언트의 연결을 기다리기 위해 listen 상태가 됩니다.
클라이언트는 해당 포트로 연결 요청을 보냅니다.
서버는 연결 요청을 받아들이기 전에 이 요청을 일시적으로 대기열에 넣습니다. 이 대기열의 크기가 backlog입니다.
backlog의 값은 listen() 시스템 호출에서 지정됩니다. 예를 들어, C 언어의 소켓 프로그래밍에서 listen(sockfd, 5);라는 호출이 있다면, 서버는 동시에 최대 5개의 연결 요청을 대기열에 넣을 수 있습니다.
만약 backlog 값이 5이고, 동시에 6개의 연결 요청이 들어오면, 6번째 연결 요청은 거절될 수 있습니다.
따라서, backlog는 고성능 서버나 동시에 많은 연결 요청이 예상되는 서비스에서는 적절히 설정해주어야 합니다. 너무 낮게 설정하면 동시에 들어오는 많은 연결 요청 중 일부가 거절될 위험이 있습니다. 너무 높게 설정하면, 필요 이상의 리소스가 낭비될 수 있습니다.
이런방식으로, OS kernel의 backlog는서버의연결수용능력을조절하는데사용됩니다
backlog는 실질적으로 컴퓨터 네트워크에서 대기열(queue)을 의미합니다. 네트워킹 쪽에서 대기열이란, 데이터나 연결 요청을 일시적으로 저장하는 장소를 의미합니다. 이 대기열은 한정된 크기를 가지기 때문에, 이 크기를 초과하는 데이터나 연결 요청이 들어올 경우 추가적인 데이터나 요청은 버려지거나 거절될 수 있습니다.
그런데 여기서 backlog는 주로 두 가지 상황에서 사용됩니다:
네트워크 장치의 패킷 대기열 (netdev_max_backlog):데이터가 네트워크를 통해 전송될 때, 각각의 데이터는 패킷(packet)이라는 작은 단위로 나뉩니다. 이러한 패킷들은 운영체제의 네트워크 스택에 도착하면 일시적으로 큐에 저장됩니다.
netdev_max_backlog는 이 큐의 크기, 즉 네트워크 스택에서 한 번에 처리할 수 있는 패킷의 최대 수를 설정합니다. 이 큐가 가득 찬 상태에서 추가 패킷이 도착하면, 그 패킷은 버려집니다.
소켓의 연결 대기열 (somaxconn):서버가 클라이언트로부터 연결 요청을 받으면, 이 연결 요청은 일단 큐에 들어갑니다. 그 후, 서버가 준비될 때마다 큐에서 연결 요청을 꺼내와 처리(accept)합니다
somaxconn은 이 큐의 크기, 즉 서버가 한 번에 대기할 수 있는 연결 요청의 최대 수를 설정합니다. 이 큐가 가득 찬 상태에서 추가 연결 요청이 들어오면, 그 요청은 거절됩니다.
이렇게 backlog는네트워크의특정부분에서일시적으로데이터나연결요청을보관하는역할을하는대기열의크기를설정하는값입니다. 서버의용도나트래픽의양에따라 backlog 값을조절하여, 서버의성능과안정성을높일수있습니다.
backlog는 물리적 네트워크 포트에서 패킷을 쌓아두는 커널의 큐 크기입니다. 만약 이 큐 크기가 작아서 큐에 쌓이지 못한 패킷들은 버려지게 됩니다. backlog 값을 확인 하려면, 아래의 명령어를 실행합니다. ]# sysctl net.core.netdev_max_backlog backlog는 또 한가지의 종류가 있는데 그것은 listen backlog 입니다. 클라이언트가 서버에 연결할 경우, accept 하지 못한 클라이언트들이 대기할 수 있는 최대값입니다. 만약 backlog가 1000이라면, 1000개의 클라이언트가 accept 에서 대기할 수 있습니다. listen backlog 값을 확인 하려면, 아래의 명령어를 실행합니다. ]# sysctl net.core.somaxconn 이러한 값들은 대량의 트래픽을 처리하는 서버에서는 알맞게 설정해줄 필요가 있습니다.
HashMap:
내부 구조 : 해시 테이블을 사용.
시간 복잡도: get과 put 연산: 평균적인 경우 O(1). 최악의 경우 (해시 충돌이 발생할 경우) O(n).
특징: 순서를 보장하지 않습니다. null 키와 null 값을 허용.
TreeMap:
내부 구조: 레드-블랙 트리 (균형 이진 검색 트리)를 사용.
시간 복잡도: get, put, remove 연산: O(log n)
특징: 키에 대해 순서를 보장합니다. null 키는 허용되지 않지만, null 값을 허용.
/*
avg 케이스가 빅오(1)이고 워스트 케이스에선 해쉬 충돌로 인해 빅오(N)이 될 수 있습니다.
Java 버전 8이전에는 해쉬 충돌에 대해 같은 Key 버켓에 대해서 LinkedList를 사용해서 빅오(N)의 시간 복잡도를 가졌지만,
현재는 동적으로 LinkedList에서 TreeMap으로 바뀌기 때문에 빅오 로그N
*/
요약하자면, HashMap은해시테이블을기반으로동작하여평균적인상황에서 get 및 put 연산이상수시간에가능하지만, 해시충돌이발생할경우성능이저하될수있다. 반면, TreeMap은키의순서를보장하며, 모든주요연산들이로그시간에이루어진다.
HashMap과 TreeMap의 선택은 상황과 필요에 따라 달라진다.
HashMap은 평균적인 경우에 빠른 접근 시간 O(1)을 제공하지만, 해쉬 충돌이 자주 발생하면 성능 저하의 위험이 있음.
반면 TreeMap은 밸런스드 트리 구조로 인해 항상 O(log n)의 시간 복잡도를 가진다.
데이터가 많지 않고 해쉬 충돌의 가능성이 적다면 HashMap이 더 유리
데이터가 엄청 많아지면 평균적으로 빅오(lonN)인 TreeMap이 유리
/*
ArrayList와 LinkedList와의 비교
ArrayList는 인덱스 기반의 접근에 최적화되어 있어 빠른 조회를 제공하지만, 중간에 요소를 삽입하거나 삭제할 경우에는 비효율적
LinkedList는 중간에 요소를 삽입하거나 삭제할 때 효율적이지만, 인덱스 기반의 조회에서는 비효율적
*/
TreeMap의 워스트 케이스 시간 복잡도 :
삽입(insert), 삭제(delete), 조회(lookup): TreeMap은 레드-블랙 트리를 기반으로 구현되어 있다. 따라서 이러한 연산들의 워스트 케이스 시간 복잡도는 모두 O(log n).
TreeMap은 내부적으로 레드-블랙 트리를 사용하여 구현되어 있다.
레드-블랙 트리는 이진 탐색 트리의 한 종류로, 트리가 균형을 유지하도록 설계되어 있다.
따라서 삽입, 삭제, 조회 연산의 시간 복잡도가 일반적으로 O(log n)으로 매우 효율적이다.
그러나 정말로 특이한 경우에, 즉 이진 탐색 트리가 완전히 한 쪽으로 치우쳐져 있을 때
(즉, 모든 노드가 왼쪽 자식 또는 오른쪽 자식만을 가질 때) 워스트 케이스의 시간 복잡도는 O(n)이 될 수 있다.
그러나 레드-블랙 트리의 특성 상 이런 워스트 케이스는 발생하지 않도록 트리의 균형을 유지하는 연산이 수행됨.
따라서 실제 TreeMap의 구현에서는 이러한 워스트 케이스 시나리오가 발생하지 않도록 보장되며,
그 결과 TreeMap의 삽입, 삭제, 조회 연산의 시간 복잡도는 항상 O(log n).