diff --git "a/namin/05/05_01_\353\271\210\353\217\204_\354\271\264\354\232\264\355\204\260_\355\214\250\355\204\264.md" "b/namin/05/05_01_\353\271\210\353\217\204_\354\271\264\354\232\264\355\204\260_\355\214\250\355\204\264.md" new file mode 100644 index 0000000..5f6bce6 --- /dev/null +++ "b/namin/05/05_01_\353\271\210\353\217\204_\354\271\264\354\232\264\355\204\260_\355\214\250\355\204\264.md" @@ -0,0 +1,53 @@ +### 빈도 카운터 패턴 + +- 두 개의 배열을 입력받아, 첫 번째 배열의 모든 요소를 제곱한 값이 두 번째 배열에 정확히 존재하는지 확인합니다. +- 결과는 boolean으로 반환합니다. + +### 수도코드 + +- 빈도수를 담을 카운터 객체 두개를 만든다. +- 배열을 순회하면서 카운터에 빈도수를 기록한다. + - 만약 값이 이미 존재 한다면 1을 증가 시킨다. + - 만약 값이 존재 하지 않는다면 1로 초기화 한다. +- 카운터1을 순회하면서 카운터1의 제곱값과 카운터2의 값을 비교한다. + - 존재하지 않으면 false + - 빈도수가 같지 않다면 false + +```javascript +//O(n) +function same(arr1, arr2) { + if (arr1.length != arr2.length) return false; + + let counter1 = new Map(); + let counter2 = new Map(); + + //O(n) + for (let val of arr1) { + counter1.set(val, (counter1.get(val) || 0) + 1); + } + + //O(n) + for (let val of arr2) { + counter2.set(val, (counter2.get(val) || 0) + 1); + } + + //O(n) + for (let [val1, f1] of counter1) { + let f2 = counter2.get(val1 ** 2); + + if (!f2) { + return false; + } + + if (f1 != f2) { + return false; + } + } + + return true; +} +``` + +### 구현하면서 놓친 부분 + +- 배열의 길이를 비교하는 부분을 빠뜨려서 두번째 배열의 길이가 긴 경우 예외적으로 통과하는 케이스가 생겼다. diff --git "a/namin/05/05_02_\354\225\240\353\204\210\352\267\270\353\236\250.md" "b/namin/05/05_02_\354\225\240\353\204\210\352\267\270\353\236\250.md" new file mode 100644 index 0000000..b28df5b --- /dev/null +++ "b/namin/05/05_02_\354\225\240\353\204\210\352\267\270\353\236\250.md" @@ -0,0 +1,37 @@ +### 애너그램 + +- 두 개의 문자열을 입력받아, 첫 번째 문자열의 모든 요소가 두 번째 문자열에 정확히 존재하는지 확인합니다. +- 결과는 boolean으로 반환합니다. + +```javascript +//O(n) +function validAnagram(str1, str2) { + let counter1 = new Map(); + let counter2 = new Map(); + + //O(n) + for (let char of str1) { + counter1.set(char, (counter1.get(char) || 0) + 1); + } + + //O(n) + for (let char of str2) { + counter2.set(char, (counter2.get(char) || 0) + 1); + } + + //O(n) + for (let [key, value] of counter1) { + const count2 = counter2.get(key); + + if (!count2) { + return false; + } + + if (value != count2) { + return false; + } + } + + return true; +} +``` diff --git "a/namin/05/05_03_\353\213\244\354\244\221_\355\217\254\354\235\270\355\204\260_\355\214\250\355\204\264.md" "b/namin/05/05_03_\353\213\244\354\244\221_\355\217\254\354\235\270\355\204\260_\355\214\250\355\204\264.md" new file mode 100644 index 0000000..98247ea --- /dev/null +++ "b/namin/05/05_03_\353\213\244\354\244\221_\355\217\254\354\235\270\355\204\260_\355\214\250\355\204\264.md" @@ -0,0 +1,37 @@ +### 다중 포인터 패턴 + +- 오름차순으로 정렬된 정수 배열을 입력받아 합이 0이 되는 첫번째 쌍을 찾는다. +- 값의 쌍을 배열로 리턴한다. 만약 0이 되는 쌍이 없다면 undefined를 리턴한다. + +### 수도코드 + +- 포인터의 인덱스를 할 변수 start, end를 선언한다. +- start는 0, end는 배열의 마지막 인덱스로 값을 할당한다. +- start가 end보다 값이 작다면 + - 배열의 start 인덱스의 값과 end 인덱스의 값을 비교한다. + - 만약 값이 같다면 결과값을 리턴한다. + - 만약 값이 같지 않고 합이 0보다 크다면 end를 1 감소 시킨다. + - 만약 값이 같지 않고 합이 0보다 작다면 start를 1 증가 시킨다. + +```javascript +//O(n) +function sumZero(arr) { + let start = 0; + let end = arr.length - 1; + + //O(n) + while (start < end) { + const sum = arr[start] + arr[end]; + + if (sum == 0) { + return [arr[start], arr[end]]; + } else { + if (sum > 0) { + end--; + } else { + start++; + } + } + } +} +``` diff --git "a/namin/05/05_04_\352\263\240\354\234\240\352\260\222_\354\204\270\352\270\260.md" "b/namin/05/05_04_\352\263\240\354\234\240\352\260\222_\354\204\270\352\270\260.md" new file mode 100644 index 0000000..8933a01 --- /dev/null +++ "b/namin/05/05_04_\352\263\240\354\234\240\352\260\222_\354\204\270\352\270\260.md" @@ -0,0 +1,75 @@ +### 고유값 세기 + +- 정렬된 정수의 배열을 입력 받아 배열의 고유한 값이 몇 개 있는지 리턴합니다. +- 입력 값엔 음수도 존재합니다. + +### 수도 코드 + +- 기준점이 될 포인터(p1)와 현재 위치를 가르키는 포인터(p2) 변수를 생성한다. +- 만약 배열의 길이가 2보다 작다면 배열 길이를 리턴한다. +- 초기 결과값은 1로 설정한다. +- p2가 배열의 길이와 같을때까지 + - p1과 p2의 값을 비교한다. + - 만약 값이 같다면 p2를 1 증가 시킨다. + - 만약 값이 같지 않다면 + - p1에 p2값을 대입한다. + - 결과값을 1 증가 시킨다. + +### 예시 + +- countUniqueValues([1,1,1,1,1,2]) // 2 +- countUniqueValues([1,2,3,4]) // 4 +- countUniqueValues([1,2,3,4,4,4,4,7,7,7,12,12,12,13]) // 7 +- countUniqueValues([]) // 0 + +```javascript +function countUniqueValues(arr) { + if (arr.length < 2) { + return arr.length; + } + + let result = 1; + let p1 = 0; + let p2 = 0; + + while (p2 < arr.length) { + if (arr[p1] == arr[p2]) { + p2++; + } else { + p1 = p2; + result++; + } + } + + return result; +} +``` + +### 강의의 해결책 + +- 포인터 두개를 사용해서 문제를 해결한다. +- i는 기준점, j는 값을 비교할 대상이 된다. +- 배열을 순회하면서 i와 j를 비교하여 값이 다르면 + - i를 1 증가 시킨다. + - i의 위치에 j의 값을 대입한다. + - 따라서 0번째 인덱스부터 i까지는 고유한 값의 배열이 생성된다. +- i와 j를 비교해서 값이 다르면 + - j를 1 증가 시킨다. +- 0-index를 사용함으로 i + 1을 결과값으로 리턴한다. + +```javascript +//O(n) +function countUniqueValues(arr) { + let i = 0; + + //O(n) + for (let j = 1; j < arr.length - 1; j++) { + if (arr[i] != arr[j]) { + i++; + arr[i] = arr[j]; + } + } + + return i + 1; +} +``` diff --git "a/namin/05/05_05_\354\212\254\353\235\274\354\235\264\353\224\251_\354\234\210\353\217\204\354\232\260_\355\214\250\355\204\264.md" "b/namin/05/05_05_\354\212\254\353\235\274\354\235\264\353\224\251_\354\234\210\353\217\204\354\232\260_\355\214\250\355\204\264.md" new file mode 100644 index 0000000..990a650 --- /dev/null +++ "b/namin/05/05_05_\354\212\254\353\235\274\354\235\264\353\224\251_\354\234\210\353\217\204\354\232\260_\355\214\250\355\204\264.md" @@ -0,0 +1,56 @@ +### 슬라이딩 윈도우 패턴 + +- 기존 값을 재활용해 연속된 하위 집합을 빠르게 계산하는 효율적인 패턴. +- 만약 하위 집합의 합을 구하는 문제가 있다면 +- 기존 방식은 모든 하위 집합의 합을 계산하므로 O(n^2)의 시간복잡도가 발생. +- 해당 패턴을 사용하면 + - 첫 번째 하위 집합의 합을 한 번 계산. + - 다음 하위 집합으로 이동할 때: + - 이전 합에서 첫 번째 값을 빼고 새 값을 더함. + +### 문제설명 + +- 배열과 정수를 입력받아, 정수 크기의 하위 집합중에 가장 큰 합을 리턴한다. + +### 수도코드 + +- 만약 배열의 크기가 정수보다 작으면 Null을 리턴한다. +- 처음 윈도우 크기만큼 합을 tempSum, maxSum에 저장한다. + +- 배열을 순회하면서 tempSum에서 이전값을 빼고 새로운 값을 더한다. +- maxSum과 비교하고 값이 더 크다면 tempSum을 maxSum에 대입한다. + +### 예시 + +- maxSubarraySum([1,2,3,4], 3) // 9 +- maxSubarraySum([1,2], 3) // null +- maxSubarraySum([1,1,1,1,9,2,9,3], 3) // 20 + +```javascript +//O(n) +function maxSubarraySum(arr, num) { + if (arr.length < num) { + return null; + } + + let tempSum = 0; + let maxSum = 0; + + for (let i = 0; i < num; i++) { + tempSum += arr[i]; + maxSum += arr[i]; + } + + for (let i = 1; i < arr.length - num + 1; i++) { + const prevVal = arr[i - 1]; + const newVal = arr[i + num - 1]; + tempSum = tempSum - prevVal + newVal; + + if (tempSum > maxSum) { + maxSum = tempSum; + } + } + + return maxSum; +} +``` diff --git "a/namin/05/05_06_\353\266\204\355\225\240_\354\240\225\353\263\265_\355\214\250\355\204\264.md" "b/namin/05/05_06_\353\266\204\355\225\240_\354\240\225\353\263\265_\355\214\250\355\204\264.md" new file mode 100644 index 0000000..b6c6163 --- /dev/null +++ "b/namin/05/05_06_\353\266\204\355\225\240_\354\240\225\353\263\265_\355\214\250\355\204\264.md" @@ -0,0 +1,44 @@ +### 분할 정복 패턴 + +- 데이터를 작게 나누어 처리하는 과정을 반복하는 패턴 +- 정렬된 배열과 정수를 입력받아 위치를 리턴한다. +- 정수가 존재하지 않으면 -1을 리턴한다. + +### 수도코드 + +- 배열의 시작과 끝을 변수로 생성 +- 시작이 끝보다 같거나 작다면 + - 중간값과 정수를 비교한다. + - 만약 중간값이 정수보다 크다면 + - 시작을 중간 + 1으로 설정한다. + - 만약 중간값이 정수보다 작다면 + - 끝을 중간 - 1으로 설정한다. + - 만약 중간값이 정수와 같다면 + - 결과를 리턴한다. + +### 예제 + +- search([1,2,3,4], 4) // 3 +- search([1,2,3,4], 5) // -1 + +```javascript +//O(log n) +function search(array, val) { + let min = 0; + let max = array.length - 1; + + while (min <= max) { + const middle = Math.floor((min + max) / 2); + + if (array[middle] < val) { + min = middle + 1; + } else if (array[middle] > val) { + max = middle - 1; + } else { + return middle; + } + } + + return -1; +} +``` diff --git a/namin/05/README.md b/namin/05/README.md new file mode 100644 index 0000000..3dfe432 --- /dev/null +++ b/namin/05/README.md @@ -0,0 +1,2 @@ +# javascript-algorythm-and-data-structures +자바스크립트 알고리즘 & 자료구조 스터디 diff --git a/namin/06/06_01_same_frequency.md b/namin/06/06_01_same_frequency.md new file mode 100644 index 0000000..d24b0d6 --- /dev/null +++ b/namin/06/06_01_same_frequency.md @@ -0,0 +1,48 @@ +### 문제설명 + +- 두개의 정수를 입력받아 정수를 이루는 숫자들의 빈도수가 같은지를 리턴하는 함수를 구현한다. +- 음수가 존재하는 케이스는 무시한다. + +### 수도코드 + +- 만약 자릿수가 다르다면 false를 리턴한다. + +- 첫번째 정수의 구성요소를 카운팅할 객체 생성 +- 첫번째 정수를 문자열로 만들어 순회하고 객체에 빈도수 카운팅 +- 두번째 정수를 문자열로 만들어 순회하고 카운팅 객체와 비교한다. + - 만약 값이 없거나 0이라면 false를 리턴한다. + - 만약 값이 있으면 객체에서 빈도를 1을 감소시킨다. +- true로 리턴한다. + +```javascript +//O(n) +function sameFrequency(num1, num2) { + let counter = new Map(); + + let strNum1 = String(num1); + let strNum2 = String(num2); + + if (strNum1.length != strNum2.length) { + return false; + } + + //O(n) + for (let i = 0; i < strNum1.length; i++) { + const n = strNum1[i]; + counter.set(n, (counter.get(n) || 0) + 1); + } + + //O(n) + for (let i = 0; i < strNum2.length; i++) { + const n = strNum2[i]; + + if (!counter.get(n)) { + return false; + } + + counter.set(n, counter.get(n) - 1); + } + + return true; +} +``` diff --git a/namin/06/06_02_are_there_Duplicates.md b/namin/06/06_02_are_there_Duplicates.md new file mode 100644 index 0000000..7c80db6 --- /dev/null +++ b/namin/06/06_02_are_there_Duplicates.md @@ -0,0 +1,67 @@ +### 문제설명 + +- 전달된 인수중에 중복된 요소가 있는지 확인한다. + +### 수도코드 + +- 정렬이 되어 있지 않은 경우 + +- 값이 있는지 체크할 객체 하나 생성 +- 인수를 담은 배열을 돌면서 객체에 값이 있는지 체크 + - 값이 있다면 true 리턴 + - 값이 없다면 값을 true로 설정 +- false 리턴 + +```javascript +//O(n) +function areThereDuplicates() { + const obj = {}; + + for (let i = 0; i < arguments.length; i++) { + const arg = arguments[i]; + + if (obj[arg]) { + return true; + } else { + obj[arg] = true; + } + } + + return false; +} +``` + +- 배열을 정렬한다. +- 인수를 담은 배열에서 다중포인터를 사용한다. +- i는 기준점, j는 현재 위치 +- 배열을 돌면서 i와 j를 비교한다. + - 만약 i와 j가 값이 다르다면 i를 1 증가 시키고, 배열 i번째에 j의 값을 추가한다. + - 만약 i와 j가 값이 같다면 true를 리턴한다. +- false를 리턴한다. + +```javascript +//O(n log n) +function areThereDuplicates() { + //O(n log n) + const arr = arguments.sort(); + + let i = 0; + //O(n) + for (let j = 1; j < arr.length; j++) { + if (arr[i] == arr[j]) { + return true; + } else { + i++; + arr[i] = arr[j]; + } + } + return false; +} +``` + +```javascript +function areThereDuplicates() { + //O(n) + return new Set(arguments).size !== arguments.length; +} +``` diff --git a/namin/06/06_03_average_pair.md b/namin/06/06_03_average_pair.md new file mode 100644 index 0000000..a6946fc --- /dev/null +++ b/namin/06/06_03_average_pair.md @@ -0,0 +1,49 @@ +### 문제설명 + +- 정렬된 정수 배열과 목표 평균이 입력값으로 주어진다. +- 배열에 쌍의 평균이 목표 평균과 같은 쌍이 있는지 체크한다. + +### 예제 + +- averagePair([1,2,3],2.5) // true +- averagePair([1,3,3,5,6,7,10,12,19],8) // true +- averagePair([-1,0,3,4,5,6], 4.1) // false +- averagePair([],4) // false + +### 수도코드 + +- 만약 배열이 2보다 크기가 작으면 false + +- start는 시작점, end는 끝점 + +- 두 쌍의 평균과 목표평균을 비교한다. +- 같다면 true를 리턴한다. +- 같지 않고 퍙균이 목표평균보다 크다면 end를 1 감소시킨다. +- 같지 않고 평균이 목표평균보다 작다면 start를 1 증가시킨다. +- 반복문이 끝나면 false를 리턴한다. + +```javascript +function averagePair(arr, avg) { + if (arr.length < 2) { + return false; + } + + let start = 0; + let end = arr.length - 1; + + //O(n) + while (start < end) { + const pairAvg = (arr[start] + arr[end]) / 2; + + if (avg == pairAvg) { + return true; + } else if (pairAvg > avg) { + end--; + } else { + start++; + } + } + + return false; +} +``` diff --git a/namin/06/06_04_is_subsequence.md b/namin/06/06_04_is_subsequence.md new file mode 100644 index 0000000..8c4af7c --- /dev/null +++ b/namin/06/06_04_is_subsequence.md @@ -0,0 +1,40 @@ +### 문제설명 + +- 두개의 문자열을 입력받는다. +- 첫번째 문자열이 순서가 바뀌지 않고 두번째 문자열에 포함되는지 체크한다. +- 포함되면 true, 아니면 false를 리턴한다. + +### 수도코드 + +- 두개 포인터 생성 +- i는 두번째 문자열에서 첫번째 문자열이 포함된 인덱스, j는 현재 위치 +- str2를 순회하면서 현재값이 str[i]와 동일한지 비교한다. + - 만약 값이 같다면 i++; + - 만약 i가 str1.length와 같다면 return true +- return i == str1.length + +### 예시 + +- isSubsequence('hello', 'hello world'); // true +- isSubsequence('sing', 'sting'); // true +- isSubsequence('abc', 'abracadabra'); // true +- isSubsequence('abc', 'acb'); // false (order matters) + +```javascript +// O(n) +function isSubsequence(str1, str2) { + let i = 0; + // O(n); + for (let j = 0; j < str2.length; j++) { + if (str2[j] == str1[i]) { + i++; + } + + if (i == str1.length) { + return true; + } + } + + return i == str1.length; +} +``` diff --git a/namin/06/06_05_max_subarray_sum.md b/namin/06/06_05_max_subarray_sum.md new file mode 100644 index 0000000..e2077eb --- /dev/null +++ b/namin/06/06_05_max_subarray_sum.md @@ -0,0 +1,52 @@ +### 문제설명 + +- 정수의 배열과 길이가 주어졌을 때, 길이만큼의 하위 집합중 가장 큰 합을 구해야 한다. +- 하위 집합은 연속적이다. +- 배열은 정렬되지 않음. + +### 수도코드 + +- 슬라이딩 윈도우 패턴 적용 + +- maxSum, tempSum 변수 생성. +- 배열의 앞에서 길이만큼 하위 집합 합 구해서 tempSum에 할당 +- 반복문 돌면서 (하위 집합이 항상 길이만큼 포함 될 수 있어야 함) +- 이전 값 빼고, 새로운 값 더하고 해서 tempSum 재할당. +- maxSum와 비교해보고 크다면 할당 + +- 배열이 길이보다 짧다면 null + +### 예제 + +- maxSubarraySum([100,200,300,400], 2) // 700 +- maxSubarraySum([1,4,2,10,23,3,1,0,20], 4) // 39 +- maxSubarraySum([-3,4,0,-2,6,-1], 2) // 5 +- maxSubarraySum([3,-2,7,-4,1,-1,4,-2,1],2) // 5 +- maxSubarraySum([2,3], 3) // null + +```javascript +function maxSubarraySum(arr, length) { + if (arr.length < length) { + return null; + } + + let maxSum = -Infinity; + let tempSum = 0; + + //O(n) + for (let n of arr.slice(0, length)) { + tempSum += n; + } + + //O(n) + for (let i = 1; i <= arr.length - length; i++) { + tempSum = tempSum - arr[i - 1] + arr[i + length - 1]; + + if (maxSum < tempSum) { + maxSum = tempSum; + } + } + + return maxSum; +} +``` diff --git a/namin/06/06_06_min_sub_array_len.md b/namin/06/06_06_min_sub_array_len.md new file mode 100644 index 0000000..03b9718 --- /dev/null +++ b/namin/06/06_06_min_sub_array_len.md @@ -0,0 +1,150 @@ +### 문제설명 + +- 양수 배열과 양수를 입력값으로 받음 +- 하위 집합의 최소 길이를 반환한다. +- 하위 집합의 조건은 양수보다 같거나 커야 한다. +- 값이 없는 경우 0을 반환한다. +- 하위 집합은 연속적이어야 한다. + +### 예제 + +{ +i: 0, +l: 3, +tempSum: 0, +} + +- minSubArrayLen([2,3,1,2,4,3], 7) // 2 -> because [4,3] is the smallest subarray +- minSubArrayLen([2,1,6,5,4], 9) // 2 -> because [5,4] is the smallest subarray +- minSubArrayLen([3,1,7,11,2,9,8,21,62,33,19], 52) // 1 -> because [62] is greater than 52 +- minSubArrayLen([1,4,16,22,5,7,8,9,10],39) // 3 +- minSubArrayLen([1,4,16,22,5,7,8,9,10],55) // 5 +- minSubArrayLen([4, 3, 3, 8, 1, 2, 3], 11) // 2 +- minSubArrayLen([1,4,16,22,5,7,8,9,10],95) // 0 + +### 수도코드 + +- 배열의 길이가 0이면 0을 리턴한다. + +- 현재 인덱스 기록할 i, 윈도우 길이를 저장할 l, 임시합을 저장할 tempSum 변수 생성 +- i = 0, l = 1, tempSum = 0 + +- 길이가 배열의 크기보다 작거나 같다면 + + - 만약 i가 길이보다 짧으면 tempSum에 i값 더하고 인덱스를 1증가한다. + - 만약 i가 길이와 같거나 길면 이전값빼고, 새로운값을 tempSum에 더하고 인덱스를 1증가한다. + + - 만약 tempSum이 양수보다 같거나 크다면 l을 리턴한다. + + - 만약 인덱스가 배열의 끝점이라면 + - 인덱스 0, tempSum = 0, l은 1증가 + +- 반복문이 끝나면 0을 리턴한다. + +```javascript +function minSubArrayLen(array, num) { + if (array.length == 0 || num == 0) { + return 0; + } + + let i = 0; + let l = 1; + let tempSum = 0; + + //O(n^2) + while (l <= array.length) { + if (i < l) { + tempSum = tempSum + array[i]; + i++; + } else { + tempSum = tempSum - array[i - l] + array[i]; + i++; + } + + if (tempSum >= num) { + return l; + } + + if (i == array.length) { + i = 0; + tempSum = 0; + l = l + 1; + } + } + + return 0; +} +``` + +### 리팩터링 + +- 기존 코드는 O(n^2)의 시간 복잡도를 갖는다. +- 시간 복잡도를 낮추기 위해 슬라이딩 윈도우 기법을 적용한다. + +- start = 0와 end = 0, 결과값에 대한 변수를 설정한다. +- 만약 start와 end가 배열의 범위 안에 있다면 +- 윈도우의 합이 정수보다 작다면 end를 1증가시킨다. +- 윈도우의 합이 정수보다 갖거나 크다면 start와 end의 차이가 result보다 작다면 결과에 기록하고 start를 1증가시킨다. + +```javascript +function minSubArrayLen(array, n) { + if (!array.length) { + return 0; + } + + let start = 0; + let end = 0; + let result = Infinity; + let sumOfWindow = 0; + + while (start < array.length - 1 && end < array.length - 1) { + if (sumOfWindow < n) { + end++; + sumOfWindow += array[end]; + } else { + const diff = end - start; + if (diff < result) { + result = diff; + } + + start++; + sumOfWindow -= array[start]; + } + } + + return result == Infinity ? 0 : result; +} +``` + +### solution + +```javascript +function minSubArrayLen(nums, sum) { + let total = 0; + let start = 0; + let end = 0; + let minLen = Infinity; + + while (start < nums.length) { + // if current window doesn't add up to the given sum then + // move the window to right + if (total < sum && end < nums.length) { + total += nums[end]; + end++; + } + // if current window adds up to at least the sum given then + // we can shrink the window + else if (total >= sum) { + minLen = Math.min(minLen, end - start); + total -= nums[start]; + start++; + } + // current total less than required total but we reach the end, need this or else we'll be in an infinite loop + else { + break; + } + } + + return minLen === Infinity ? 0 : minLen; +} +``` diff --git a/namin/06/06_07_find_longest_substring.md b/namin/06/06_07_find_longest_substring.md new file mode 100644 index 0000000..32b1134 --- /dev/null +++ b/namin/06/06_07_find_longest_substring.md @@ -0,0 +1,42 @@ +### 문제풀이 + +- 문자열을 받아 모든 고유 문자가 포함된 가장 긴 하위 문자열의 길이를 반환해야 합니다. + +### 예제 + +- findLongestSubstring('') // 0 +- findLongestSubstring('rithmschool') // 7 +- findLongestSubstring('thisisawesome') // 6 +- findLongestSubstring('thecatinthehat') // 7 +- findLongestSubstring('bbbbbb') // 1 +- findLongestSubstring('longestsubstring') // 8 +- findLongestSubstring('thisishowwedoit') // 6 + +### 수도코드 + +- start, end, map 변수 선언 +- str 길이 만큼 반복문 돌고 고유한 문자열인지 체크 + - 고유한 문자열이라면 end++, map에 str[end] 추가, result에 최대값 추가 + - 고유한 문자열이 아니라면 start++, map에서 str[start] 제거 + +```javascript +function findLongestSubstring(str) { + let start = 0; + let map = new Map(); + let result = 0; + + for (let end = 0; end < str.length; end++) { + const char = str[end]; + + while (map.has(char)) { + map.delete(str[start]); + start++; + } + + map.set(char, true); + result = Math.max(result, end - start + 1); + } + + return result; +} +```