두 문자열 s, t
t가 s의 애너그램(문자열을 재배열한 것)이라면 true
아니면 false 반환
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
if (s.length !== t.length)
return false;
let map = new Map();
for (let i = 0; i < s.length; i++)
map.set(s[i], map.has(s[i]) ? map.get(s[i]) + 1 : 1);
for (let i = 0; i < t.length; i++) {
let cnt = map.get(t[i]);
if (cnt > 0) {
map.set(t[i], cnt - 1);
} else
return false;
}
return true;
};
s와 t의 길이가 같다는 명확한 조건이 없어서 우선 둘의 길이가 다를 때 false 반환
(정확히 모든 문자를 사용하여 재배열해야 하므로 길이가 다를 수 없음)
s를 순회하면서 각 문자를 map에다가 저장, 값은 등장한 횟수
다시 t를 순회하면서 반대로 문자를 하나씩 제거
t의 문자가 map에 더 이상 없으면 바로 false 반환
무사히 순회가 끝났다면 true 반환
Accepted
Runtime 60ms (Beats 89.99%)
Memory 50.20MB (Beats 96.76%)
여태 알고리즘을 풀어오면서 문자열 문제에서 가장 많이 사용했던 형식의 알고리즘이었기 때문에 빠르게 풀어낼 수 있었다. 그런데 두번째 for문을 처음에는 cnt가 1일 때 map에서 문자 삭제, 1 이상일 때 감소한 값으로 set, 이 외에(map에 없을 때)는 false를 반환하는 식으로 구현했다. 그런데 곰곰히 생각해보니까 그런 경우는 마지막에 map의 크기를 구하는 것처럼 한번 더 map을 살펴야할 때 필요한 거고, 이 문제에서는 for문 중간에 false로 반환되지 않으면 마지막에는 무조건 true이므로 굳이 map에서 요소를 삭제할 필요가 없었다. 즉, 1 밑으로 내려간 0과 음수들을 가진 문자는 없다고 생각하고 false를 반환하면 되는 거였다. 그래서 더 깔끔하게 코드를 작성할 수 있었다.
그리고 map.get()으로 받아온 값을 따로 변수에 저장해서 사용하는 것과 필요할 때마다 호출(고작 두번인데도!)하는 것의 런타임 속도가 꽤 차이가 나는걸 이번에도 확인할 수 있었다. 반복적으로 사용할 메소드의 결과값은 꼭 변수에 따로 할당해서 사용해보자.