Skip to content

Commit cc5da6c

Browse files
authored
Merge pull request #927 from lledellebell/main
[dd_._._bb] Week 07
2 parents 06b8556 + 457b29a commit cc5da6c

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/***
2+
* @problem
3+
* 주어진 문자열에서 중복되지 않는 문자로 이루어진 가장 긴 부분 문자열의 길이를 구해야 합니다.
4+
*
5+
* @constraints
6+
* - 문자열의 길이는 0 이상 5 * 10^4 이하입니다.
7+
* - 문자열은 ASCII 문자로만 구성됩니다.
8+
*
9+
* @example
10+
* - 입력: "abcabcbb"
11+
* 출력: 3 ("abc")
12+
* - 입력: "bbbbb"
13+
* 출력: 1 ("b")
14+
* - 입력: "pwwkew"
15+
* 출력: 3 ("wke")
16+
*
17+
* @description
18+
* - ASCII 문자의 마지막 위치를 저장할 배열을 사용합니다.
19+
* - 중복 문자가 발견되면 시작 지점을 해당 문자의 마지막 위치 다음으로 이동합니다.
20+
* - 현재 서브스트링의 길이를 계산하여 최대 길이를 갱신합니다.
21+
*
22+
* @complexity
23+
* - 시간 복잡도: O(n)
24+
* ㄴ 문자열을 한 번 순회하며 각 문자를 처리합니다.
25+
* - 공간 복잡도: O(1)
26+
* ㄴ 고정 크기 배열(128)을 사용하므로 공간 복잡도는 상수입니다.
27+
*/
28+
function lengthOfLongestSubstring(s: string): number {
29+
// ASCII 문자의 마지막 위치를 저장할 배열 (128 크기, 초기값 -1)
30+
const lastSeenIndex = Array(128).fill(-1);
31+
let substringStart = 0;
32+
let longestLength = 0;
33+
34+
for (let currentIndex = 0; currentIndex < s.length; currentIndex++) {
35+
const currentCharCode = s.charCodeAt(currentIndex);
36+
37+
// 중복 문자가 발견되었고, 그 문자의 마지막 위치가 현재 시작점 이후라면
38+
if (lastSeenIndex[currentCharCode] >= substringStart) {
39+
// 시작 지점을 중복 문자의 다음 위치로 이동
40+
substringStart = lastSeenIndex[currentCharCode] + 1;
41+
}
42+
43+
// 현재 문자의 위치를 배열에 저장
44+
lastSeenIndex[currentCharCode] = currentIndex;
45+
46+
// 현재 서브스트링의 길이를 계산하고 최대값 갱신
47+
longestLength = Math.max(longestLength, currentIndex - substringStart + 1);
48+
}
49+
50+
return longestLength;
51+
}
52+
53+
// 테스트
54+
console.log(lengthOfLongestSubstring("abcabcbb")); // 출력: 3
55+
console.log(lengthOfLongestSubstring("bbbbb")); // 출력: 1
56+
console.log(lengthOfLongestSubstring("pwwkew")); // 출력: 3

reverse-linked-list/lledellebell.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @problem
3+
* 단일 연결 리스트를 뒤집는 알고리즘을 함수형 프로그래밍 스타일로 구현합니다.
4+
* 예: 1 -> 2 -> 3 -> 4 -> 5 -> => 5 -> 4 -> 3 -> 2 -> 1
5+
*
6+
* @constraints
7+
* - 노드의 개수는 0 이상일 수 있습니다.
8+
* - 각 노드의 값은 정수입니다.
9+
* - 입력 리스트는 단일 연결 리스트입니다.
10+
*
11+
* @example
12+
* - Input: head = [1, 2, 3, 4, 5]
13+
* - Output: [5, 4, 3, 2, 1]
14+
*
15+
* @description
16+
* 재귀를 사용하여 연결 리스트를 뒤집습니다.
17+
* 함수형 프로그래밍 스타일에서는 상태를 변경하지 않고, 각 호출에서 새로운 리스트를 반환합니다.
18+
*
19+
* @complexity
20+
* - 시간 복잡도: O(n)
21+
* 리스트의 모든 노드를 한 번씩 방문합니다.
22+
* - 공간 복잡도: O(n)
23+
* 재귀 호출 스택을 사용합니다.
24+
*/
25+
class ListNode {
26+
val: number;
27+
next: ListNode | null;
28+
29+
/**
30+
* @constructor
31+
* @param val - 노드의 값
32+
* @param next - 다음 노드에 대한 참조
33+
*/
34+
constructor(val?: number, next?: ListNode | null) {
35+
this.val = val ?? 0; // 값이 없으면 기본값 0
36+
this.next = next ?? null; // 다음 노드가 없으면
37+
}
38+
}
39+
40+
/**
41+
* 단일 연결 리스트를 뒤집는 함수 (재귀적, 함수형 스타일)
42+
* @param head - 연결 리스트의 시작 노드
43+
* @param prev - 이전 노드 (초기값은)
44+
* @returns 뒤집힌 연결 리스트의 시작 노드
45+
*/
46+
function reverseList(
47+
head: ListNode | null,
48+
prev: ListNode | null = null
49+
): ListNode | null {
50+
// 기본 조건: 리스트가 비어 있거나 마지막 노드에 도달한 경우
51+
if (head === null) {
52+
return prev;
53+
}
54+
55+
// 다음 노드 저장
56+
const next = head.next;
57+
58+
// 현재 노드의 방향을 이전 노드로 설정
59+
head.next = prev;
60+
61+
// 재귀 호출로 다음 노드 처리
62+
return reverseList(next, head);
63+
}
64+
65+
// 연결 리스트 생성
66+
const node1 = new ListNode(1);
67+
const node2 = new ListNode(2);
68+
const node3 = new ListNode(3);
69+
const node4 = new ListNode(4);
70+
const node5 = new ListNode(5);
71+
72+
node1.next = node2;
73+
node2.next = node3;
74+
node3.next = node4;
75+
node4.next = node5;
76+
77+
const reversedHead = reverseList(node1);
78+
79+
// 결과
80+
let current = reversedHead;
81+
while (current !== null) {
82+
console.log(current.val); // 5, 4, 3, 2, 1
83+
current = current.next;
84+
}

0 commit comments

Comments
 (0)