TIL | WIL

5/18 목 [LeetCode #242] 유효한 아나그램 TIL

깊은바다거북 2023. 5. 18. 21:58

[LeetCode] 242. Valid Anagram

문제:

Given two strings s and t, return true if t is an anagram of s, and false otherwise.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Example 1:

Input: s = "anagram", t = "nagaram"
Output: true

Example 2:

Input: s = "rat", t = "car"
Output: false

Constraints:

  • 1 <= s.length, t.length <= 5 * 104
  • s and t consist of lowercase English letters.

Follow up: What if the inputs contain Unicode characters? How would you adapt your solution to such a case?

나의 풀이:

// Double for loop로 풀이
// TIme: O(N)
// Space: O(N)
function mapSolution(s, t) {
	if (s.length !== t.length) {
		return false;
	}
	const map = new Map();
    for (let letter of s) { // O(N)
        map.set(letter, (map.get(letter) ?? 0) + 1);
    }
    for (let letter of t) { // O(N)
        map.set(letter, (map.get(letter) ?? 0) - 1);
        if (map.get(letter) < 0) {
            return false;
        }
    }

    return true;
}

// Time: O(N) 
// Space: O(N) (one Hash Map)
function objectSolution(s, t) {
    if (s.length !== t.length) {
        return false;
    }

    const countCharacter = {};
    for (const character of s) { // O(N)
        countCharacter[character] = (countCharacter[character] ?? 0) + 1;
    }

    for (const character of t) { // O(N)
        countCharacter[character] = (countCharacter[character] ?? 0) - 1;
        // when t has a character that doesn't exist in s, or when the current character count surpasses that of s: 
        if (countCharacter[character] < 0) {
            return false;            
        }
    }

    return true;
}

다른 풀이:

// 두 문자열을 먼저 정렬하고 같은 인덱스별로 비교하는 방법. 정렬에 필요한 공간을 계산에 넣지 않는다면 O(1)의 공간 복잡도로 해결할 수 있게 된다. 

// Time: 2 * O(NlogN) + O(N)
// Space: O(1) (if not consider sorting memory)
function sortSolution(s, t) {
    if (s.length !== t.length) {
        return false;
    }

    s = s.split('').sort(); // O(NlogN)
    t = t.split('').sort(); // O(NlogN)
    for (let index in s) { // O(N)
        if (s[index] !== t[index]) {
            return false;
        }
    }

    return true;
}

마지막 해법의 공간 복잡도 부분에서 의문이 생겨서 비교해보려고 한다. 우선 간단한 방법은 다음과 같다:

// How to let know memory usage for current process:
arr = [1, 2, 3, 4, 5, 6, 9, 7, 8, 9, 10];
arr.reverse();
u = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`The script uses approximately ${Math.round(u * 100) / 100} MB`);
// => The script uses approximately 13.95 MB

// Look through all memory usage: 
arr = [1, 2, 3, 4, 5, 6, 9, 7, 8, 9, 10];
arr.reverse();
u = process.memoryUsage();
for (let key in u) {
  console.log(`${key} ${Math.round(u[key] / 1024 / 1024 * 100) / 100} MB`);
}
/* => rss 41.69 MB
    heapTotal 15.97 MB
    heapUsed 14.1 MB
    external 0.99 MB
    arrayBuffers 0.73 MB
*/

⇒ 전역 객체인 process의 memoryUsage() 반환값 중 heapUsed가 바로 현재 프로세스를 실행할 때 사용된 메모리라고 한다.

(참고: https://www.valentinog.com/blog/node-usage/)

이를 토대로 주어지는 자료의 크기별 시간, 공간 사용량을 비교해보려고 한다. 걸린 시간 비교는 지난 번에 알게 된 대로 perf_hooks 라이브러리의 performance.now()로 시작과 끝을 찍어서 비교하고, 공간은 방금의 코드처럼 비교하기로 한다.

바 차트를 그려 비교해보려고 하는데, 제일 범용적이고 인지도가 있다는 D3.js와 더 간단하고 깔끔해 보이는 Chart.js 중 선택하려고 한다. 브라우저에 그리지 않고 Node.js 자체에서 볼 수 있는 방법이 있는지도 추가로 찾아볼 요량이다.


※ 위 내용은 스스로 공부하며 적어둔 노트이며 불확실한 내용이 있을 수 있습니다. 학습용으로 적합하지 않음을 유념해주세요. ※


Uploaded by N2T