CS/알고리즘

누적 합 누적 합이란 수열에 대해 각 인덱스까지의 구간의 합을 구하는 것을 의미합니다. 모든 구간에 대해 단순하게 반복하여 하나씩 더해가는 방법을 사용하게 되면 최악의 경우 O(n^2)의 시간 복잡도를 가질 수 있습니다. 하지만 이전 인덱스까지의 누적합에 현재 값을 더하는 방식인 누적 합을 사용하면 O(n)의 시간 복잡도를 가질 수 있습니다. 배열에 따라 누적합을 저장해놓은 뒤, 구하고자 하는 범위까지의 누적합에서 해당 범위에 포함되지 않는 범위를 빼주면 구할 수 있습니다. 따라서 배열의 특정 범위의 구간 합을 구하고자 한다면, 해당 알고리즘이 매우 유용할 수 있습니다. 예시 백준 11659 문제인 구간 합 구하기 4를 통해 누적합에 대해 알아보겠습니다. 우선 5 4 3 2 1에 대한 누적합을 구하고 배..
슬라이딩 윈도우 슬라이딩 윈도우란 일정한 길이를 이동시키면서 조건에 맞는 값을 찾는 알고리즘입니다. 배열에서 일정 범위의 합을 비교할 때 매우 유용한 방법으로, 값을 이동시킬 때 배열의 처음 값을 제거하고 배열의 마지막 값을 더해주기만 하면 되는데, 배열의 모든 값을 불러와서 더하는 연산을 피할 수 있어 매우 효율적입니다. 양 옆에 지점을 둔다는 점에서 투 포인터와 비슷한 점이 있지만, 투 포인터는 범위가 유동적으로 변하지만, 슬라이딩 윈도우는 범위가 고정되어 있다는 점이 차이점입니다. 다음은 투 포인터를 그림으로 표현한 예시입니다. 조건에 따라 범위가 유동적으로 변경되는 것을 볼 수 있습니다. 다음은 슬라이딩 윈도우를 그림으로 표현한 예시입니다. 범위는 항상 고정되어 있고, 배열은 좌우로만 이동합니다.
투 포인터 투 포인터란, 배열에서 원래 이중 for문으로 O(N^2)으로 처리되는 작업을 2개의 포인터를 통해 O(N)으로 해결해주는 알고리즘입니다. 여기서의 포인터는 C언어에서의 포인터의 개념이 아니라, 해당 지점을 의미하기 위해 사용되는 개념입니다. 이중 for문으로 처리할 때 주로 i가 계산되고, 그 안에서 j가 계산되는데, j가 계산될 때 i에 대한 정보가 쓰이지 않습니다. 하지만 투 포인터 같은 경우에는 i에 대한 정보를 사용하여 포인터를 이동시킵니다. 투 포인터 문제는 이분 탐색으로도 풀 수 있는 경우가 많고, 그 반대의 경우 또한 많습니다. 투 포인터 문제는 크게 두 가지 유형이 있습니다. 정렬 후 양 옆에서 다가오는 것 left, right를 지정하고, 상황에 따라 left나 right가 ..
메모이제이션 메모이제이션이란 동일한 계산을 반복할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 실행 속도를 빠르게 하는 기술입니다. 이는 동적 계획법(Dynamic Programming)에서 핵심이 되는 기술입니다. 캐싱이라고 표현되기도 합니다. 예를 들어 재귀 함수를 사용한 피보나치 수열 함수가 있다고 해봅시다. func fibonacci(_ n: Int) -> Int { if n Int { var fiboArray: [Int] = [0, 1] guard n > 1 else { return n } for num in 2...n { fiboArray.append(fiboArray[num - 2] + fiboArray[num - 1]) } return fiboArray..
LCS LCS란 보통 최장 공통 부분수열(Longest Common Subsequence)을 의미하지만, 최장 공통 문자열(Longest Common Substring)을 말하기도 합니다. 여기에서 부분수열(Subsequence)과 문자열(Substring)의 차이는 문자열이 연속적인지 아닌지에 따라 달라지는데요, 연속적이라면 문자열(Substring)이고, 비연속적이면 부분수열(Subsequence)입니다. 다음과 같은 예시가 있다고 가정해봅시다. [AUTABBEHNSAAB, BCUAMEFKAJNAAB] 위 예시에서 AAB는 연속적이기 때문에 문자열이라고 할 수 있고, UAENAAB는 비연속적이기 때문에 부분 수열이라고 할 수 있습니다. 위에서 말한 두 가지의 LCS를 구현하는 방법에 대해 알아보겠습니..
Dev_Ted
'CS/알고리즘' 카테고리의 글 목록