문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {1020, 10, 30, 20, 50} 이고, 길이는 4이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

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

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

둘째 줄에는 가장 긴 증가하는 부분 수열을 출력한다. 그러한 수열이 여러가지인 경우 아무거나 출력한다.

예제

예제 입력 1

1
2
3
6
10 20 10 30 20 50

예제 출력 1

1
2
4
10 20 30 50

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 나의 오답
const [N, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

const DP = Array.from({ length: N }, () => 1);

for (let i = 1; i < N; i++) {
for (let j = 0; j < i; j++) {
if (A[j] < A[i]) {
DP[i] = Math.max(DP[i], DP[j] + 1);
}
}
}

const LIS = Math.max(...DP);

let LIS_Array = [];
for (let i = 0; i < N; i++) {
const index = DP.findIndex((elem) => elem === i + 1);
LIS_Array.push(A[index]);
}

console.log(LIS);
console.log(LIS_Array.join(" "));
  • 기존 LIS를 구하는 로직에서 DP에 해당하는 LIS뿐만 아니라 그 때의 배열까지 생성해주도록 하였다.
  • 처음 배열 길이만큼 반복문을 순회하면서 DP값에서 Index를 찾는다. 해당 index의 A 수열의 값을 넣어준다.
  • 왜 틀렸는지 이유를 모르겠어서 해설을 보게되었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const [N, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

const DP = Array.from({ length: N }, () => 1);

for (let i = 1; i < N; i++) {
for (let j = 0; j < i; j++) {
if (A[j] < A[i]) {
DP[i] = Math.max(DP[i], DP[j] + 1);
}
}
}

let LIS = Math.max(...DP);
let LIS_Array = [];

for (let i = N - 1; i >= 0; i--) {
if (DP[i] === LIS) {
LIS_Array = [A[i], ...LIS_Array];
LIS--;
}
}

console.log(LIS_Array.length);
console.log(LIS_Array.join(" "));
  • 이전 내 코드는 findIndex 메서드로 제일 앞에서 부터 해당 인덱스를 찾아주도록 하였다. 하지만 이런 경우 반례가 생긴다. 왜냐하면 내가 처음에 DP의 초기값을 모두 1로 설정해두었기 때문에 LIS_Array의 배열의 데이터가 이상하게 들어올 수 있다

반례

N = 14, A = [10, 12, 1, 3, 5, 6, 7, 10, 12, 2, 4, 7, 10, 12]

  • findIndex로 앞에서부터 찾았을 경우: LIS_Array = [10, 12, 5, 6, 7, 10, 12]
  • 반복문 역순으로 찾았을 경우: LIS_Array = [1, 3, 5, 6, 7, 10, 12]

댓글 공유

문제

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

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

입력

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

출력

첫째 줄에 답을 출력한다.

예제

예제 입력 1

1
2
3
10
10 -4 3 1 5 6 -35 12 21 -1

예제 출력 1

1
2
33

예제 입력 2

1
2
3
10
2 1 -4 3 4 -4 6 5 -5 1

예제 출력 2

1
2
14

예제 입력 3

1
2
3
5
-1 -2 -3 -4 -5

예제 출력 3

1
-1

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 나의 오답
const [n, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

let DP = Array.from({ length: n }, () => 0);
if (A[0] < 0) {
DP = Array.from({ length: n }, () => A[0]);
}

for (let i = 1; i < n; i++) {
for (let j = i + 1; j < n; j++) {
DP[i] = Math.max(DP[i], DP[i - 1] + A[i]);
}
}

console.log(Math.max(...DP));
  • 처음엔 연속되었다고 하여서 2연속만 생각했었다. 하지만 2번째 예제에서는 연속된 숫자가 3, 4, -4, 6, 5 이렇게 구하여 총합이 14이다.
  • 0번째부터 i번째 까지 합을 저장하여 이전값과 비교하여 최댓값을 저장해준다.
  • 즉, 01, 02, 03, … 09번째의 합중 최대값만 DP[0]에 저장해준다. 이렇게 0번째부터 9번째 DP를 구하였다.
  • 그리고 첫번째가 음수의 경우는 DP를 초기값으로 모두 설정해주었다.
  • 하지만 시간 초과가 떴다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const [n, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

const DP = Array.from({ length: n }, () => A[0]);

for (let i = 1; i < n; i++) {
DP[i] = Math.max(DP[i - 1] + A[i], A[i]);
}

console.log(Math.max(...DP));
  • DP는 초기 값으로 설정해준다.
  1. DP[0] = A[0]
  2. DP[1]은 DP[0] + A[1] 과 A[1] 중에 최대값을 저장한다. 왜냐하면 A[1] 이전까지의 연속된 숫자들의 합이 양수라면 A[1] 보다 크지만 음수인 경우는 A[1]부터 시작하는 것이 크기 때문이다.

댓글 공유

문제

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다. 이 경우, 수학자 숌크라테스는 “11은 3개 항의 제곱수 합으로 표현할 수 있다.”라고 말한다. 또한 11은 그보다 적은 항의 제곱수 합으로 표현할 수 없으므로, 11을 그 합으로써 표현할 수 있는 제곱수 항의 최소 개수는 3이다.

주어진 자연수 N을 이렇게 제곱수들의 합으로 표현할 때에 그 항의 최소개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 100,000)

출력

주어진 자연수를 제곱수의 합으로 나타낼 때에 그 제곱수 항의 최소 개수를 출력한다.

예제

예제 입력 1

1
2
7

예제 출력 1

1
2
4

예제 입력 2

1
2
1

예제 출력 2

1
2
1

예제 입력 3

1
2
4

예제 출력 3

1
2
1

예제 입력 4

1
2
11

예제 출력 4

1
2
3

예제 입력 5

1
2
13

예제 출력 5

1
2

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const input = +require("fs").readFileSync("/dev/stdin").toString().trim();

const DP = Array.from({ length: input + 1 }, (_, i) => i);

for (let i = 4; i <= input; i++) {
for (let j = 1; j <= Math.sqrt(i); j++) {
const sqrt = Math.sqrt(i);
if (sqrt === parseInt(sqrt)) {
DP[i] = 1;
} else {
DP[i] = Math.min(DP[i], DP[i - j ** 2] + 1);
}
}
}

console.log(DP[input]);
  • 처음에는 단순히 초기값을 가지고 다음값을 구하는 식으로만 했었는데, 이렇게 할 경우 최소항을 비교하여 저장하면서 진행할 수 없다고 판단하여 2중 for문을 사용하였다.
  • 그 결과, 각 DP 마다 해당 index의 제곱근을 빼준 숫자의 DP에 +1 해준 것과 현재 DP를 비교했다.

ex) input = 18이라면, DP[18] = 18인 상태로 시작한다.

  1. j = 1 인 경우, DP[17] + 1 = 3이므로, DP[18] = 3를 저장한다.
  2. j = 2 인 경우, DP[14] + 1 = 4이므로, 이전 값을 그대로 둔다.
  3. j = 3 인 경우, DP[9] + 1 = 2 이므로, DP[18] = 2를 저장한다.
  4. j = 4 인 경우, DP[2] + 1 = 3 이므로 이전 값을 그대로 둔다.

j는 제곱근 이전 까지만 순회를 하므로 순회를 종료하고 DP값을 출력한다.

따라서, DP[18] = 2 로 (9+9) 이렇게 답을 구할 수 있다.

댓글 공유

문제

수열 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가 주어졌을 때, 그 수열의 부분 수열 중 바이토닉 수열이면서 가장 긴 수열의 길이를 구하는 프로그램을 작성하시오.

입력

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

출력

첫째 줄에 수열 A의 부분 수열 중에서 가장 긴 바이토닉 수열의 길이를 출력한다.

예제 입력 1

1
2
10
1 5 2 1 4 3 4 5 2 1

예제 출력 1

1
7

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const [N, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

function LBS(arr) {
const N = arr.length;
const DP_inc = Array.from({ length: N }, () => 1);
const DP_dec = Array.from({ length: N }, () => 1);

for (let i = 0; i < N; i++) {
for (let j = 0; j < i; j++) {
if (A[j] < A[i]) {
DP_inc[i] = Math.max(DP_inc[i], DP_inc[j] + 1);
}
}
}

for (let i = N - 1; i >= 0; i--) {
for (let j = i + 1; j < N; j++) {
if (A[j] < A[i]) {
DP_dec[i] = Math.max(DP_dec[i], DP_dec[j] + 1);
}
}
}

const DP = [];
for (let i = 0; i < N; i++) {
DP.push(DP_inc[i] + DP_dec[i] - 1);
}

return Math.max(...DP);
}

console.log(LBS(A));

해설

  1. 수열의 시작 부분부터 해당 index의 증가하는 부분수열 길이를 구한다.
  2. 수열의 마지막 부분부터 해당 index의 감소하는 부분수열의 길이를 구한다.
  3. 증가하는 부분 수열 길이와 감소하는 부분 수열의 길이를 더하여 가장 큰 값의 길이를 구하면 된다.

단, 이 때 기본값으로 세팅한 길이 1이 2번 더해진 것이므로 1을 빼줘야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 나의 오답
function LBS(arr) {
const N = arr.length;
const DP = Array.from({ length: N }, () => 1);

for (let i = 1; i < N; i++) {
for (let j = 0; j < i; j++) {
if (A[j] < A[i]) {
DP[i] = Math.max(DP[i], DP[j] + 1);
}
}
for (let k = i + 1; k < N; k++) {
if (A[k] >= A[k - 1]) break;

DP[i] = Math.max(DP[i], DP[i] + 1);
}
}

return Math.max(...DP.map((elem) => elem - 1));
}

console.log(LBS(A));

처음에는 감소하는 부분 수열을 구할 때, 역순으로 시작하지 않고 증가하는 부분 수열 구할 때 새로운 반복문으로 해당 index부터 시작하는 감소하는 부분 수열을 구하였는데 이는 DP라는 배열 하나를 가지고 반복문을 돌렸기 때문에 제대로 동작하지 않고 저장값이 꼬여버릴 수 있다.

댓글 공유

문제

수열 A가 주어졌을 때, 가장 긴 감소하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 30, 10, 20, 20, 10} 인 경우에 가장 긴 감소하는 부분 수열은 A = {10, 30, 10, 20, 20, 10} 이고, 길이는 3이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

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

출력

첫째 줄에 수열 A의 가장 긴 감소하는 부분 수열의 길이를 출력한다.

예제 입력 1

1
2
6
10 30 10 20 20 10

예제 출력 1

1
3

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const [N, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

function LDS(arr) {
const N = arr.length;
const DP = Array.from({ length: N }, () => 1);

for (let i = 1; i < N; i++) {
for (let j = 0; j < i; j++) {
if (A[j] > A[i]) {
DP[i] = Math.max(DP[i], DP[j] + 1);
}
}
}
return Math.max(...DP);
}

console.log(LDS(A));

해설

지난 번에 가장 긴 증가하는 부분수열과 조건문만 수정하면 되는 문제였다.

DP는 A 수열의 index에서 감소하는 부분 수열의 길이를 저장한다.

DP의 해당 index와 이전 index까지의 수열 요소와 비교하여 이전 index가 더 작다면, DP값을 갱신해주는 문제이다.

댓글 공유

CSS Box model

CSS Box model은 모든 HTML 요소를 감싸는 박스이다.

  • content: 텍스트, 이미지가 나타날 박스
  • padding: 컨텐츠 주변의 투명한 공간
  • border: padding과 content 사이의 테두리
  • margin: border 바깥의 투명한 공간
1
2
3
4
5
6
div {
width: 300px;
border: 15px solid green;
padding: 50px;
margin: 20px;
}

❗️ 주의사항

box model의 width, height를 설정하면, 이것은 content 부분의 width, height를 설정한 것이다.

전체 사이즈를 계산하기 위해서는 padding, border, margin을 모두 더해줘야한다.

1
2
3
4
5
6
div {
width: 320px;
padding: 10px;
border: 5px solid gray;
margin: 0;
}

요소의 총 width = width + left padding + right padding + left border + right border + left margin + right margin

요소의 총 height = height + top padding + bottom padding + top border + bottom border + top margin + bottom margin

요소의 총 width는 350px이다.

width와 height

width와 heigth로 올 수 있는 값은 다음과 같다.

  • auto: 기본값으로, 브라우저가 width와 height를 계산한다.
  • length: px, cm 등등
  • %: containing block의 퍼센트
  • initial: 기본값으로 설정
  • inherit: 부모 값으로 부터 상속 받은 값

max와 min

max와 min은 length 값으로 설정할 수 있다.

ex) px, cm, containing block의 %

1
2
3
4
5
div {
max-width: 500px;
height: 100px;
background-color: powderblue;
}

는 브라우저 width가 500px보다 작아지면 수평으로 스크롤이 생겨난다.

스크롤을 해결하기 위해서는 max-width를 사용하면 가능하다.

1
2
3
4
5
div {
max-width: 500px;
height: 100px;
background-color: powderblue;
}

max-width와 width를 같은 요소에 사용할 때, width 속성이 max-width 속성보다 큰 경우 max-width 속성이 사용된다.

box-sizing

만약, padding 값에 상관없이 width를 설정한 값을 content 그대로 사용하고 싶다면 box-sizing 속성을 설정한다.

1
2
3
4
5
div {
width: 300px;
padding: 25px;
box-sizing: border-box;
}

위 코드는 padding 값이 어떻든 content의 width는 300px로 설정된다.

margin

margin으로 가로로 가운데 정렬

margin을 사용하면 컨테이너 내부의 요소를 수평으로 가운데에 위치하도록 설정할 수 있다.

1
2
3
4
5
div {
width: 300px;
margin: auto;
border: 1px solid red;
}

margin collpase

두개의 margin이 하나처럼 동작할 때가 있다.

1
2
3
4
5
6
7
h1 {
margin: 0 0 50px 0;
}

h2 {
margin: 20px 0 0 0;
}

h1의 bottom margin이 50px이고 h2의 top margin이 20px이다.

h1 아래에 h2가 위치해 있을 때, 예상대로라면 h1과 h2 사이에는 70px이라고 예상되지만 margin-collpase 현상으로 인해 둘 중 큰 margin만 적용된다.

이는 오직 top, bottom에서만 발생한다. left, right margin에서는 발생하지 않는다.

border

margin과 padding과 달리 border는 style과 width, color를 설정할 수 있다.

또한 원하는 방향에 각각 스타일링을 해줄 수 있다.

1
2
3
p {
border-left: 6px solid red;
}

1
2
3
p {
border-bottom: 6px solid red;
}

테두리 둥글게

1
2
3
4
p {
border: 2px solid red;
border-radius: 5px;
}

댓글 공유

CSS background

1
2
3
4
5
6
background-color
background-image
background-repeat
background-attachment
background-position
background (shorthand property)

background-color

컬러는 다음 3가지 값만 가능하다.

  1. 유효한 컬러이름 ex) ‘red’, ‘green’ …
  2. HEX 값 ex) ‘#ff0000’
  3. RGB 값 ex) ‘rgb(255,0,0)’
1
2
3
4
5
6
7
8
div {
background-color: green;
opacity: 0.3;
}

div {
background: rgba(0, 128, 0, 0.3); /* Green background with 30% opacity */
}

opacity 속성을 줘서 배경을 흐리게 할 수 있다.

❗️opacity 속성을 사용하게 될 경우 자식 요소까지 흐려지므로 가독성이 떨어질 수도 있다.

background-image

기본값으로 image는 반복되어서 전체 요소를 덮어준다.

신기한 것은 p 태그에도 해당 속성을 설정할 수 있다는 점이다.

1
2
3
p {
background-image: url("paper.gif");
}

repeat, position 속성

image를 가로, 세로 반복되게 설정하는 속성이다.

position은 요소내에서 image의 위치를 설정한다.

1
2
3
4
5
body {
background-image: url("img_tree.png");
background-repeat: no-repeat;
background-position: bottom;
}

해당 배경 이미지를 아래에 위치시킨다.

background-attachment

1
2
3
4
5
6
body {
background-image: url("img_tree.png");
background-repeat: no-repeat;
background-position: right top;
background-attachment: fixed;
}

fixed로 설정하면 position fixed 처럼 배경이미지가 스크롤 하여도 해당 위치에 고정되어 있다.

scroll로 설정하면 다른 페이지를 보려고 스크롤 할 때, 배경도 스크롤된다.

단축표현

1
2
3
body {
background: #ffffff url("img_tree.png") no-repeat right top;
}

한줄로 쓸 수 있는데, 순서는 다음과 같다.

  • background-color
  • background-image
  • background-repeat
  • background-attachment
  • background-position

댓글 공유

netlify 배포하기

🖱 1. 드래그 앤 드랍으로 배포하기

  1. npm run build 명령어를 실행하여 build 파일을 만든다.
  2. netlify 홈페이지에 가서 build 폴더를 드래그 드랍한다.

netlify사이트

배포 끝!

🔗 Cocktail project site Link

❗️React Router 사용하여 netlify 배포시 문제

React Router를 사용하여 netlify에 배포했을 때, root 경로이외의 직접적으로 경로에 접근할 때, Page Not Found가 뜨는 문제가 있다.

📌 문제 발생 원인!

해당 문제는 React Router는 클라이언트 사이드에서 라우팅을 다루기때문에, root 페이지가 아닌 경로로 직접적으로 방문했을 경우, netliffy는 해당 경로를 어떻게 다룰지 알 수 없다.

🙆🏻‍♂️ 어떻게 해결하는가?

netlify에서 _redirects 파일을 제공한다. 여기에 netlify가 클라이언트 사이드에서 다루지 않는 URL을 어떻게 다룰 지에 대한 코드를 적어주면 된다.

1
2
// _redirects 파일
/* /index.html 200

폴더구조

SPA 프레임워크를 사용하여 애플리케이션을 만들고 history pushstate를 사용하여 URL을 클린하게 사용하는 경우 위와 같이 파일을 생성하여 적어주면된다.

이렇게 하면 어떤 URL로 브라우저 요청이 오던지 간에 404 대신 index.html을 제공한다.

2. github에서 CI 사용하여 배포하기

이 방법을 사용하면 프로젝트 변경사항을 반영하여 배포하기 편리하다.

  1. 깃헙 레포를 생성한다.
  2. 이미 존재하는 파일을 깃헙 레포에 푸시한다.
1
2
3
4
5
6
git init
git add .
git commit -m "initial commit"
git remote add origin https://github.com/loco9939/react-cocktail-project.git
git branch -M main
git push -u origin main
  1. netlify에 가서 “add new site” 버튼 클릭한 후 github으로 배포하기 하여 생성한 레포를 선택하고 배포한다.

netlify사이트

  1. package.json에 가서 build 명령어를 수정해주자.
1
2
3
4
5
6
7
8
// package.json
{
"scripts": {
...
"build": "CI= react-scripts build",
...
}
}

보통 react-scripts build만 되어있을텐데 앞에 CI= 을 추가해주자.

  1. 이후 해당 개발 파일을 수정한다음 깃헙에 push 하게 되면 netlify 가 알아서 배포를 해준다.

body 태그의 배경 색깔을 변경해보았다.

색깔변경후화면

댓글 공유

문제

수열 A가 주어졌을 때, 그 수열의 증가 부분 수열 중에서 합이 가장 큰 것을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가 부분 수열은 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 이고, 합은 113이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

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

출력

첫째 줄에 수열 A의 합이 가장 큰 증가 부분 수열의 합을 출력한다.

예제 입력 1

1
2
10
1 100 2 50 60 3 5 6 7 8

예제 출력 1

1
113

내 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const [N, input] = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const A = input.split(" ").map(Number);

function maxIncreasingSubArray(A) {
const n = A.length;
const DP = [...A];

for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (A[i] > A[j] && DP[i] < DP[j] + A[i]) {
DP[i] = DP[j] + A[i];
}
}
}
return Math.max(...DP);
}

console.log(maxIncreasingSubArray(A));

풀이

  1. DP는 해당 인덱스까지 가장 긴 부분수열의 합을 나타낸다. 이를 계산하기 편하게 하기 위해 DP에 A 수열의 값을 spread 문법으로 복사해준다.

  2. 어짜피 DP[0]은 1로 확정이므로 i(인덱스)가 1부터 반복문을 순회한다.
    이는 DP에 값을 저장하기 위한 반복문이다.

  3. i 이전까지 수열 값과 A[i]값을 비교하여 A[i]가 A[j]보다 크고 DP[i] 값이 DP[j]+A[i] 보다 작으면 증가하는 부분 수열에 포함될 수 있다.

그렇기 때문에 해당 DP[i]값을 새로운 값으로 갱신해준다.

예시

1
const A = [1, 100, 2, 50, 60, 3, 5, 6, 7, 8];

1. i = 1 && j = 0 일 때

  • A[1] = 100, A[0] = 1이므로 A[i] > A[j] 조건 만족한다
  • DP[1] < DP[0] + A[1] 만족하므로 DP[1] = DP[0] + A[1]로 갱신
1
DP = [1, 101, 2, 50, 60, 3, 5, 6, 7, 8];

2. i = 2 이고

2.1. j = 0 일 때

  • A[2]=2, A[0] = 1 이므로 A[i] > A[j] 조건 만족한다.
  • DP[2] < DP[0] + A[2] 만족하므로 DP[2] = DP[0] + A[2]로 갱신

2.2. j = 1 일 때,

  • A[2]=2, A[1] = 100 이므로 A[i] > A[j] 조건 만족하지 못한다.
1
DP = [1, 101, 3, 50, 60, 3, 5, 6, 7, 8];

즉, 0번째부터 해당 인덱스까지 수열의 두 수를 비교하고 DP에 저장된 값도 비교하여 둘다 만족하면 DP 값을 갱신하는 것이다.

댓글 공유

공부 목표

<오늘부터 CSS 마스터> 챕터를 시작하게 된 이유는 평소 리액트로 상태관리에 대해서만 생각하다보니 CSS로 화면을 스타일링 하는 것이 쉽게 나오지 않게 되었다.

그래서 이를 개선하고자 매일 CSS 공부를 한개씩 익혀가도록 목표를 세웠습니다!

공부는 W3Cschool) 사이트를 참조하면서 공부를 하거나 Youtube 강의를 보고 배울 수 도 있으며, 간단한 웹 사이트 스타일링을 클론해보는 방향으로 진행할 것입니다.

CSS란?

  • CSS는 Cascading Style sheet를 의미한다.

말 그대로 폭포처럼 떨어져 내리는 스타일시트이다.

  • CSS는 HTML 요소가 화면에 어떻게 나타날지를 묘사한다.

CSS를 왜 사용하나요?

CSS는 디자인, 레이아웃, 변화등을 포함한 웹 페이지의 스타일을 다른 기기와 화면 크기에 따라 정의하기 위해 사용한다.

CSS는 큰 문제를 해결한다!

HTML은 웹 페이지를 구성하기 위해 태그를 포함하도록 의도된 적이 없다!

나 색상 속성이 HTML 3.2에 추가되었을 때, 모든 페이지에 글꼴과 색상을 추가하는 것은 매우 비용이 많이 드는 작업이 되었다.

그래서 W3C가 CSS를 만들어 냈고 HTML 페이지에서 스타일 형식을 제거하였다.

CSS 문법

CSS 문법

CSS 선택자

CSS 선택자는 스타일링하고 싶은 HTML 요소를 선택한다.

총 5가지의 항목이 있다.

  1. 간단한 선택자
    • name, id, class 기반으로 요소 선택하기
  2. 조합 선택자
    • 둘 사이의 특정한 관계를 기반으로 요소 선택하기
  3. Pseudo-class 선택자
    • 특정 상태를 기반으로 요소 선택하기
  4. Pseudo-element 선택자
    • 요소의 일부분을 스타일링하고 선택하기
  5. Attribute 선택자
    • attribute나 attribute 값을 기반으로 요소 선택하기

center class를 포함한 p태그 선택자

1
2
3
4
p.center {
text-align: center;
color: red;
}

❗️ p태그와 .center 사이에 띄어쓰기가 있으면 안된다!

* 전체 선택자

1
2
3
4
* {
text-align: center;
color: blue;
}

Group 선택자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
h1 {
text-align: center;
color: red;
}

p {
text-align: center;
color: red;
}

/* 같은 스타일이라면 쉼표로 구분하여 한줄로 작성 가능 */
h1,
p {
text-align: center;
color: red;
}

CSS 추가하는 방법 3가지

  1. 외부 CSS
  2. 내부 CSS
  3. inline CSS

다중 CSS 우선순위

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="mystyle.css" />
<style>
h1 {
color: orange;
}
</style>
</head>
</html>

만약 mystyle.css에서 h1을 blue로 하였더라도 CSS는 가장 나중에 읽은 CSS를 적용하기 때문에 h1의 color는 orange가 될 것이다.

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<style>
h1 {
color: orange;
}
</style>
<link rel="stylesheet" type="text/css" href="mystyle.css" />
</head>
</html>

만약 mystyle.css가 더 아래에 있어서 나중에 읽힌다면 h1은 mystyle.css에서 정의한 스타일로 적용될 것이다.

Cascading 우선순위

  1. inline style
  2. 태그에 있는 외부 CSS와 내부 CSS
  3. 브라우저 기본

댓글 공유

Copyrights © 2023 loco9939. All Rights Reserved.

loco9939

author.bio


author.job