커플 (2N-2, 2N-1)가 인접해서 앉고 싶은데, 그렇지 못하다면 최소로 swap하여 인접하게 앉을 수 있도록 하는 문제이다.

 

커플은 (2N-2, 2N-1)으로 (0,1), (2,3), (4,5), ...이므로 x의 파트너는 x가 짝수인 경우 x+1, 홀수인 경우 x-1이다.

먼저 array를 0부터 2자리씩 보기 시작하면서 해당 파트너와 인접하면 넘어가고,

인접하지 않으면 짝은 옆으로 데려와서 앉힌다.

 

즉, 소파에 첫번째 앉아있는 사람은 고정시키고 두번째 사람만 옮김으로써 커플을 완성하도록 한다. 

시간복잡도는 O(N^2)이고 코드는 아래와 같다.

class Solution {
	public int minSwapsCouples(int[] row) {
		int ans = 0;

		for (int i = 0; i < row.length; i += 2) {
			int x = row[i];

			if (row[i + 1] == findPartner(x)) {
				continue;
			}

			ans++;

			for (int j = i + 1; j < row.length; ++j) {
				if (row[j] == findPartner(x)) {
					row[j] = row[i + 1];
					row[i + 1] = findPartner(x);
					break;
				}
			}
		}
		return ans;
	}

	public int findPartner(int x) {
		if (x % 2 == 0) {
			return x + 1;
		}
		return x - 1;
	}
}

이 문제는 트리를 어떤 방식으로든 순회했을 때, 그 합의 최대를 구하는 문제이다.

https://leetcode.com/problems/binary-tree-maximum-path-sum/

예를 들어 위 예제의 경우 최적의 순회 방법중 하나는 15 -> 20 -> 7 이고 그 합은 15 + 20 + 7 = 42이다.

 

먼저 저번에 공부했던 tree dp처럼 어떤 노드를 기준으로 해당 서브 트리의 최대값을 구할 수 있도록 하자고 생각했다.

즉, 리프 노드의 경우는 해당 노드에 적혀있는 수를 리턴하고,

그 이외는 아래에서부터 올라오면서 최대 값을 해당 노드에 저장하는 식이다.

 

이러한 경우 시간복잡도는 O(N)으로 볼 수 있으며 풀이는 아래와 같다.

class Solution {
	int answer = Integer.MIN_VALUE;

	public int findMaxNode(TreeNode node) {
		if (node == null) {
			return 0;
		}

		int leftValue = Math.max(findMaxNode(node.left), 0);
		int rightValue = Math.max(findMaxNode(node.right), 0);

		int newValue = node.val + leftValue + rightValue;

		answer = Math.max(answer, newValue);

		return node.val + Math.max(leftValue, rightValue);
	}

	public int maxPathSum(TreeNode root) {
		findMaxNode(root);
		return answer;
	}
}

'알고리즘 공부 > leetcode' 카테고리의 다른 글

leetcode: Target Sum  (0) 2021.01.27
leetcode: Couples Holding Hands  (0) 2021.01.24
leetcode: Maximum Frequency Stack  (0) 2021.01.23
leetcode: Range Sum Query - Mutable  (0) 2021.01.10
leetcode: 01 Matrix  (0) 2021.01.08

FreqStack has two functions:

  • push(int x), which pushes an integer x onto the stack.
  • pop(), which removes and returns the most frequent element in the stack.
    • If there is a tie for most frequent element, the element closest to the top of the stack is removed and returned.

두가지 자료구조를 사용한다.

  • frequency: (key, value) -> 값 key에 대한 빈도수 value를 저장한 자료구조
  • frequencyValueStack: (key, stack) -> 빈도수 key에 대해 값 stack을 저장한 자료구조
  • maxfrequency: 가장 많은 빈도수를 저장
import java.util.*;
class FreqStack {
	Map<Integer, Integer> frequency;
	Map<Integer, Stack<Integer>> frequencyValueStack;
	int maxfreq;

	public FreqStack() {
		frequency = new HashMap<Integer, Integer>();
		frequencyValueStack = new HashMap<Integer, Stack<Integer>>();
		maxfreq = 0;
	}

	public void push(int x) {
		int xFrequency = frequency.getOrDefault(x, 0) + 1;
		frequency.put(x, xFrequency);
		if (xFrequency > maxfreq) {
			maxfreq = xFrequency;
		}

		/*
		 * implement a multi-value map, Map<K,Collection<V>>, 
		 * supporting multiple values per key: 
		 * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
		 */
		frequencyValueStack.computeIfAbsent(xFrequency, stack -> new Stack<Integer>()).push(x);
	}

	public int pop() {
		int x = frequencyValueStack.get(maxfreq).pop();
		
		frequency.put(x, frequency.get(x) - 1);
		if (frequencyValueStack.get(maxfreq).size() == 0) {
			maxfreq--;
		}
		return x;
	}
}

 

'알고리즘 공부 > leetcode' 카테고리의 다른 글

leetcode: Couples Holding Hands  (0) 2021.01.24
leetcode: Binary Tree Maximum Path Sum  (0) 2021.01.24
leetcode: Range Sum Query - Mutable  (0) 2021.01.10
leetcode: 01 Matrix  (0) 2021.01.08
leetcode: Number of Islands  (0) 2021.01.07

세그먼트 트리란?

주어진 쿼리에 대해 빠르게 응답하기 위해 만들어진 자료구조로, 주로 구간 합을 다룰 때 많이 사용한다.

대부분 완전 이진 트리로 구성된다.

 

세그먼트 트리에서는

수를 바꾸는 과정 :: O(lgN)

수를 더하는 과정 :: O(lgN)으로 변하게 된다.

M번 실행한다 치면 O(MlgN + MlgN) -> O(MlgN)이 걸리게 된다.



 

 

https://leetcode.com/problems/range-sum-query-mutable/

class NumArray {
	int[] tree;
	int n;

	public NumArray(int[] nums) {
		if (nums.length > 0) {
			n = nums.length;
			tree = new int[n * 2];
			buildTree(nums);
		}
	}

	private void buildTree(int[] nums) {
		for (int i = n, j = 0; i < 2 * n; i++, j++)
			tree[i] = nums[j];
		for (int i = n - 1; i > 0; --i)
			tree[i] = tree[i * 2] + tree[i * 2 + 1];
	}

	void update(int pos, int val) {
		pos += n;
		tree[pos] = val;
		while (pos > 0) {
			int left = pos;
			int right = pos;
			if (pos % 2 == 0) {
				right = pos + 1;
			} else {
				left = pos - 1;
			}

			tree[pos / 2] = tree[left] + tree[right];
			pos /= 2;
		}
	}

	public int sumRange(int l, int r) {
		l += n;
		r += n;
		int sum = 0;
		while (l <= r) {
			if ((l % 2) == 1) {
				sum += tree[l];
				l++;
			}
			if ((r % 2) == 0) {
				sum += tree[r];
				r--;
			}
			l /= 2;
			r /= 2;
		}
		return sum;
	}
}

세그먼트 트리에 대해 좀 더 공부해 봐야겠다...

'알고리즘 공부 > leetcode' 카테고리의 다른 글

leetcode: Binary Tree Maximum Path Sum  (0) 2021.01.24
leetcode: Maximum Frequency Stack  (0) 2021.01.23
leetcode: 01 Matrix  (0) 2021.01.08
leetcode: Number of Islands  (0) 2021.01.07
leetcode: Trapping Rain Water  (0) 2020.12.27

방법1 - 각 cell에서 1인 부분을 큐에 넣고 bfs를 통해 0까지의 최소 거리를 찾는다.

import java.util.*;
class Solution {
	public static int dr[] = { 0, 0, 1, -1 };
	public static int dc[] = { 1, -1, 0, 0 };

	public int[][] updateMatrix(int[][] matrix) {
		Queue<Position> queue = new LinkedList<Position>();
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				if (matrix[i][j] != 0) {
					queue.add(new Position(i, j, 0));
				}
			}
		}

		while (!queue.isEmpty()) {
			Position now = queue.poll();
			updateCell(now.row, now.col, matrix);
		}
		return matrix;
	}

	public void updateCell(int row, int col, int[][] matrix) {
		Queue<Position> queue = new LinkedList<Position>();
		queue.add(new Position(row, col, 0));

		while (!queue.isEmpty()) {
			Position now = queue.poll();

			if (matrix[now.row][now.col] == 0) {
				matrix[row][col] = now.value;
				return;
			}

			for (int i = 0; i < 4; i++) {
				int newRow = now.row + dr[i];
				int newCol = now.col + dc[i];

				if (isBoundary(newRow, newCol, matrix)) {
					queue.add(new Position(newRow, newCol, now.value + 1));
				}
			}
		}
	}

	public boolean isBoundary(int row, int col, int[][] matrix) {
		if (row < 0 || row >= matrix.length) {
			return false;
		}
		if (col < 0 || col >= matrix[row].length) {
			return false;
		}
		return true;
	}

	public void printMatrix(int[][] matrix) {
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				System.out.print(matrix[i][j] + " ");
			}
			System.out.println();
		}
	}
}

class Position {
	int row, col, value;

	public Position(int row, int col, int value) {
		this.row = row;
		this.col = col;
		this.value = value;
	}
}

 

방법2 - 어차피 matrix에 거리를 계속 업데이트 하고 있는데 이 것을 이용해서 다음 값을 구할 수 없을까? => DP

class Solution {
	public int[][] updateMatrix(int[][] matrix) {
		int n = matrix.length;
		int m = matrix[0].length;
		int[][] dp = matrix;
		int INF = 10000;

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (matrix[i][j] == 1) {
					dp[i][j] = INF;
				}
			}
		}

		for (int i = 1; i < n; i++) {
			dp[i][0] = Math.min(dp[i][0], dp[i - 1][0] + 1);
		}
		for (int i = 1; i < m; i++) {
			dp[0][i] = Math.min(dp[0][i], dp[0][i - 1] + 1);
		}

		for (int i = 1; i < n; i++) {
			for (int j = 1; j < m; j++) {
				dp[i][j] = Math.min(dp[i][j], Math.min(dp[i][j - 1], dp[i - 1][j]) + 1);
			}
		}

		for (int i = n - 2; i >= 0; i--) {
			dp[i][m - 1] = Math.min(dp[i + 1][m - 1] + 1, dp[i][m - 1]);
		}
		for (int i = m - 2; i >= 0; i--) {
			dp[n - 1][i] = Math.min(dp[n - 1][i + 1] + 1, dp[n - 1][i]);
		}

		for (int i = n - 2; i >= 0; i--) {
			for (int j = m - 2; j >= 0; j--) {
				dp[i][j] = Math.min(dp[i][j], Math.min(dp[i][j + 1], dp[i + 1][j]) + 1);
			}
		}

		return dp;
	}
}

'알고리즘 공부 > leetcode' 카테고리의 다른 글

leetcode: Maximum Frequency Stack  (0) 2021.01.23
leetcode: Range Sum Query - Mutable  (0) 2021.01.10
leetcode: Number of Islands  (0) 2021.01.07
leetcode: Trapping Rain Water  (0) 2020.12.27
leetcode: Median of two sorted Arrays  (0) 2020.12.26

전형적인 bfs문제이다. 

시간복잡도는 O(grid 요소의 갯수)와 같다.

import java.util.*;
class Solution {
	public static int dr[] = { 0, 1, 0, -1 };
	public static int dc[] = { 1, 0, -1, 0 };

	public int numIslands(char[][] grid) {
		int answer = 0;

		for (int i = 0; i < grid.length; i++) {
			for (int j = 0; j < grid[i].length; j++) {
				if (grid[i][j] == '1') {
					answer++;
					grid[i][j] = '0';
					bfs(i, j, grid);
				}
			}
		}
		return answer;
	}

	public static void bfs(int row, int col, char[][] grid) {
		Queue<Position> queue = new LinkedList<Position>();
		queue.add(new Position(row, col));

		while (!queue.isEmpty()) {
			Position now = queue.poll();

			for (int i = 0; i < 4; i++) {
				int newRow = now.row + dr[i];
				int newCol = now.col + dc[i];

				if (isBoundary(newRow, newCol, grid) && grid[newRow][newCol] == '1') {
					grid[newRow][newCol] = '0';
                    queue.add(new Position(newRow, newCol));
				}
			}
		}
	}

	public static boolean isBoundary(int row, int col, char[][] grid) {
		if (row < 0) {
			return false;
		}
		if (row >= grid.length) {
			return false;
		}
		if (col < 0) {
			return false;
		}
		if (col >= grid[row].length) {
			return false;
		}

		return true;
	}
}

class Position {
	int row, col;

	public Position(int row, int col) {
		this.row = row;
		this.col = col;
	}
}

브루트포스 방법으로 양 옆을 다 보는 방법의 경우 시간복잡도 O(N^2)이 걸릴 것이다.

 

이 문제의 경우 아래와 같이 왼쪽에  있는 높이 중에서 가장 높은 높이만 보고 있는 상태이므로

=> 스택을 사용한다면 O(N)만에 문제를 풀 수 있다.

https://leetcode.com/problems/trapping-rain-water/

문제풀이 로직은 아래와 같다.

1. index를 오른쪽으로 움직이면서 스택의 맨 위에 담은 높이와 비교했을때 height[index]이 크거나 같으면 스택에 담는다.

2. 높이가 바뀌면 이전까지 물을 계산해서 answer에 더해주며, 이전 높이는 pop 시켜준다.

import java.util.*;
class Solution {
	public int trap(int[] height) {
		int answer = 0;

		Stack<Integer> stack = new Stack<Integer>();
		int index = 0;
		while (index < height.length) {
			while (!stack.isEmpty() && height[index] >= height[stack.peek()]) {
				int top = stack.pop();

				if (stack.isEmpty()) {
					break;
				}
				int distance = index - stack.peek() - 1;
				int bounded_height = Math.min(height[index], height[stack.peek()]) - height[top];
				answer += distance * bounded_height;
			}
			stack.push(index++);
		}

		return answer;
	}
}

'알고리즘 공부 > leetcode' 카테고리의 다른 글

leetcode: 01 Matrix  (0) 2021.01.08
leetcode: Number of Islands  (0) 2021.01.07
leetcode: Median of two sorted Arrays  (0) 2020.12.26
leetcode: Letter Combinations of a Phone number  (0) 2020.12.26
leetcode: Palindrome Partitioning  (0) 2020.12.26
class Solution {
	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
		int nums1Length = nums1.length;
		int nums2Length = nums2.length;

		int size = nums1Length + nums2Length;

		int nums1Index = 0;
		int nums2Index = 0;
		int mergedArray[] = new int[size];
		int index = 0;
		while (true) {

			if (nums1Index >= nums1Length && nums2Index >= nums2Length) {
				break;
			} else if (nums1Index >= nums1Length) {
				mergedArray[index++] = nums2[nums2Index++];
			} else if (nums2Index >= nums2Length) {
				mergedArray[index++] = nums1[nums1Index++];
			} else if (nums1[nums1Index] > nums2[nums2Index]) {
				mergedArray[index++] = nums2[nums2Index++];
			} else {
				mergedArray[index++] = nums1[nums1Index++];
			}
		}

		if (size % 2 == 0) {
			return (mergedArray[size / 2] + mergedArray[size / 2 - 1]) / (double) 2;
		}
		return mergedArray[size / 2];
	}
}

N=nums1.length, M=nums2.length라고 두면

위 방법대로 푼다면 시간복잡도는 O(N+M)이 나오고,

mergedArray라는 새 자료구조로 nums1, nums2를 옮겨야 하기 때문에 추가적인 공간 복잡도는 O(N+M)가 된다.

 

 

문제에서는 제시되지 않았으나, nums1, nums2가 정렬되어있다고 치고 이분탐색으로 문제를 푼다면 O(log(N+M)) 풀이도 가능하다.

class Solution {
	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
		if (nums2.length < nums1.length) { // 짧은 길이를 nums1로 둔다.
			return findMedianSortedArrays(nums2, nums1);
		}

		int start = 0;
		int end = nums1.length;
		int size = nums1.length + nums2.length;

		while (start < end) {
			int p1 = (start + end) / 2;
			int p2 = (size + 1) / 2 - p1;

			if (p1 == 0 || nums1[p1 - 1] <= nums2[p2]) {
				if (p2 == 0 || nums2[p2 - 1] <= nums1[p1]) {
					break;
				} else {
					start = p1 + 1;
				}
			} else {
				end = p1 - 1;
			}
		}

		int p1 = (start + end) / 2;
		int p2 = (size + 1) / 2 - p1;
		int m = Integer.MIN_VALUE;
		int n = Integer.MAX_VALUE;
		if (size % 2 == 1) {
			return Math.max(p1 - 1 >= 0 ? nums1[p1 - 1] : m, p2 - 1 >= 0 ? nums2[p2 - 1] : m);
		} else {
			return (Math.max(p1 - 1 >= 0 ? nums1[p1 - 1] : m, p2 - 1 >= 0 ? nums2[p2 - 1] : m)
					+ Math.min(p1 < nums1.length ? nums1[p1] : n, p2 < nums2.length ? nums2[p2] : n)) / 2.0;
		}
	}
}

 

 

마지막으로 아래는 O(min(N,M)) 풀이이다. 이 풀이는 이해하기 어렵지만 일단 추가해둔다... 시간날때 읽어봐야지...

leetcode.com/problems/median-of-two-sorted-arrays/discuss/2481/Share-my-O(log(min(mn)))-solution-with-explanation

 

Share my O(log(min(m,n))) solution with explanation - LeetCode Discuss

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

+ Recent posts