반응형

https://developer.android.com/topic/libraries/view-binding

 

뷰 결합  |  Android 개발자  |  Android Developers

뷰 결합 뷰 결합 기능을 사용하면 뷰와 상호작용하는 코드를 쉽게 작성할 수 있습니다. 모듈에서 사용 설정된 뷰 결합은 모듈에 있는 각 XML 레이아웃 파일의 결합 클래스를 생성합니다. 바인딩

developer.android.com

Fragment에서 ViewBinding을 사용할 경우 메모리 누수(Memory leak)를 조심해야 합니다.

그 이유를 Fragment의 생명주기와 함께 알아봅시다.

 

먼저, Fragment의 생명주기를 보면 다음과 같습니다.

Fragment Lifecycle

위 Fragment의 생명주기를 보면 onCreate 이후에 onCreateView가 호출되는 것을 알 수 있습니다.

onCreate는 Fragment가 생성될 때 호출되며, onCreateView는 Fragment의 뷰를 구성할 때 호출됩니다.

 

즉, onCreate는 아직 화면이 보이지 않은 상태(View가 생성되지 않은 상태)에서 실행되고

onCreateView는 화면(뷰)을 구성할 때 실행됩니다.

 

그럼 반대로, Fragment을 닫을때는 View를 먼저 닫고 Fragment를 닫아야 하겠죠? ( 괄호를 먼저 열고 늦게 닫는 개념 )

그래서 onDestroyView가 호출된 후에 onDestroy가 호출됩니다.

 

따라서, Fragment는 View 보다 생명주기가 오래 지속되게 됩니다.

 

이 내용을 기억한 상태로, 다음 코드를 봅시다.

    private var _binding: ResultProfileBinding? = null
    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = ResultProfileBinding.inflate(inflater, container, false)
        val view = binding.root
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

위 코드의 onCreateView에서 binding을 선언하여 뷰를 결합함으로써 view에 대한 reference를 참조하게 됩니다.

이 때, 만약 Fragment A에서 Fragment B로 전환이 된다면

Fragment A의 View는 사라지게 되지만 Fragment A는 아직 종료되지 않은 상태로 남게 됩니다.

그래서 Fragment는 binding변수를 계속 갖고있는 상태로 view에 대한 reference를 참조하고 있게 됩니다.

 

즉, Fragment A의 View요소들은 쓰이지 않음에도 불구하고 아직 view에 대한 reference가 남아 있기 때문에

메모리 누수가 발생하게 됩니다.

 

그래서 이를 방지하기 위해 바로 아랫 부분의 onDestroyView에서 binding변수를 null로 만들어 view에 대한 reference의 참조를 해제해 주는 겁니다.

 

위의 설명이 바로 상단의 안드로이드 공식 문서 링크에 나와있는 설명인

"프래그먼트는 뷰보다 오래 지속됩니다. 프래그먼트의 onDestroyView() 메서드에서 결합 클래스 인스턴스 참조를 정리해야 합니다." 입니다.

 

따라서, Fragment에서 ViewBinding을 사용할 때는

메모리누수를 방지하기 위해 위의같이 onDestroyView에서 binding을 null로 만들어 참조를 해제해주는 습관을 가지는 것이 좋습니다.

 

 

 

이 방법 외에도, Binding 사용시 메모리 누수를 방지하는 것에 대한 여러가지 방법이 있지만

오늘은 위와 같은 방법을 소개를 드렸습니다.

 

안드로이드 개발에 관련한 사항들은 github에도 주기적으로 업로드 하니 언제나 팔로우&맞팔은 환영입니다!

https://github.com/HongEunho/

반응형
반응형

https://www.acmicpc.net/problem/1912

 

1912번: 연속합

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

문제 설명

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.


풀이 과정

이 문제는 DP(다이나믹 프로그래밍)을 이용해 최댓값을 찾는 문제이다.

 

DP라는 리스트(배열)의 각 칸에는 그 칸까지 숫자들을 고려했을 때의 연속합의 최댓값을 담을 것이다.

예를 들어, DP[2]는 2번째 인덱스 까지의 숫자를 고려했을 때의 최댓값이 저장될 것이다.

 

이 때, 만약 이전 인덱스 까지의 연속합이 음수라서 이전까지의 합에 현재 수를 더하는 것 보다

현재 수 만을 갖고있는게 더 큰 경우에는

이전까지 연속합을 끊어내고 현재 인덱스부터 새로운 구간합을 만들어가야 한다.

 

이러한 부분들을 고려하여 작성한 파이썬 코드는 다음과 같다.

n = int(input())
nums = list(map(int, input().split()))

INF = -int(1e9)
dp = [INF]*n

if n<2:
  dp[0] = nums[0]

else:
  dp[0] = nums[0]
  dp[1] = max(nums[1], dp[0]+nums[1])
  for i in range(2, n):
    dp[i] = max(dp[i-1]+nums[i], nums[i])

print(max(dp))

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

오늘은 안드로이드 개발 언어 중 하나인 코틀린의 기초 문법중

Scope Function에 대해 알아보겠습니다.

 

그리고 이 Scope Function을 자바와 비교하여

자바와 코틀린 코드간의 차이점을 알아보고, 어떻게 사용하는지 알아보겠습니다.

 

Scope Function

  • 코틀린 표준 라이브러리에서 제공하는,
  • 객체의 Context 내에서 코드 블럭을 실행하는 것을 목적으로 만든 함수
  • let, run, with, apply, also 의 5가지가 존재
  • let, run, with는 람다식의 결과를 반환하며
  • apply, also는 컨텍스트 객체를 반환한다.

let

let() 함수는 호출한 객체를 이어지는 함수 블록의 인자로 전달한다.

그리고 그 함수 블록의 결과를 반환한다.

그래서 주로 객체 결과값에 함수를 호출하는 경우에 사용한다.

val sumNumberStr = number?.let{
    "${sum(10, it)}"
}.orEmpty()

위의 코드처럼, number 객체에 sum함수를 호출하여 sum의 결과값을 반환한다.

 

scope함수를 이용하지 않은 자바 코드의 경우 다음과 같다.

Integer number = null;
String sunNumberStr = null;
if (number != null){
    sumNumberStr = "" + sum(10, number);
} else{
    sumNumberStr = "";
}

두 코드를 비교해보면, 확실히 가독성 측면에서 차이가 있다.

scope함수를 이용하면 연관된 코드를 블럭안에 묶음으로써 가독성을 높일 수 있고,

유효범위를 명확히 알 수 있게 된다.

또한 nullable에 대한 처리로 인해 안전성 또한 높일 수 있다.

 

run

run() 함수는 변수를 넣고 변수로 반환값을 바로 얻고싶을 때 주로 사용한다.

val width = run{
    val point = Point()
    point.x * 0.5
}

 

만약, scope함수를 이용하지 않고 자바 코드로 구현을 하게 되면

아래와 같은 코드가 탄생할 것이다.

Point point = new Point()
int width = point.x * 0.5

 

let함수는 또한 복잡한 계산을 할 때, 다음과 같이 블록 내에 임시변수가 필요할 때 사용하기도 한다.

val result = run {
    val defaultPadding = TypedValue.applyDimension(...)
    val extraPadding = TypedValue.applyDimension(...)
  
    defaultPadding + extraPadding
}

 

with

with() 함수는 인자로 받는 객체를 이어지는 함수 블록의 리시버로 전달한다.

즉, 함수에서 사용할 객체를 매개변수를 통해 전달받는 형태이다.

val person = Person()
with(person){
    work()
    sleep()
    println(age)
}

 

with함수를 사용하지 않은 자바코드는 아래와 같다.

Person person = new Person();
person.work();
person.sleep();
System.out.println(person.age);

 

apply

apply() 함수는 이 함수를 호출한 객체를 이어지는 함수 블록의 리시버로 전달한다.

객체를 반환하기 때문에 주로 객체 초기화에 사용한다.

val person = Person().apply {
    firstName = "Eun Ho"
    lastName = "Hong"
}

 

scope함수를 사용하지 않은 자바 코드는 다음과 같다.

Person person = new Person();
person.firstname = "Eun Ho";
person.lastname = "Hong";

 

also

also() 함수는 기존 객체를 변경하지 않기 때문에

주로 데이터의 유효성을 확인하거나 디버깅을 할 때 사용한다.

Random.nextInt(100).also{
    print("getRandomInt() generated value $it")
}

 

also함수를 사용하지 않은 자바 코드는 다음과 같다.

int value = Random().nextInt(100);
System.out.print(value);

 


오늘은 이렇게 코틀린의 Scope Function인

let, run, with, apply, also 와, 이들의 사용의도와 방법을 자바코드와 비교하여 알아보았습니다.

 

긴 글 읽어주셔서 감사합니다.

반응형
반응형

오늘은 오라클 DB의 테이블을 변경하는 방법에 대해 알아보겠습니다.

 

테이블을 변경할 때는

ALTER TABLE 라는 명령어를 사용하게 됩니다.

 

ALTER TABLE [테이블명] 이 기본 구조이고

그 뒤에, 컬럼을 수정하거나 삭제하느냐에 따라 MODIFY 명령어를 붙이느냐, ADDDROP 등을 붙이느냐가 달라집니다.

 

그럼 하나씩 차례대로 알아봅시다!

 

테이블 컬럼 추가

먼저 테이블에 컬럼을 추가하는 방법입니다.

추가는 ADD 명령어를 이용하여 다음과 같이 작성하면 됩니다.

 

ALTER TABLE [테이블명] ADD 컬럼명 데이터타입(길이);

ALTER TABLE User ADD USER_ID VARCHAR2(15);

위 예시는 User라는 테이블에 USER_ID라는 컬럼을 VARCHAR2(15) 타입으로 설정하여 추가한 쿼리입니다.

 

테이블 컬럼 수정

테이블의 컬럼을 수정할 때에는

MODIFY 명령어를 이용하여 다음과 같이 작성합니다.

 

ALTER TABLE [테이블명] MODIFY [컬럼명] [데이터타입(길이)];

 

이 때, 컬럼의 데이터 타입을 변경할건지, 아니면 컬럼의 길이를 변경할건지에 따라

각각 상황에 맞게 입력해주면 됩니다.

 

ALTER TABLE User MODIFY User_NAME VARCHAR2(10);

위 예시는 User 테이블의 User_NAME 컬럼의 데이터타입을 VARCHAR2로 길이는 10으로 변경한 쿼리 입니다.

 

테이블 컬럼명 변경

테이블의 컬럼명을 변경할 때에는

RENAME COLUMN 명령어를 이용하여 다음과 같이 작성합니다.

 

ALTER TABLE [테이블명] RENAME COLUMN [변경전 컬럼명] TO [변경후 컬럼명];

ALTER TABLE User RENAME COLUMN User_Password TO User_Pw;

위 예시는 User 테이블의 User_Password 라는 컬럼의 이름을 User_Pw로 변경한 쿼리입니다.

 

테이블 컬럼 삭제

테이블의 특정 컬럼을 삭제하고 싶을 때에는

DROP COLUMN 명령어를 이용하여 다음과 같이 작성합니다.

 

ALTER TABLE [테이블명] DROP COLUMN [삭제할 컬럼명];

ALTER TABLE User DROP COLUMN User_Name;

위 예시는 User 테이블에 존재하는 User_Name이라는 컬럼을 삭제하는 쿼리입니다.

 

컬럼 기본값 및 NULL 설정 변경

컬럼의 기본값이나 Null 설정을 변경할 때에는

컬럼을 수정할 때와 마찬가지로 MODIFY 명령어를 사용하게 됩니다.

 

[테이블 기본값 설정]

ALTER TABLE User MODIFY User_NAME VARCHAR2(15) DAFAULT 'KIM';

 

[테이블 기본값 삭제]

ALTER TABLE User MODIFY User_NAME DEFAULT NULL;

 

 

[테이블 NOT NULL 설정]

ALTER TABLE User MODIFY User_id VARCHAR(10) NOT NULL;

 

[테이블 NOT NULL 제거]

ALTER TABLE User MODIFY User_id VARCHAR2(10) NULL;

 

[기본값 + NULL 설정]

ALTER TABLE USER MODIFY User_id VARCHAR2(10) DEFAULT 'kim' NOT NULL;

 

주의사항

위의 방법대로 컬럼의 길이(크기)를 변경한다거나, 데이터 타입을 변경할 때 오류가 발생할 수 있습니다.

 

① 컬럼의 크기를 변경하는 경우에는,

기존 데이터 중 바꿀 크기보다 큰 데이터가 있다면 오류가 발생할 수 있는데

이 때는 그러한 데이터가 있는지 확인을 하고 바꾸어야 합니다.

 

[바꿀 크기가 10인데 10보다 큰 데이터가 있는지 확인하는 쿼리]

SELECT * FROM User
WHERE length(User_Name) > 10;

 

 

② 데이터 타입을 변경하는 경우에는,

해당 컬럼의 데이터를 모두 비워야 변경이 가능합니다.

 

그러기 위해서는,

임시로 temp컬럼을 하나 생성해준 다음

temp컬럼에 잠시 데이터를 옮겨놓고

원래 컬럼의 데이터를 모두 비운 후에 데이터 타입을 변경하고

temp컬럼의 데이터들을 다시 원래 컬럼으로 옮겨주면 됩니다.

 

 

오늘은 이렇게 오라클 테이블을 수정하는 방법에 대해 알아보았습니다.

 

테이블을 생성하고 나면 중간에 테이블을 변경해야 할 일이 많을텐데,

이러한 방법을 잘 숙지하셨다가 수정하시면 좋을 것 같습니다.

 

오늘도 긴 글 읽어주셔서 감사합니다.

반응형
반응형

오늘은

SQL에서 테이블 생성과 생성후에 기본키를 지정하고, 코멘트를 붙이는 방법에 대해 알아보겠습니다.

 

먼저, 테이블을 생성하는 기본적인 구성과 방법에 대해 알아보겠습니다.

 

테이블 생성

먼저, 명령어와 구성은 다음과 같습니다.

Create TABLE 테이블명
(
	컬럼명1	데이터타입		기본값(생략O) 	NULL여부(생략O)
    	컬럼명2	데이터타입		기본값(생략O)	NULL여부(생략O)
        ...
 );

컬럼명에는 컬럼 이름을 입력하면 되고,

데이터타입에는 NUMBER(4), VARCHAR2(10), int, DATE 등의 데이터 타입을 입력합니다.

기본값에는 DEFAULT 100과 같이 기본값으로 지정해줄 값을 입력하면 되며(생략가능)

NULL여부에는 NOT NULL과 같이 NULL 허용 여부를 지정합니다(기본은 NULL허용이며 생략시 NULL 허용)

 

 

그럼 위의 방법을 이용해 테이블을 한번 생성해봅시다!

CREATE TABLE User
(
	id		int			not null,
        name	VARCHAR2(10),
        nickname	VARCHAR2(10),
        age		int,
        address 	char(25)
 );

위 코드는

User라는 이름의 테이블을 생성한 것이며

컬럼은 id, name, nickname, age, address로 구성되어 있습니다.

 

id의 자료형은 int형이고 null을 허용하지 않습니다. 기본값은 입력하지 않았으므로 기본값 입력은 되지 않습니다.

name의 자료형은 VARCHAR2(10)이고 기본값은 X, NULL은 허용 입니다.

아래 자료형들도 마찬가지로 구성되어 있습니다.

 

 


기본키 추가

이렇게 테이블을 생성하고 나면, PK(Primary Key 기본키) 구성을 해야합니다.

 

기본키를 구성하는 방법에는 두가지가 있습니다.

① 따로 제약조건으로 추가하는 방법(ALTER)

② 테이블 생성시 지정하는 방법(CREATE TABLE)

 

먼저, 따로 제약조건을 주어 지정하는 방법을 알아보겠습니다.

 

기본적인 명령어는 다음과 같습니다.

ALTER TABLE [테이블명] ADD CONSTRAINT [제약조건명] PRIMARY KEY ([컬럼명1,컬럼명2...])

 

이를 위의 테이블에 적용하면 다음과 같이 작성할 수 있습니다.

ALTER TABLE USER ADD CONSTRAINT pk_id PRIMARY KEY(id)

 

 

이번에는 테이블 생성시 지정하는 방법입니다.

 

다음과 같이 기본키로 지정하고자 하는 컬럼의 뒤에 primary key를 붙일 수도 있고

CREATE TABLE User
(
	id		int			not null	primary key,
        name	VARCHAR2(10),
        nickname	VARCHAR2(10),
        age		int,
        address 	char(25)
 );

 

다음과 같이 

CONSTRAINTS [제약조건명] PRIMARY KEY(컬럼명1, 컬럼명2...) 으로 설정하는 방법이 있습니다.

CREATE TABLE User
(
	id		int			not null,
        name	VARCHAR2(10),
        nickname	VARCHAR2(10),
        age		int,
        address 	char(25),
        CONSTRAINTS pk_id PRIMARY KEY(id)
 );

코멘트 생성

이번에는 코멘트를 지정하는 방법에 대해 알아보겠습니다.

코멘트는 말 그대로, 부가 설명에 해당합니다.

 

내가 만든 테이블이나 컬럼에 대해 부가설명을 붙이고 싶을 때 사용하며 필수는 아닙니다.

 

기본적인 명령어 구성은 다음과 같습니다.

COMMENT ON TABLE [테이블명] IS '코멘트';

COMMENT ON COLUMN [컬럼명] IS '코멘트';

 

이를 실제에 적용해보면,

COMMENT ON TABLE USER IS '회원정보';
COMMENT ON COLUMN User.id IS '회원아이디';

이렇게 각각 테이블과 컬럼에 적용할 수 있습니다.

 

오늘은 이렇게 테이블의 생성과 기본키 지정, 그리고 코멘트 작성방법 까지 알아보았습니다.

다음에는 테이블의 수정/삭제 및 인덱스에 대해 알아보겠습니다.

 

긴 글 읽어주셔서 감사합니다!

https://github.com/HongEunho

 

HongEunho - Overview

📖 Android, Java, Kotlin, Algorithm, Clean Architecture - HongEunho

github.com

 

반응형
반응형

웍스모바일 하계 인턴 채용공고

 

2021년 7월부터 8월까지 웍스 모바일(네이버 웍스)에서 채용연계형 인턴십을 진행했습니다.

그래서 인턴 과정에 대한 전체적인 내용을 적어보려 합니다.

 

1. 서류 전형

1 [필수문항] 자신에 대해 자유롭게 표현해 주세요.

=> 이 항목은 저의 가치관을 개발에 접목시켜 작성했습니다.

아무래도 개발자를 뽑는 공고인 만큼, 개발과 연관하여 소개하는 것이 좋을 것 같다고 생각했다.

 

2 [필수문항] 자신의 기술력과 열정을 보여줄 수 있는 활동사항을 기재해 주세요.

=> 개인 토이 프로젝트와 학부때 진행했던 프로젝트들, 동아리 활동 위주로 적었습니다.

특히 저는 안드로이드 부문으로 지원했기 때문에 안드로이드 관련 활동 위주로 적었습니다!

 

3 [필수문항] Works Mobile에서 제공하는 서비스(기업 대상의 그룹웨어 웍스모바일, 네이버 개인화 서비스 - 메일/캘린더/주소록/클라우드 등)에 대해 알고 있는지, 사용해 본 경험이 있다면 어떤 장단점이 있다고 느꼈는지 기재해 주세요. (경쟁 서비스와의 비교도 OK)

=> 아무래도 네이버웍스 앱을 직접 사용해본 경험이 없다보니, 직접 스토어에서 설치해서 사용도 해보고 후기 관련 글들을 찾아보면서 정리했던 것 같습니다.

 

4 [필수문항] 본인이 보유한 Programming Skill의 활용정도를 모두 적어주세요. (고급/중급/초급)

[작성예시 : C - 중급 Java - 고급 Linux 커맨드 및 개발환경 - 고급 Shell Scripting - 초급 Android - 중급 Javascript - 중급]

=> 본인의 활용정도를 솔직하게 적으면 될 것 같아요.

 

5 [필수문항] 자신이 앞으로 어떤 개발 분야에서 성장하고 싶은지, 그렇게 생각한 이유와 성장을 위해 한 노력을 포함하여 기술해주세요.

=> 제가 개발자를 꿈꾸게 된 이유를 시작으로 스토리를 써내려 갔습니다. 특히, 어떤 분야에서 어떤 개발을 하고 싶은지 구체적으로 적은 것 같아요.

 

6 [필수문항] 아래 리스트 중에서 본인이 지금까지 수강한 과목이 있다면 해당 과목에서 받은 학점을 모두 기재해 주세요.

(자료구조, 알고리즘, 운영체제, 데이터베이스, 컴퓨터 네트워크, 소프트웨어 엔지니어링)

[작성예시 - 자료구조론 : A+ , 운영체제 : B-]

=> 저는 전공자였기 때문에 학교에서 들었던 전공 수업들을 적고 학점을 솔직하게 적었습니다.

 

그리고 이렇게 서류전형 합격을 하였습니다!


2. 코딩테스트

코딩테스트는 네이버 신입공채의 코딩테스트 보다는 쉬운 수준이었습니다.

당시 기억으로는 마지막 문제 빼고는 수월하게 풀 수 있는 수준이었고, 마지막 문제가 좀 어렵게 나왔던 것 같습니다.

(비슷한 문제가 백준 골1~플레4 정도에 있었습니다.)

 

평소에 코딩테스트 준비를 열심히 하셨다면 충분히 푸실 수 있을 거라고 생각합니다!

그리고 이렇게 코딩테스트 합격을 하게 되었습니다!

 


3. 화상 면접

면접은 네이버 웍스를 통해 진행했습니다.

자사에서 직접 개발한 네이버 웍스의 화상회의를 통해 진행한 것이 조금 신기하기도 하고 놀랍기도 했습니다.

 

면접은 1시간 가량 진행되었고,

전반적인 CS 지식과 자기소개서 기반의 질문, 안드로이드 관련 질문, 그리고 창의성 질문으로 진행되었습니다.

 

CS는 기초적인 자료구조부터 알고리즘 문제, 데이터베이스 등 다양한 부분으로 출제가 되었고

자기소개서는 저의 자기소개서를 바탕으로 질문이 들어왔습니다.

그리고 저는 안드로이드 부분을 지원했기 때문에 안드로이드 관련 질문이 들어왔습니다.

마지막으로 창의성 테스트 같은 문제가 나왔습니다.

 

그리고 면접 결과는...

이렇게 합격을 하게 되었습니다!

그리고 7월 초부터 약 두달간 인턴십을 진행하게 되었습니다!


4. 인턴

인턴은 코로나 때문에 전 기간 전면 재택으로 진행되었습니다.

인턴 시작 전에 장비들을 집으로 보내주셨습니다. (장비는 정말 좋은 것들로 잘 보내주셨습니다...ㅎㅎ)

 

약 2달간 저는 안드로이드 관련 프로젝트를 진행했습니다.

처음 1주는 앞으로 사용하게 될 기술 스터디를 진행하였고

후에 2주는 설계를 진행하였습니다.

그리고 나머지 4주는 개발 및 테스트를 진행하였고

마지막 1주는 평가를 진행하였습니다.

 

① 설계

설계는 시퀀스 다이어그램과 ER 다이어그램, 마일스톤을 작성하면서 진행하였습니다.

저는 인턴을 진행하면서 시퀀스 다이어그램을 처음 그려봤는데... 처음이다 보니 많이 헤맸습니다.

하지만 아무래도 정해진 기간안에 설계를 끝내야 하다보니.. 시간분배를 잘 하셔야 합니다!

 

그래서 저는 미리 시퀀스 다이어그램에 대해서 공부하시고 가시는 것을 추천드립니다!

 

② 개발 및 테스트

개발 패턴은 MVVM 패턴을 사용했고 Coroutine, Dagger2, AAC, Unit/UI Test 등 다양한 기술스택들을 사용했습니다.

사실 MVVM 패턴이 무엇인지는 알고 있었지만, 인턴을 진행하면서 처음 공부하다보니 많이 어려움을 느꼈습니다.

뿐만 아니라, 기술 스택들의 난이도가 조금 있다보니... 순탄하지가 않았던 것 같습니다 ㅠㅠ

 

특히 Dagger2는 난이도가 정말 어려웠고 실제 프로젝트 기간중에서도 가장 많이 공부하며 시간을 보낸 것 같습니다.

 

③ 평가 및 발표

마지막 1주는 발표와 평가를 진행했습니다.

평가와 발표 또한 모두 비대면 온라인으로 진행되었습니다.

뿐만 아니라 마지막날 팀 회식(?)겸 쫑파티를 했는데 이것 마저도 온라인으로 진행되었습니다 ㅋㅋㅋ


5. 전환 및 발표

인턴 종료 후 약 2주 정도 후에 전환 심사 결과가 발표되었습니다.

코로나 때문인지 전환 면접은 따로 진행하지 않았습니다!

 

저는 아쉽게도 전환에 성공하지는 못했습니다.

 

하지만 인턴기간 동안 정말 많은 것들을 배웠고, 저 또한 정말 많이 성장했다고 느꼈습니다.

또한 이 때의 경험을 발판삼아 이후에 더 열심히 준비한 끝에

 

하반기에 더 좋은(?) 회사에 취업을 하게 되었고

글을 쓰는 현 시점에, 다음주 입사를 앞두고 있습니다!

 

이 글을 보시는 분들이라면, 웍스 모바일 인턴을 준비중이거나 인턴십을 진행중이신 분들이 많으실텐데

모두 열심히 준비하셔서 잘 되셨으면 좋겠습니다!

 

긴 글 읽어주셔서 감사합니다!

반응형
반응형

문제 설명

https://www.acmicpc.net/problem/11054

 

11054번: 가장 긴 바이토닉 부분 수열

첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)

www.acmicpc.net

수열 S가 어떤 수 Sk를 기준으로 S1 < S2 < ... Sk-1 < Sk > Sk+1 > ... SN-1 > SN을 만족한다면, 그 수열을 바이토닉 수열이라고 한다.

예를 들어, {10, 20, 30, 25, 20}과 {10, 20, 30, 40}, {50, 40, 25, 10} 은 바이토닉 수열이지만,  {1, 2, 3, 2, 1, 2, 3, 2, 1}과 {10, 20, 30, 40, 20, 30} 은 바이토닉 수열이 아니다.

 

수열 A가 주어졌을 때, 그 수열의 부분 수열 중 바이토닉 수열이면서 가장 긴 수열의 길이를 구하는 프로그램을 작성하시오.


풀이 과정

이 문제는 이 문제의 하위버전인 가장 긴 증가하는 부분수열 문제(https://www.acmicpc.net/problem/11053)를 풀었다면 쉽게 접근할 수 있는 문제이다.

 

먼저, 길이 10짜리 수열을 보자.

1 5 2 1 4 3 4 5 2 1

일단은, 감소하는 부분은 생각하지 말고 인덱스별로 증가하는 부분만을 생각해보자.

5는 1 -> 5 로 증가하기 때문에 길이 2짜리 부분수열이며

2는 1 -> 5 -> 2 가 될 수 없기 때문에 1 -> 2 로 2이다.

1은 증가할 수 없기 때문에 1이며

4는 1 -> 2 -> 4 이기 때문에 3이다.

 

이러한 식으로 부분증가 수열 중 최대 길이를 찾아내야 하는데,

이는 기준점(i)2번째 인덱스부터 끝점까지 반복문을 통해 이동해주며

그 안에서의 다른 기준점(j) 세워 처음부터 i번째 인덱스 이전까지 돌며

 

i번째 수보다 작은 수를 만났을 경우에 그 수까지 부분수열의 길이에 +1을 해주면 된다.

 

즉, 2중 for문을 통해 i번째 인덱스에 대해 그 인덱스의 부분수열을 구해주면 된다.

참고로, 배열 길이는 1000이므로 2중 for문을 돌더라도 시간초과가 발생하지 않는다.


이를 그대로, 감소하는 수열에 적용해보자.

 

이번엔 기준점(i)을 처음 2번째 인덱스가 아닌 마지막에서 2번째 인덱스를 두어 감소하도록 하고

그 안의 기준점(j)을 끝점부터 i번째 인덱스 까지 돌며

 

i번째 수보다 작은 수를 만났을 경우에 그 수까지의 부분수열의 길이에 +1을 해주면 된다.

 

이를 코틀린 코드로 나타내면 다음과 같다.

import kotlin.collections.*
import kotlin.math.max

fun main(args: Array<String>) {
    val n = readLine()!!.toInt()
    val list = readLine()!!.split(" ").map { it.toInt() }

    val upDp = Array(1001){1}
    val downDp = Array(1001){1}

    for(i in 1 until n) {
        for(j in 0 until i) {
            if(list[i] > list[j]) {
                upDp[i] = max(upDp[i], upDp[j] + 1)
            }
        }

    }

    for(i in n-2 downTo 0) {
        for(j in n-1 downTo i+1) {
            if(list[i] > list[j]) {
                downDp[i] = max(downDp[i], downDp[j] + 1)
            }
        }
    }

    var max = 0
    for(i in 0 until n) {
       if(upDp[i] + downDp[i] > max) {
           max = upDp[i] + downDp[i]
       }
    }

    print(max-1)
}

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

https://www.acmicpc.net/problem/10844

 

10844번: 쉬운 계단 수

첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.

www.acmicpc.net

문제 설명

5656이란 수를 보자.

이 수는 인접한 모든 자리의 차이가 1이다. 이런 수를 계단 수라고 한다.

N이 주어질 때, 길이가 N인 계단 수가 총 몇 개 있는지 구해보자. 0으로 시작하는 수는 계단수가 아니다.


풀이 과정

이 문제는 단계마다의 규칙을 찾아 점화식을 세워 구현하는 DP 문제이다.

 

길이 1짜리 계단을 생각해보면,

1 2 3 4 5 6 7 8 9 총 9개의 계단이 있다.

 

길이 2짜리 계단을 생각해보면,

10 12 21 23 32 34 43 45 ... 87 89 98 로 총 17개가 있다.

 

그렇다면 길이 3짜리 계단은,

101 121 123 212 210 232 234 ... 789 787 898 987 989 가 있다.

 

여기서 규칙을 찾아보자.

끝자리가 0이나 9라면 더 늘릴 수 있는 수가 없기 때문에 하나만 더 추가로 만들 수 있다.

 

예를 들어, 1같은 경우 끝자리 0에 1을 추가한 101 만을 만들 수 있다.

하지만, 끝자리가 0이 아닌 21 같은 경우는 1을 추가한 212나 1을 뺀 210을 만들 수 있게 된다.

 

이를 이용하면, 다음과 같은 코드를 작성할 수 있다.

fun main(args: Array<String>) {
    val n = readLine()!!.toInt()

    val dp = Array(101) { IntArray(10) }
    dp[1][0] = 0
    for(i in 1 until 10) {
        dp[1][i] = 1
    }

    for(i in 2 until n+1) {
        for(j in 0 until 10) {
            when(j) {
                0 -> dp[i][j] = dp[i-1][1]
                9 -> dp[i][j] = dp[i-1][8]
                else -> dp[i][j] = (dp[i-1][j-1] + dp[i-1][j+1]) % 1000000000
            }
        }
    }

    var ans = 0L
    dp[n].forEach { ans += it }
    print(ans%1000000000)

}

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형

+ Recent posts