배열과 연결 리스트 알고리즘 기초

시간 복잡도

알고리즘 분석 시 시간과 공간 복잡도를 우선 고려합니다. O(n³) 이상의 복잡도는 실제 환경에서 비효율적입니다. n은 데이터 규모를 나타내며, 로그 복잡도(log n)는 연산 횟수가 데이터 크기에 로그적으로 비례함을 의미합니다.

배열

이진 탐색

정렬된 배열에서 중복 없을 때 적용 가능합니다. 탐색 구간을 반으로 축소하며 대상 값을 검색합니다.

class BinarySearcher {
    int findTarget(int[] data, int target) {
        int low = 0;
        int high = data.length - 1;
        
        while (low <= high) {
            int pivot = low + (high - low) / 2;
            if (data[pivot] > target) {
                high = pivot - 1;
            } else if (data[pivot] < target) {
                low = pivot + 1;
            } else {
                return pivot;
            }
        }
        return -1;
    }
}

시간 복잡도: O(log n)

요소 제거

빠른 포인터와 느린 포인터를 활용해 효율적으로 요소를 제거합니다.

class ElementRemover {
    int filterValues(int[] data, int removeVal) {
        int slow = 0;
        for (int fast = 0; fast < data.length; fast++) {
            if (data[fast] != removeVal) {
                data[slow++] = data[fast];
            }
        }
        return slow;
    }
}

시간 복잡도: O(n), 공간 복잡도: O(1)

정렬된 배열 제곱

양끝 포인터로 최대 제곱값을 비교하며 새 배열에 역순으로 저장합니다.

class SquareSorter {
    int[] sortedSquares(int[] nums) {
        int left = 0, right = nums.length - 1;
        int[] output = new int[nums.length];
        int idx = output.length - 1;
        
        while (left <= right) {
            int leftSq = nums[left] * nums[left];
            int rightSq = nums[right] * nums[right];
            if (leftSq >= rightSq) {
                output[idx--] = leftSq;
                left++;
            } else {
                output[idx--] = rightSq;
                right--;
            }
        }
        return output;
    }
}

시간 복잡도: O(n)

최소 길이 부분 배열

슬라이딩 윈도우 기법으로 목표 합을 만드는 최소 길이 구간을 탐색합니다.

class SubarrayFinder {
    int minSubArray(int target, int[] nums) {
        int start = 0, total = 0;
        int minLength = Integer.MAX_VALUE;
        
        for (int end = 0; end < nums.length; end++) {
            total += nums[end];
            while (total >= target) {
                minLength = Math.min(minLength, end - start + 1);
                total -= nums[start++];
            }
        }
        return minLength == Integer.MAX_VALUE ? 0 : minLength;
    }
}

시간 복잡도: O(n)

스파이럴 행렬

레이어별로 외곽부터 내부까지 시계방향으로 숫자를 채웁니다.

class SpiralGenerator {
    int[][] generateSpiral(int n) {
        int[][] grid = new int[n][n];
        int layer = 0, start = 0, counter = 1;
        
        while (layer++ < n / 2) {
            for (int col = start; col < n - layer; col++) 
                grid[start][col] = counter++;
            for (int row = start; row < n - layer; row++) 
                grid[row][n - layer] = counter++;
            for (int col = n - layer - 1; col >= layer; col--) 
                grid[n - layer][col] = counter++;
            for (int row = n - layer - 1; row >= layer; row--) 
                grid[row][start] = counter++;
            start++;
        }
        if (n % 2 == 1) grid[start][start] = counter;
        return grid;
    }
}

시간 복잡도: O(n²)

연결 리스트

노드가 데이터와 포인터로 구성된 선형 구조입니다. 단일/이중/순환 연결 리스트 유형이 존재합니다.

요소 제거

가상 헤드 노드를 활용해 경계 조건을 단순화합니다.

class ListCleaner {
    ListNode removeElements(ListNode head, int target) {
        if (head == null) return null;
        ListNode dummyHead = new ListNode(0, head);
        ListNode prev = dummyHead;
        ListNode curr = head;
        
        while (curr != null) {
            if (curr.val == target) {
                prev.next = curr.next;
            } else {
                prev = curr;
            }
            curr = curr.next;
        }
        return dummyHead.next;
    }
}

태그: 이진탐색 투포인터 슬라이딩윈도우 스파이럴행렬

7월 11일 02:49에 게시됨