JavaScript에서 배열을 회전하는 두 가지 방법
종종 단순해 보이는 배열이나 문자열 알고리즘을 작성하는 것은 우리가 일을 지나치게 복잡하게 하거나 단순히 그러한 데이터 유형으로 작업하는 더 기본적인 빌딩 블록 중 일부를 알지 못하기 때문에 우리를 함정에 빠뜨릴 것입니다.
이것을 완벽하게 구현하는 질문은 배열 회전입니다.
프롬프트
숫자 배열(숫자)과 해당 배열을 오른쪽으로 몇 번이나 "회전"해야 하는지(k)에 대한 정수가 주어졌다고 가정해 보겠습니다.
이것은 무엇을 의미 하는가? 시각화해 보겠습니다.
nums = [1, 2, 3, 4, 5]
k = 3
=> [3, 4, 5, 1, 2]
k = 2
=> [4, 5, 1, 2, 3]
k = 1
=> [5, 1, 2, 3, 4]
보시다시피, 배열을 "회전"한다는 것은 단순히 해당 값을 오른쪽(또는 왼쪽)으로 이동하고 회전 목마를 회전하는 것과 같이 배열의 반대쪽 끝에 다시 놓는 것입니다.
이제 어떻게 하면 될까요?
솔루션
인터뷰 환경에서 이 질문을 설득력 있게 만드는 이유는 이 질문을 해결할 수 있는 여러 가지 방법이 있다는 것입니다. 이 모든 방법은 런타임과 공간 복잡성에 서로 다른 영향을 미칩니다. 모든 사람이 다르게 할 수 있으므로 후보자가 "단순한"문제를 해결하고 설명하는 다양한 방법을 보는 것은 좋은 질문입니다.
오늘 우리는 두 가지 잠재적인 솔루션을 살펴볼 것입니다.
nums = [1, 2, 3, 4, 5]
k = 3
=> [3, 4, 5, 1, 2]
k = 2
=> [4, 5, 1, 2, 3]
k = 1
=> [5, 1, 2, 3, 4]
인터뷰 환경에서 이 질문을 설득력 있게 만드는 이유는 이 질문을 해결할 수 있는 여러 가지 방법이 있다는 것입니다. 이 모든 방법은 런타임과 공간 복잡성에 서로 다른 영향을 미칩니다. 모든 사람이 다르게 할 수 있으므로 후보자가 "단순한"문제를 해결하고 설명하는 다양한 방법을 보는 것은 좋은 질문입니다.
오늘 우리는 두 가지 잠재적인 솔루션을 살펴볼 것입니다.
먼저 코드를 살펴본 다음 코드에서 무슨 일이 일어나고 있는지 분석해 보겠습니다.
1. 브루트 포스
const rotateArray1 = function(nums, k) {
for (let i = 0; i < k; i++) {
nums.unshift(nums.pop());
}
return nums;
}
이것은 "무차별 대입"접근 방식으로 간주됩니다. 본질적으로 처음에 문제에 대해 생각할 수 있는 가장 직접적인 방법이기 때문입니다.
우리는 배열의 끝에서 무언가를 제거한 다음 앞쪽에 놓기를 원한다는 것을 알고 있습니다. 그리고 우리는 그것을 (k)번 하고 싶어한다는 것을 압니다. 맞죠?
이 솔루션은 정확한 방향을 코드에 넣습니다. 배열의 마지막 요소를 pop()할 때마다 for 루프를 (k)번 실행하고 그것을 배열의 앞쪽으로 unshift()에 대한 인수로 제공합니다. 그런 다음 끝에 배열을 반환합니다.
여기서 런타임 복잡도는 O(n * k)입니다. 왜냐하면 우리가 unshift()를 사용할 때마다 JavaScript는 후드 아래 배열의 각 요소를 다시 배치하기 때문입니다.
공간 복잡도는 원래 배열을 제자리에서 수정하기 때문에 O(1) 또는 상수 공간입니다. 엄청난!
2. 반전
const rotateArray2 = function(nums, k) {
// reverse helper function
function reverse(arr, start, end) {
while (start < end) {
[arr[start], arr[end]] = [arr[end], arr[start]];
start++;
end--;
}
}
k %= nums.length;
reverse(nums, 0, (nums.length - 1));
reverse(nums, 0, (k - 1));
reverse(nums, k, (nums.length - 1));
return nums;
}
이것은 지금까지 세 가지 솔루션 중 가장 흥미로운 솔루션입니다. 이것은 당신이 처음에는 생각하지 않았을 것 같은 일종의 알고리즘 솔루션이지만 잠시 동안 "더 큰 그림"에 대해 생각한 후에 올 수 있습니다.
회전 중인 배열을 시각화하면 다음과 같은 패턴을 확인할 수 있습니다.
nums = [1, 2, 3, 4, 5]
k = 2
=> [4, 5, 1, 2, 3]
// original array reversed
[5, 4, 3, 2, 1]
// reverse just the first (k) elements
[4, 5, 3, 2, 1]
// see where we're going?
// reverse from (k) to the end
[4, 5, 1, 2, 3]
그리고 당신은 회전된 결과를 얻었습니다!
다시 말하지만, 이것은 처음에는 생각할 수 없는 약간의 논리 비약이지만 이 문제에 대해 설정한 범위 내에서 완벽하게 작동합니다.
실제 솔루션의 경우, 배열, 시작 인덱스 및 끝 인덱스를 취하는 도우미 함수를 설정한 다음 ES6 구문을 사용하여 증가하기 전에 array[start] 및 array[end] 요소를 교환합니다. 및 포인터 감소.
위의 예를 기반으로 이 함수를 세 번 호출해야 한다는 것을 알고 있습니다.
그리고 우리는 끝났습니다!
여기서 런타임 복잡도는 O(n * 3)입니다. 왜냐하면 여전히 각 요소를 적어도 한 번은 뒤집을 필요가 있기 때문입니다. 우리는 이것을 세 번 반복할 것입니다.
여기서 공간 복잡도는 다시 상수 O(1)입니다. 여전히 훌륭합니다!
당신은 그것을 가지고 있습니다! 동일한 문제에 대해 완전히 다르지만 똑같이 실행 가능한 두 가지 솔루션입니다. 두 가지를 모두 아는 것의 장점은 도구 상자에 더 많은 잠재적 도구가 있고 면접관이 다른 접근 방식을 시도하도록 요청할 경우 다른 방식으로 문제에 대답할 수 있다는 것입니다.
재미있게 읽으셨기를 바랍니다! :)
Reference
이 문제에 관하여(JavaScript에서 배열을 회전하는 두 가지 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/seanwelshbrown/two-ways-to-rotate-an-array-in-javascript-1bi3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)