벌써 두 번째 월급을 받았습니다. 시간이 너무 빨라서 이렇게 나태하게 살아도 되나 싶습니다. (생각만 하는 타입)

한 달이 지난 후 베네핏 카드를 받게 되었습니다. 매달 정해진 금액만큼 어디에나 사용할 수 있는 엄청난 복지카드 입니다. 저는 우선 가족외식 때 밥을 샀고, 제 돈 주고 사긴 아까웠던 고가의 악세사리도 질렀습니다. ㅎㅎ

여전히 밥은 맛있습니다. 양도 여전히 많아서 반도 못 먹는게 많이 아쉽습니다.. 😭

카카오는 라이언과 춘식이를 정말 좋아하는 것 같습니다

최근에는 테이크아웃 메뉴들을 많이 이용하고 있습니다. 샐러드가 맛있어서 자주 먹게 되는 것 같습니다. 다이어트라고 하기엔 다른 메뉴보다 칼로리가 높은 경우가 많습니다. (why지..)


회사를 다니면서 이 계약이 끝나면 어떻게 해야하나 라는 고민을 많이 하고 있는데요.. 아무래도 제가 맡은 직무가 단순한 편인만큼 경험으로 녹여낼 수 있는 부분이 많지 않기 때문입니다.

아무래도 다니면서 부가적인 준비를 병행하는 것은 불가피한 것 같습니다만, 게을러빠진 제가 어떻게 해낼지...^^; 🤔 열심히 살기가 쉽지 않습니다.

20년도 기출에 출제된 개념을 정리했습니다.

 

정규화

  • 반정규화: 데이터베이스의 정규화 이후 성능 향상, 개발 편의성 등을 위해 정규화에 위배되는수행 기법

 

[언어]

  • Xml: 웹에서 구조화한 문서 표현/전송하도록 설계한 마크업 언어
  • Json: 자바스크립트 객체 문법, 구조화된 데이터 표현하기 위한 문자 기반 표준 포맷, 이름-값 쌍
  • Csv: 몇 가지 필드를 쉽표로 구분한 텍스트 데이터/파일
  • Yaml: 이메일 양식에서 개념 얻은 사람이 쉽게 읽을 수 있는 데이터 지결화 양식

 

[소프트웨어 테스팅]

  • 살충제 패러독스: 동일 테스트 케이스로 동일 절차 반복 수행하면 새로운 결함 찾을 수 x
  • 결함집중(파레토법칙): 20% 모듈에서 80% 결함 발생
  • 오류부재의 궤변: 오류 없는 소프트웨어여도 사용자 요구사항에 부합하면 가치 x

 

[모듈 독립성]

  • 결합도: 모듈 간 상호작용 (낮을수록)
  • 응집도: 모듈 내부의 기능적 결합 정도 (높을수록)

 

[앱 성능 측정]

  • 처리량: 일정 시간 내 앱이 처리하는 일의 양
  • 응답 시간: 앱에 요청 전달 ~ 응답 도착 까지 걸린 시간
  • 경과 시간: 앱에 요청 전달 ~ 처리 완료 까지 걸린 시간
  • 자원 사용률: 앱이 작업 처리하는 동안의 cpu/메모리/네트워크 등 자원 사용률

 

[보안3요소]

  • 기밀성: 보면 안됨
  • 무결성: 바꾸면 안됨
  • 가용성: 인가된 사용자면 언제든 사용

 

[서비스 공격] 

  • Dos: 가용성 떨어뜨림
  • Rainbow table attack: 솔트쳐서 방지

 

[통신 프로토콜]

  • 기본 3요소: 구문, 의미, 타이밍

 

[프로세스 스케줄링]

  • 비선점 스케줄링
  • 선점 스케줄링: 강제 뺏기 가능

 

[트랜잭션 4속성] ACID

  • 원자성: 모두 수행되거나, 모두 안 되거나
  • 일관성: 언제나 일관성 있는 db 상태
  • 독립성: 한 트랜잭션 수행 중에 다른 트랜잭션 접근 불가(독립적)
  • 영속성: 트랜잭션 성공 후 결과 지속적으로 유지돼야 함

 

[데이터 마이닝] 

  • 대규모 저장된 데이터 안에서 가치있는 유용한 정보 찾는 것

 

[암호화 알고리즘]

  • 비밀키(대칭키): DES/AES/ARIA/SEED/IDEA
  • 공개키9비대칭키): RSA/ELGama
  • 해시 알고리즘: SHA/MD5/HAS-16

 

[LOCrlqjq]

  • 총라인수/(명수*300)

 

[생명주기 모델]

  • 나선형: 계획수립-위험분석-공학적개발-고객평가
  • 애자일

 

[soap]

  • Xml 기반 메세지를 컴퓨터 네트워크 상에서 교환하는 프로토콜

 

[형상관리]

  • 형상식별-형상통제-형상감사-형상기록(식통감기)
  • 버전관리 도구

 

[AJAX] - 웹 페이지 전체를 다시 로딩하지 않고 일부분만 갱신할 수 있는 비동기 방식 처리기술

 

[UI 설계원칙] 

  • 직관성: 누구나 쉽게 사용
  • 유효성: 사용 목적 정확히 달성
  • 학습성: 누구나 쉽게 배우고 익힘
  • 유연성: 사용자 요구사항 최대한 수용, 오류 최소화

 

[앱 테스트]

  • 프로그램 실행 여부
  • 테스트 기법
  • 테스트 시각
  • 테스트 목적: 회복/안전/강도/성능/구조회귀병행
  • 테스트 기반: 명세(시간많이걸림)/구조시간많이걸림)/경험

 

[SQL 인덱스]

Create index idx_name on student (name asc)

 

[SQL 인젝션] - SQL 구문 삽입해 서버 db 공격(XSS는 JS 이용)

 

[IPSec] - 네트워크 계층인 ip 계층에서 ip 패킷 단위의 데이터 변조 방지 및 암호화 기능 제공하는 통신 규약

  • AH: 인증, 무결성 보장 위한 프로토콜 
  • ESP: 인증, 무결성, 기밀성 제공

 

[RTO] - 목표 복구 시간 

 

[시멘틱 웹]

  • 의미론적 웹, 문서 의미에 맞게 앱의 의미에 맞게 구성된 웹
  • 컴퓨터가 사람 대신 정보를 읽고, 이해, 가공해 새 정보를 만들 수 있도록 이해하기 쉬운 의미를 가진 차세대 지능형 웹

 

[REST]

  • 자원을 이름으로 구분해 해당자원의 상태를 주고받는 것
  • RESTful: REST 아키텍처 구현 웹 서비스

 

[형상통제] - 소프트웨어 형상 변경 요청을 검토하고 승인해 현재의 베이스라인에 반영될 수 있도록 통제

  • 형상식별-형상통제-형상감사-형상기록

 

[EAI 구축] - 시스템 통합

  • Point to point: 중간에 미들웨어 두지 않고 앱 간 직접 연결
  • Hub % spoke: 단일 접점이 허브 시스템 통해 데이터 전송하는 중앙 집중적 방식
  • Message bus: 앱 사이 미들웨어(버스)를 둬 처리
  • Hybrid: 유연한 통합 작업 가능

 

[ui 설계]

  • 직관성: 누구나 쉽게 이해, 사용할 수 있어야
  • 유효성: 사용자 목적 정확히 달성해야
  • 학습성: 누구나 쉽게 배우고 익힐 수 있어야
  • 유연성: 사용자 요구사항을 최대한 수용하며, 오류 최소화해야

 

[코드 커버리지]

  • 구문 커버리지: 코드 구조 내 모든 구문에 대해 한 번 이상 수행
  • 조건 커버리지: 결정 포인트 내 모든 개별 조건식에 대해 수행
  • 결정 커버리지: 결정 포인트 내 모든 분기문에 대해 수행
  • 조건/결정 커버리지: 결정포인그 T/F 개별 조건식 T/F를 거쳐야 함
  • 변경/조건 커버리지: 모든 결정 포인트 내의 개별 조건식은 적어도 한 번 T, F 를 거쳐야 함
  • 다중 조건 커버리지: 결정 포인트 내 모든 개별 조건식의 가능한 조합을 100% 보장해야 함

 

[SQL-ALTER]

  • 속성 추가: ALTER TABLE 학생 ADD 주소 VARCHAR(20);
  • 속성 변경: ALTER TABLE 학생 MODIFY 주소 VARCHAR(20);
  • 속성 삭제: ALTER TABLE 학생 DROP 주소

 

[스키마] - 데이터베이스의 전체적인 구조와 제약조건에 대한 명세를 기술하고 정의한 것

  • 외부스키마
  • 개념스키마
  • 내부스키마

 

[ICMP] - 인터넷 프로토콜의 비신뢰적 특성 보완 위한 프로토콜

  • Ip 패킷 전송 중 에러 발생 시 원인을 알려주거나 네트워크 상태 진단해주는 기능 제공

 

[라우팅 영역에 따른 분류]

  • IGP: AS 내부 라우터 간 
    • RIP(거리벡터 알고리즘), OSPF(링크상태 프로토콜)
  • EGP: AS 외부 라우터 상호간
    • BGP

 

 

 

<24년 3회 6번>

#include <stdio.h>
int func(){
    static int x = 0;
    x += 2;
    return x;
}

int main() {
    int x = 0;
    int sum = o;
    for(int i = 0; i < 4; i++){
    	x++;
        sum += func();
    }
    printf("%d", sum);
    return 0;
}

정답: 20

 

static 변수는 누적될 수 있습니다. func() 함수의 x는 0, 2, 4, 6, 8이 되고, sum은 0, 2, 6, 12, 20이 됩니다. (main() 함수의 x는 신경쓰지 말자)

 

 

 

<24년 3회 10번>

#include <stdio.h>
struct Node{
    int value;
    struct Node *next;
};

void func(struct Node* node){
    while(node != NULL && node -> next != NULL){
        int t = node -> value;
        node -> value = node -> next -> value;
        node -> next -> value = t;
        node = node -> next -> next;
    }
}

int main(){
    struct Node n1 = {1, NULL};
    struct Node n2 = {2, NULL};
    struct Node n3 = {3, NULL};
    n1.next = &n3;
    n3.next = &n2;
    func(&n1);
    struct Node* current = &n1;
    while(current != NULL){
        printf("%d", current -> value);
        current = current -> next;
    }
    return 0;
}

정답: 312

 

Node라는 구조체를 정의했습니다. 여기서 각 노드는 정수값 value와 다음 노드를 가리키는 포인터 *next를 가지고 있습니다.

func() 함수는 두 개씩 짝지어서 노드들의 value 값을 서로 교환합니다. (첫번째와 두번째, 세번째와 네번째..)

main() 함수에 next가 NULL인 노드 3개가 정의되어 있습니다. 연결 순서가 n1->n3->n2 이므로 연결 리스트는 1->3->2입니다.

func()를 호출 후 node = &n1이므로 n1.value = 2, n3.value = 1이 되고, 다음 노드는 n2이지만 그 다음 n2->next가 없으므로 종료하게 됩니다. 따라서 최종 구조는 3->1->2

 

 

<24년 3회 19번>

#include <stdio.h>
void func(int**arr, int size){
    for(int i = 0; i<size; i++){
    	*(arr+i) = (*(*arr+i)+i)%size;
    }
}

int main(){
    int arr[] = {3, 1, 4, 1, 5}
    int *p = arr;
    int**pp = &p;
    int num = 6;
    func(pp, 5);
    num = arr[2];
    printf("%d", num);
    return 0;
}

정답: 1

 

*(arr+i) = (*(*arr+i)+i)%size 는 arr[i] = (arr[i] + i)%size 와 동일합니다. 따라서 최종 배열은 {3, 2, 1, 4, 4}

 

 

<24년 2회 5번>

#include<stdio.h>
void swap(int a,int b){
    int t= a;
    a = b;
    b = t;
}

int main(){
    int a = 11;
    int b = 19;
    swap(a, b);
    switch(a){
        case 1:
            b += 1;
        case 11:
            b += 2;
        default:
            b += 3
            break;
    }
    printf("%d", a-b);
}

정답: -13

 

쉽게 생각했다간 함정에 빠질 수 있는 문제입니다. swap() 함수를 호출할 때 a, b 변수의 주소를 전달한 것이 아니므로 main() 함수에서의 a, b 변수는 영향을 받지 않습니다.

break문을 만날 때까지 모든 문장이 실행되므로, case 11에서 b=19+2=21, default에서 b=21+3=24이고 break를 만나 멈춥니다.

 

 

<24년 2회 6번>

void func(char *d, char *s){
    while(*s){
        *d = *s;
            d++;
            s++;
    }
    *d='\0';
}

int main(){
    char* str1 = "first";
    char str2[50] = "teststring";
    int result = 0;
    func(str2, str1);
    for(int i = 0; str2[i] != '\0'; i++){
        result += i;
    }
    printf('%d\n", result);
    return 0;
}

정답: 10

 

str2의 내용이 str1의 first로 덮어씌워지고, 따라서 ( f i r s t \0 ) 입니다. 총 5개의 문자이므로 0+1+2+3+4 = 10

 

 

<24년 2회 19번>

int main(){
    int arr[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9}
    int *parr[2] = {arr[1], arr[2]};
    printf("%d", parr[1][1] + *(parr[1]+2) + **parr);
}

정답: 21

 

*(parr[1]+2)는 parr[1] 에 주소 2를 더한 값인 세 번째 열이므로 9, *parr = parr[0]이고 **parr = parr[0][0]이므로 4 입니다.

 

 

포인터란?🖱️

메모리의 주소값을 저장하는 변수입니다. [자료형 * 변수명] 의 형태로 선언하며, 값이 아닌 '값이 저장된 주소'를 가리킵니다.

  • int * p = &a 는, p가 변수 a의 주소를 저장한다는 뜻입니다.
    • &a: a의 주소값을 구함
    • p: 포인터 p 가 가리키는 주소에 있는 값을 의미
  • int * p = &arr[0] 과 int * p = arr 은 같습니다.
  • int * p = &arr[1] 과 int * p = arr[1] 은 다릅니다.
    • &을 붙이지 않으면 주소값이 아닌 두 번째 행 자체를 가리키는 것 

 

예제를 통해 살펴보겠습니다.

#include <stdio.h>

int main() {
    int a = 10;
    int *p = &a;

    printf("a의 값: %d\n", a);       // 10
    printf("a의 주소: %p\n", &a);    // 예: 0x7ffeefbff58c
    printf("p의 값: %p\n", p);       // &a와 같음
    printf("*p의 값: %d\n", *p);     // 10 (p가 가리키는 주소의 값)
    
    *p = 20; // 포인터를 통해 a의 값을 변경
    printf("a의 새로운 값: %d\n", a); // 20
}

a의 값과 a의 주소는 다른 의미입니다. 포인터를 통해 a의 값을 변경할 수 있으며, *p=a, p=&a 입니다. 

 

c언어는 기본적으로 함수에 인자를 넘길 때 복사본이 넘어가는 방식입니다. 이때 포인터를 넘기면 원본을 직접 조작하는 것이 가능해집니다. 

void setToZero(int *p) {
    *p = 0; // 원본 값 변경
}

int main() {
    int a = 10;
    setToZero(&a);  // 주소를 넘김
    printf("%d\n", a);  // 0
}

 

 

20년도에 출제된 기출 예제를 살펴보겠습니다.

void main(){
    char *p = "KOREA";
    printf("%s\n", p);
    printf("%s\n", p+3);
    printf("%c\n", *p);
    printf("%c\n", *(p+3));
    printf("%c\n", *p+2);
}

정답은 아래와 같습니다.

KOREA

EA

K

E

M

 

이중 포인터(double pointer)🖱️

포인터를 가리키는 포인터의 포인터로, 즉 포인터의 주소를 저장합니다. 정보처리기사 시험에서도 나왔던 것으로 기억합니다.

포인터 자체를 조작하거나 변경하기 위해 사용합니다.

 

비슷한 예제를 통해 살펴보겠습니다.

#include <stdio.h>

int main() {
    int a = 10;
    int *p = &a;
    int **pp = &p;

    printf("a의 값: %d\n", a);         // 10
    printf("*p의 값: %d\n", *p);       // 10
    printf("**pp의 값: %d\n", **pp);   // 10

    // 주소 출력
    printf("a의 주소: %p\n", &a);
    printf("p의 값 (a의 주소): %p\n", p);
    printf("p의 주소: %p\n", &p);
    printf("pp의 값 (p의 주소): %p\n", pp);
}

p는 &a를, pp는 &p를 가리키고 있습니다. (pp) --> (p) --> (a) 라고 생각하면 됩니다. 

 

<24년 3회 2번>

def func(lst):
    for i in range(len(lst) // 2):
       lst[i], lst[-i-1] = lst[-i-1], lst[i]

lst = [1,2,3,4,5,6]
func(lst)
print(sum(lst[::2]) - sum(lst[1::2]))

정답: 3

 

리스트를 거꾸로 뒤집고, 리스트 슬라이싱을 실행한 코드입니다. 

리스트 슬라이싱은 리스트[start:stop:step]의 형태를 가집니다. step은 생략 시 기본값이 1입니다.

  • lst[:]: 리스트 전체 복사5
  • lst[::2]: 짝수 인덱스(↔홀수는 lst[1::2])
  • lst[::-1]: 리스트 역순
  • lst[:3]: 앞에서 3개 (↔lst[-3:]: 뒤에서 3개)

 

 

<24년 3회 12번>

def func(value):
    if type(value)==type(100):
    	return 100
    elif type(value)==type(""):
    	return len(value)
    else:
    	return 20

a = "100.0"
b = 100.0
c = (100,20)
print(func(a)+func(b)+func(c))

정답: 45

 

100.0 은 정수형인 100과 다른 자료이므로 else문이 수행되어야 한다. 따라서 5+ 20 + 20

 

 

<24년 2회 3번>

def cnt(str,p):
    result = 0;
    for i in range(len(str)):
    	sub = str[i:i+len(p)]
        if sub == p:
	     result += 1
        return result

str = "abdcabcabca"
p1 = "ca"
p2=  "ab"
print(f'ab{cnt(str,p1)} ca{cnt(str,p2)}")

정답: ab3 ca3

 

ab와 ca가 뒤바뀌어 print되는 함정문제였다. (둘 다 3이 아니었으면 틀린 사람이 꽤 있었을 것) 

 

 

<24년 1회 8번>

a = ['Seoul', 'Kyeonggi', 'Incheon', 'Daejeon', 'Daegu', 'Pusan'];
str01 = 'S'
for i in a:
    str01 = str01 + i[1]
print(str01)

정답: Seynaau

 

i[1]은 'Kyeonggi'라고 착각할 수 있는데, 반복문을 잘 보면 i[1]이란 각 문자의 두 번째 글자를 뜻한다. 

정말 빠르게 지나가버린 3월입니다. 잠깐 눈 감았다 떴는데 한달이 지나버린 기분이랄까요?

첫 출근에 벌벌 떨면서 보안 게이트 앞을 서성이던 날이 엊그제 같은데, 이젠 간식이 채워지는 시간마다 미리 가서 대기를 하고 있는만큼 완벽하게 적응했다고(?) 볼 수 있겠습니다. 😅

버섯 리조또

제가 생각한 카카오 최고 복지는 당연 먹을거리 입니다. 저는 대학생 때도 학식이 싫어서 국밥을 찾아 나섰던 사람인데요? 카카오는 밥이 제 기준으로 너무 맛있고.. 너무 맛있습니다. 나 한달만에 돼지가 되(돼 드립입니다) 🐷

 

 

간식창고는 매일 일정한 시간에 새롭게 채워지는데요, 사실 초반에 정신없이 주워먹었다가 순식간에 체중이 불어버려서 ㅎㅎ.. 요즘은 많이 자제하고 있습니다. 무려 칙촉 한 봉지를 오전 내내 나눠 먹은 인내심도 발휘하고 있음. 🍪 냠 

어시스턴트 분들의 블로그 후기를 읽으면서 과연 잘 적응할 수 있을까 걱정을 많이 했습니다. 다행히 저는 정말 좋은 분들만 계신 팀으로 들어가게 되어서 즐거운 회사 라이프를 보내고 있습니다. 😊 특히 어시스턴트 동기분들이 계셔서 너무 좋습니다.. //// 

 

아지트 1층 빵집 휘낭시에 is GOAT

 

저한테는 사실상 첫 사회 경험인만큼 긴장하면서 2주정도를 보냈던 것 같습니다. 목표했던 회사에서의 경험은 특히 저에게 있어 소중하게 느껴졌고, 특히 팀원 분들께서 많은 이야기를 해주시고, 또 도와주신 덕분에 정말 잘 다니고 있는 것 같습니다. 

 

어쩌다보니 먹는 얘기만 주절주절 하게 되었는데요,

아무튼 앞으로 남은 기간동안 더 빠르게 성장하는 사람이 되었으면 좋겠습니다. 파이팅! 🫡

<24년 3회 1번>

public class Main{
   static String[] x = new String[3];
   static void func(String[] x, int y) {
      for(int i = 1; i < y; i++){
         if(x[i-1].equals(x[i])){
            System.out.print("O");
         }
         else{
            System.out.print("N");
         }
     }
     for (String z : x){
        System.out.print(z);
     }
  }

   public static void main(String[] args){
      x[0] = "A";
      x[1] = "A";
      x[2] = new String("A");
      func(x, 3);
  }
}

답: OOAAA

 

반복변수 i가 1에서 1씩 증가하고, x[i-1]과 x[i]가 같으면 O를, 다르면 N을 호출합니다. 

.equals()를 사용하면 문자열의 내용(값)이 같은지를 비교하는 것이므로 x[0], x[1]과 x[2]는 같은 것

(.equals() 가 아닌 == 을 사용했다면 false였을 것) 

 

 

<24년 3회 14번>

public class Main{
	public static void main(String[] args){
    	B a = new D();
        D b = new D();
        System.out.print(a.getX() + a.X + b.getX() + b.x);
       }
}

class B {
	int x = 3;
    int getX() {
    	return x * 2;
    }
}

class D extends B{
	int x = 7;
    int getX() {
    	return x * 3;
    }
}

정답: 52

 

B a = new D() 에서 클래스 형 변환이 발생했으므로 a.getX()는 B.getX()가 아닌 D.getX()

클래스에서의 형 변환은 메소드에 대해서만 발생(변수는 형 변환 대상 x)하므로 a.x=3

따라서 21 + 3 + 21 + 7 = 52

 

 

<24년 3월 17번> 

public class Main{
	public static void main(String[] args) {
    	int sum = 0;
        try{
        	func();
        }
        catch (NullPointerException e){
        	sum = sum + 1;
        }
        catch (Exception e){
        	sum = sum + 10;
        finally{
        	sum = sum + 100;
        }
        System.out.print(sum);
    }
    static void func() throws Exception{
    	throw new NullPointerException();
    }
 }

정답: 101

 

func() 메소드에서 강제로 NullPointerExeption(Null을 가진 객체를 참조하는 경우 사용하는 예외 객체) 예외를 발생시킵니다. (throw는 강제로 예외를 발생시킵니다)

sum + 1 이후에 try-catch문이 종료되었으므로 finally로 넘어가 + 100을 해줍니다. 

 

 

<24년 3회 18번>

class Printer{
	void print(Integer a){
   		System.out.print("A" + a);
    }
    void print(object a){
    	System.out.print("B" + a);
    }
    void print(Number a){
    	System.out.print("C" + a);
    }
}

public class Main{
	public static void main(String[] args){
    	new Collection<>(0).print();
    }
    public static class Collection<T> {
    	T value;
        public Collection(T t){
        	value = t;
        }
        public void print() {
        	new Printer().print(value);
        }
    }
}

정답: B0

 

오버로딩과 제너릭 기법에 대한 이해가 필요한 문제입니다. 

overloading: print 메소드는 이름은 같고 인수의 자료형이 다르므로 서로 다른 메소드입니다.

Generic: 메소드를 선언할 때 자료형이 정해지지 않고, 생성하거나 호출할 때 정해집니다. (<> 사용)

new Collection<>(0)을 보면 정수를 전달했으므로 T는 integer이지만, 컴파일 과정에서만 유효하고 실행 시에 제거됩니다.

실행 과정에서는 기본 자료형(object) 로 취급되므로 B가 호출됩니다. (T는 자료형, t는 인수이므로 a는 0)

 

 

<24년 2회 1번>

public class Test{
	public static void main(String[] args){
    	String str = "ITISTESTSTRING";
        String[] result = str.split("T");
        System.out.print(result[3]);
    }
}

정답: S

 

T를 기준으로 문자열을 분리합니다. 이 때 분리 기준 문자가 포함되지 x (ST가 아니라 S)

 

 

<24년 2회 2번>

public class Test{
	public static void check(int[] x, int[] y){
    	if(x==y) System.print("O");
        else System.out.print("N");
    }
    
    public static void main(String[] args){
    	int a[] = new int[] {1, 2, 3, 4);
        int b[] = new int[] {1, 2, 3, 4);
        int c[] = new int[] {1, 2, 3};
        check(a,b);
        check(b,c);
        check(a,c);
     }
}

정답: NNN

 

은근히(?) 함정 문제 (b,c랑 a,c 비교하기는 쉽지만 a,b가 헷갈릴 수 있음)

a와 b는 값과 상관없이 주소가 다르므로 서로 다른 객체입니다. 따라서 N

 

 

<24년 2회 7번>

interface Number{
	int sum(int[] a, boolean odd);
}

public class Test{
	public static void main(String[] args){
    	int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        OENumber OE = new OENumber();
        System.out.print(OE.sum(a, true) + "," + OE.sum(a,false));
    }
}

class OENumber implements Number{
	public int sum(int[] a, boolean odd){
    	int result = 0;
        for (int i = 0; i < a.length; i++){
        	if ((odd && a[i] % 2 != 0) || (!odd && a[i] % 2 == 0)){
            	result += a[i];
            }
        }
        return result;
     }
}

정답: 25, 20

 

홀수와 짝수의 합을 구하는 문제이므로 흐름을 외워두면 편합니다. 

class OENumber 는 Number 인터페이스를 상속받습니다.

OE.sum(a, true)는 홀수의 합, OE.sum(a, false)는 짝수의 합 

 

 

<24년 2회 8번>

public class Test{
	public static String rf(String str, int index, boolean[] seen){
    	if(index < 0) return "";
        char c = str.charAt(index);
        String result = rf(str, index - 1, seen);
        if(!seen[c]){
        	seen[c] = true;
            return c + result;
        }
        return result; 
     }
     
     public static void main(String[] args){
     	String str = "abacabcd";
        int len = str.length();
        boolean[] seen = new boolean[256];
        System.out.print(rf(str, len-1, seen));
     }
}

정답: dcba

 

문자열의 중복된 문자를 제거하면서 역순으로 새로운 문자열을 생성하는 재귀 함수 입니다. 

논리형 배열 요소에는 true/false를 저장할 수 있으며, 기본값은 false입니다.

if(!seen[c])문을 통해 해당 문자가 처음 등장했다면 포함하여 반환하고, 이미 본 문자라면 포함하지 않고 반환합니다.

 

 

<24년 1회 1번>

#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[]) {
	int v1 = 0;
    int v2 = 35;
    int v3 = 29;
    if(v1 > v2 ? v2 : v1)
    	v2 = v2 << 2;
    else
    	v3 = v3 << 2;
   	printf("%d", v2 + v3);
    return 0;
}

정답: 151

 

if문을 보면 v1 > v2일 경우 v2를, 그렇지 않을 경우 v1를 조건으로 사용하라고 되어있습니다. 따라서 v1의 값인 0을 조건으로 사용합니다. (조건은 결과가 0이면 false, 나머지는 true)

<<는 왼쪽 시프트 연산자 입니다. 즉, v1 = 0 = 거짓이므로 else로 넘어가고, v3의 값을 왼쪽으로 2비트 이동합니다. 

29 = 11101 에서 2비트 이동하면 1110100 = 116 = v3이 됩니다.

코드를 끝까지 읽어야 하는게, v3이 답이 아닌 v2+v3이 답이므로 35 + 116 = 151 이 답입니다.

(문제를 끝까지 안 읽고 답을 적었다가 점수를 잃는 상황이 종종 발생함) 

 


<24년 1회 5번>

class Connection{
    private static Connection _inst = null;
    private int count = 0;
    public static Connection get(){
    	if(_inst == null){
        	_inst = new Connection();
            return _inst;
        }
        return _inst;
     }
     public void count() {count++;}
     public int getCount() {return count;}
}

public class Test{
	public static void main(String[] args){
    	Connection conn1 = Connection.get();
        conn1.count();
        Connection conn2 = Connection.get();
        conn2.count();
        Connection conn3 = Connection.get();
        conn3.count();
        conn1.count();
        System.out.print(conn1.getCount());
     }
}

정답: 4

 

connection 클래스에 싱글톤 패턴이 적용되었습니다. 즉, 객체변수 _inst가 사용하는 메모리 공간을 객체 변수 conn1~conn3이 공유하고 있습니다. _inst가 null이면 새로운 connection 객체를 생성하고 반환하며, null이 아닌 경우 기존 인스턴스를 반환합니다.

count() 메서드 호출 시 값이 증가하며, 최종적으로 4가 출력됩니다.

 


<24년 1회 11번>

class Parent {
	int x, y;
    
    Parent(int x, int y){
    	this.x = x;
        this.y = y;
    }
    int getX() {
    	return x*y;
    }
}

class Child extends Parent{
	int X;
    
    Child(int x){
    	super(x+1, x);
        this.x = x;
    }
 	int getX(int n){
    	return super.getX() + n;
    }
}

public class Main{
	public static void main(String[] args){
    	Parent parent = new Child(10);
        System.out.println(Parent.getX());
    }
}

정답: 110

 

Child 클래스가 Parent 클래스를 상속하며, this.x = x;가 실행되어 부모 클래스의 x를 다시 덮어씌웁니다. getX(int n)에서 부모의 getX() 값에 n을 더해 반환하며, Parent.getX()를 호출하므로 11*10 (main 메서드에선 hetX(int n)을 호출하지 않고 getX()를 호출)

아무 생각 없이 120이라고 적었다가 틀린 문제 😅

 


<24년 1회 18번>

class firstArea{
    int x, y;
    public firstArea(int x, int y){
    	this.x = x;
        this.y = y;
    }
 	public void print(){
    	System.out.println(x+y);
    }
 }
 
 class secondArea extends firstArea{
    int bb = 3;
    public secondArea(int i){
    	super(i, i+1);
    }
    public void print(){
    	System.out.println(bb*bb);
    }
}

public class Main{
	public static void main(String[] args){
    	firstArea st = new secondArea(10);
        st.print();
    }
}

정답: 9

 

마찬가지로 상속의 개념이 잘 잡혀있지 않으면 헷갈릴 수 있는 문제입니다. secondArea 클래스의 생성자를 이용해 firstArea클래스의 객체 변수 st를 선언했으므로, 클래스 형 변환이 발생한 것이며 이 때 자식클래스인 secondArea의 print() 메소드가 수행됩니다.

 

문제: https://school.programmers.co.kr/learn/courses/30/lessons/12906

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

<문제 설명>
배열 arr가 주어집니다. 배열 arr의 각 원소는 숫자 0부터 9까지로 이루어져 있습니다. 이때, 배열 arr에서 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하려고 합니다. 단, 제거된 후 남은 수들을 반환할 때는 배열 arr의 원소들의 순서를 유지해야 합니다. 예를 들면,arr = [1, 1, 3, 3, 0, 1, 1] 이면 [1, 3, 0, 1] 을 return 합니다.arr = [4, 4, 4, 3, 3] 이면 [4, 3] 을 return 합니다.배열 arr에서 연속적으로 나타나는 숫자는 제거하고 남은 수들을 return 하는 solution 함수를 완성해 주세요.

 

내 풀이

def solution(arr):
    answer = []
    for i in range(len(arr) - 1):  
        if arr[i] != arr[i + 1]:  
            answer.append(arr[i]) #뒷숫자와 다른 경우 apppend
    answer.append(arr[-1])  #마지막 원소 추가
    return answer

 

반복문이 끝나면 마지막 하나의 문자가 남아있기 때문에 반드시 추가해주어야 한다. 

문제: https://school.programmers.co.kr/learn/courses/30/lessons/42576

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

<문제 설명>
수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.
마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

 

내 풀이

정확성 테스트 성공 / 효율성 테스트 실패

def solution(participant, completion):
    cnt = 0
    for i in completion:
        participant.remove(i)
    answer = participant[0]
    return answer

 

for문과 remove를 사용해 제거하고자 했으나 시간 초과로 테스트 실패

 

Hash 이용 풀이

해시 함수(Hash Function) - 임의의 값을 고정된 길이의 데이터로 변환하는 함수

def solution(participant, completion):
    participant.sort()
    completion.sort()
    
    for i in range(len(completion)):
        if participant[i] != completion[i]:
            return participant[i]
    return participant[-1]

 

우선 정렬해주고, 두 리스트를 비교해 맞지 않는 이름을 찾아낸다. 순서가 모두 맞을 경우 맨 뒤의 남은 이름 1개를 return 하는 방식

검은사막으로 유명한 펄어비스에서 [ 2025 펄어비스 테크 인턴십] 이 열렸고, 저는 DBA 직무에 지원하였습니다. 

사실 직무 중에서 제 경험이나 역량들과 정확히 맞아떨어지는 직무는 없었기 때문에, 그나마 가장 승산이 있다고 생각한 직무에 지원하게 되었습니다.


서류 

서류는 포트폴리오 + 자기소개서를 제출해야 했습니다. 개인적으로 좋았던 점은, 최종합격하지 않은 자격증도 기재가 가능했다는 사실입니다. 유명한 자격증 찍먹러인 저에게는 1차 합격만 해둔 자격증이 3개나 있었기 때문입니다. ㅎㅎ 

 

우선 저는 검은사막이라는 게임에 대해서 잘 몰랐기 때문에, 무작정 깔아서 3일 내내 게임을 벼락치기 해봤습니다. 🤫

그렇지만 평소 다른 게임을 즐겨 하였기 때문에, 검은 사막을 경험하면서 느꼈던 점과 더불어 게임에 대한 열정이나 관심을 잘 보여주고자 노력했습니다. 

 

가장 어려웠던 문항은 '본인의 성장과정을 작성해 주세요.' 였습니다. 너무 어렸을 때의 경험을 적는게 독이 될수도 있다고 생각했지만, 개인적으로 제가 꼭 말씀드리고 싶었던 과거의 경험들이 있었기 때문에 저는 초등학교 시절부터의 이야기를 담았습니다. 

(아마 좋은 방법은 아닌 것 같습니다.) 

제가 왜 이런 사람으로 성장하게 되었는지, 포인트가 될 경험을 3개정도 키워드로 잡아두고 작성했습니다. 

 

게임을 좋아할 뿐이지, 게임 관련 프로젝트 경험은 하나도 없었습니다. 그래서 포트폴리오에 넣어둔 프로젝트도 굉장히 무관해보였습니다. 제 생각엔 자소서를 좋게 봐주신 덕분에 + DBA와의 연관성을 억지로(?)라도 맞추고자 노력한 덕분에 서류에서 합격할 수 있었다고 생각합니다. 아니면 그냥 서류 배수가 높았던 것일지도,,? 😅

 

 


코딩테스트

코딩테스트는 알고리즘 + SQL + CS 객관식 + CS 서술형으로 이루어져 있었습니다. 😅

아마 제가 봤던 2차 전형 중에서 가장 특이했던 것 같은데, 인적성 설문(서술형), 인성 검사 (객관식), Culture Fit 검사를 모두 치뤄야 했기 때문입니다. 기억하기로는 각각 시간도 꽤나 걸렸던 것 같습니다. 

 

코테 난이도는 상,중,하 중에서는 중 정도에 속한다고 생각합니다. 그렇지만 CS 서술형 문제가 꽤 까다로웠습니다. 

저는 개인 사정으로 시험을 준비하지 못해서 불합격 했습니다. 그렇지만 코테를 꾸준히 준비하신 분들이라면, 추가로 CS 공부만 조금 더 해가신다면 충분히 통과하실 수 있을거라고 생각합니다! 

 

함께 취뽀합시다. 파이팅! 👊

 


 

+ Recent posts