반응형

# 50. Pow(x, n)

x^n 을 구하는 문제

 

단순히 x 를 n 번 곱해서 문제를 해결할 수도 있지만, 그렇게 해결할 경우 n 이 INT_MIN ~ INT_MAX 범위를 갖기 때문에 시간초과가 날 것으로 생각된다.

때문에 이 방식이 아니라 조금 더 현명하게 문제를 해결하고자 한 방법이 이진법을 생각한 것이었다. 이진법의 경우, 각 자릿수가 2의 승수를 의미하는데 (네 자리라면 8, 4, 2, 1 이런식으로) 각 자리별로 bit 가 1이면 해당 값을 더하고, 0이면 패스하는 식으로 이루어진다.

이 문제는 x 의 n 승을 구하는 문제이므로 더하는 게 아니라 해당 값을 곱하는 방식으로 문제를 풀었다.

추가로, 처음에는 n 이 음수일 경우 값을 나눠주도록 해서 문제를 해결하려 했는데 일반적으로 곱셈보다 나눗셈이 더 시간이 많이 걸린다는 사실을 알지 못했다. 그래서 시간초과가 발생하는 걸 보고, 우선 값을 다 곱해준 뒤 나누기를 해 주는 방식으로 문제를 해결했다.

 

double myPow(double x, int n) {
    double ans = 1;
    bool neg = n < 0;

    while (n){
        if (n & 1)
            ans *= x;
        x *= x;
        n /= 2;
    }

    if (neg){
        ans = 1 / ans;
    }
    return ans;
}

# 53. Maximum Subarray

배열이 주어졌을 때, 해당 배열의 연속된 SubArray 중 가장 큰 합을 갖는 경우의 합을 구하는 문제

 

DP 의 대표적인 유형 문제로, 배열을 순차 탐색하면서 (이전 인덱스까지의 최대 합 + 현재 인덱스의 값) 과 (현재 인덱스의 값) 을 비교해 더 큰 값을 저장해 나가는 방식으로 문제를 해결했다.

 

int maxSubArray(vector<int>& nums) {
    if (nums.size() == 1)
        return nums[0];
    int max_sum = nums[0];
    int cur_sum = nums[0];

    for (int i = 1; i<nums.size(); i++){
        cur_sum = max(cur_sum + nums[i], nums[i]);
        max_sum = max(max_sum, cur_sum);
    }
    return max_sum;
}

# 54. Spiral Matrix

M * N 행렬이 주어졌을 때, 해당 행렬을 나선형으로 탐색한 결과를 구하는 문제

 

이 문제는, BFS 문제를 풀 때 주로 사용한 방식으로 문제를 해결했다.

{오른쪽, 아래, 왼쪽, 위} 방향으로 이동할 때의 인덱스 변화량을 미리 저장해 두고 방향만 바꾸는 방식으로 순서대로 탐색을 했다.

이미 탐색한 위치인 경우, 값을 INT_MIN 값으로 바꿔주어서 다시 탐색하지 않도록 하고 행렬의 범위를 벗어나는 경우 방향을 바꾸도록 했다.

 

int dy[4] = { 0, 1, 0, -1 }, dx[4] = { 1, 0, -1, 0 };

vector<int> spiralOrder(vector<vector<int>>& matrix) {
	int dir = 0, cy, cx;
	int n = matrix.size(), m = matrix[0].size();
	int size = n * m;
	vector<int> ans;
	cy = cx = dir = 0;
	while (size--) {
		ans.push_back(matrix[cy][cx]);
		matrix[cy][cx] = INT_MIN;
		int ny = cy + dy[dir], nx = cx + dx[dir];
		if (ny < 0 || ny >= n || nx < 0 || nx >= m) {
			dir = (dir + 1) % 4;
			ny = cy + dy[dir], nx = cx + dx[dir];
		}
		else if (matrix[ny][nx] == INT_MIN) {
			dir = (dir + 1) % 4;
			ny = cy + dy[dir], nx = cx + dx[dir];
		}
		cy = ny, cx = nx;
	}
	return ans;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 58, 59, 61] 문제 풀이  (0) 2021.04.28
[LeetCode # 55 ~ 57] 문제 풀이  (0) 2021.04.07
[LeetCode # 47 ~ 49] 문제 풀이  (0) 2021.04.02
[LeetCode # 43, 45, 46] 문제 풀이  (0) 2021.04.01
[LeetCode # 38 ~ 40] 문제 풀이  (0) 2021.03.30
반응형

# 47. Permutations II

# 46. 과 유사하지만, 주어진 배열에 중복값이 있을 수 있어 Unique 한 순열을 찾기 위한 조건이 하나 추가된 문제

 

배열에 중복값이 존재하기 때문에, 배열을 우선 정렬을 하고 문제 풀이를 시작했고,

앞서 DFS 방식으로 문제를 해결한 부분에 추가적으로 적용한 조건이 이미 해당 위치에서 사용한 값은 넘기도록 하는 조건을 추가했다.

 

void recursivePermutation(vector<vector<int>>& ans, vector<int>& nums, vector<int>& cur, bool used[]){
    if (nums.size() == cur.size()){
        ans.push_back(cur);
        return;
    }
    int prev = -30;

    for (int i = 0; i<nums.size(); i++){
        if (used[i])
            continue;
        if (prev != -30 && prev == nums[i])
            continue;
        prev = nums[i];
        used[i] = true;
        cur.push_back(nums[i]);
        recursivePermutation(ans, nums, cur, used);
        cur.pop_back();
        used[i] = false;
    }
}

vector<vector<int>> permuteUnique(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> ans;
    vector<int> vec;
    bool used[10];
    recursivePermutation(ans, nums, vec, used);

    return ans;
}

# 48. Rotate Image

주어진 Matrix 를 우측으로 90도 회전하는 문제

 

이 문제는, 처음 마주했을 때 그 위치를 어떻게 계산해서 바꿔줄까를 고민하고 있었는데 그러던 중 Solution 을 보고 그 방법이 너무 간단해서 그 방법대로 문제를 해결하게 되었다.

어떤 행렬을 우측으로 90도 회전하는 것은, 그 행렬의 전치행렬을 구하고 col 을 reverse 하게 되면 우측으로 90도 회전한 것과 같아진다는 것이 그 방법이었다.

 

void rotate(vector<vector<int>>& matrix) {
    int n = matrix[0].size();

    for (int i = 0; i < n; i++){
        for (int j = i; j < n; j++){
            swap(matrix[i][j], matrix[j][i]);
        }
    }
    for (int j = 0; j < (n + 1) / 2; j++){
        for (int i = 0; i<n; i++){
            swap(matrix[i][j], matrix[i][n - j - 1]);
        }
    }
}

# 49. Group Anagrams

문자열 배열이 주어졌을 때, 문자열들을 Anagram* 끼리 그룹을 묶어 주는 문제

* Anagram 이란, 문자열에 속한 문자들이 같은 경우를 Anagram 이라 한다.

 

이 문제는, 해시테이블을 활용하면 쉽게 해결할 수 있을 거라 생각했다.

우선, 각 문자열들이 동일한 문자를 갖는 지를 확인하기 위한 방법으로 각각의 문자열들을 정렬하고, 정렬된 문자열을 Key 로 리스트에 저장하는 방식으로 문제를 해결했다.

최종적으로는 해시테이블을 벡터로 변환해서 Return 해서 문제를 간단하게 해결했다.

 

vector<vector<string>> groupAnagrams(vector<string>& strs) {
    map<string, vector<string>> table;

    for (string str : strs){
        string sorted = str;
        sort(sorted.begin(), sorted.end());

        map<string, vector<string>>::iterator it = table.find(sorted);
        if (it != table.end()){
            // Sorted String 을 Key 로 갖는 List 가 있을 때
            it->second.push_back(str);
        }
        else {
            vector<string> v = {str};
            table.insert(make_pair(sorted, v));
        }
    }
    vector<vector<string>> ans;
    for(map<string, vector<string>>::iterator it = table.begin(); it != table.end(); it++){
        ans.push_back(it->second);
    }
    return ans;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 55 ~ 57] 문제 풀이  (0) 2021.04.07
[LeetCode # 50, 53, 54] 문제 풀이  (0) 2021.04.06
[LeetCode # 43, 45, 46] 문제 풀이  (0) 2021.04.01
[LeetCode # 38 ~ 40] 문제 풀이  (0) 2021.03.30
[LeetCode # 34 ~ 36] 문제 풀이  (0) 2021.03.24
반응형

# 43. Multiply Strings

정수를 표현하는 문자열 2개가 주어졌을 때, 해당 정수들의 곱을 구하는 문제

정수형으로 표현 가능한 범위를 초과하기 때문에 타입 변환 후 곱셈을 수행하는 방식으로는 해결이 불가능

 

해당 문제를 보고 처음 든 생각은, 처음 곱셈을 배울 때 한자리씩 곱셈을 수행하고 그 결과를 더하는 방식이었다.

문자열이기 때문에 곱셈을 수행할 수는 없고, 한 자리씩 수행을 한다면 문제를 해결할 수 있을 것이라 생각했다.

하지만 단순히 이런 방식으로는 문제 해결이 불가능했고(시간 초과), 다소 최적화가 필요한 부분이 있어 해당 부분을 적용했다.

최적화를 한 방식은, 두 수를 곱했을 때 결과로 나올 수 있는 자리수는 두 자리수의 합이기 때문에 미리 문자열을 해당 사이즈만큼 선언해 놓고 그 문자열에 값을 더하는 방식으로 문제를 해결하는 것이었다.

 

string multiply(string num1, string num2) {
	string sum(num1.size() + num2.size(), '0');

	for (int i = num1.size() - 1; i >= 0; i--) {
		int carry = 0;
		for (int j = num2.size() - 1; j >= 0; j--) {
			int tmp = (sum[i + j + 1] - '0') + (num1[i] - '0') * (num2[j] - '0') + carry;
			sum[i + j + 1] = tmp % 10 + '0';
			carry = tmp / 10;
		}
		sum[i] += carry;
	}

	int startpos = sum.find_first_not_of("0");
	if (startpos != string::npos)
		return sum.substr(startpos);
	return "0";
}

# 45. Jump Game II

0 이 아닌 수들로 이루어진 배열이 주어졌을 때, 최소한의 점프* 로 마지막 인덱스에 도달할 수 있는 점프 횟수를 구하는 문제

* 각 배열의 값들은 해당 위치에서 점프를 뛸 수 있는 최대 거리

 

이 문제는 전형적인 DP 문제라고 생각하고 문제를 해결했다.

시작 인덱스부터 탐색을 해나가며 각 인덱스 위치에서 점프를 뛸 수 있는 각각의 인덱스로 점프를 뛰고, 최소한의 점프로 해당 인덱스에 도달한 점프 횟수를 저장하는 방식으로 문제를 풀 수 있었다.

 

int jump(vector<int>& nums) {
    int len = nums.size();
    int ans[1001] = {0, };

    for (int i = 0; i<len; i++){
        for (int k = 1; k <= nums[i] && i + k < len; k++){
            if (ans[i + k] == 0 || ans[i] + 1 < ans[i + k]){
                ans[i + k] = ans[i] + 1;
            }
        }
    }
    return ans[len - 1];
}

# 46. Permutations

정수형 배열이 주어졌을 때, 이 배열로 만들 수 있는 모든 순열을 만드는 문제

 

이 문제는 전형적인 dfs 문제로, 어떤 값이 사용되었는지 사용되지 않았는지를 저장해 나가며 그 값이 사용되지 않은 값이라면 추가하고, 사용된 값이라면 Pass 하는 방식으로 문제를 해결할 수 있었다.

 

void recursivePermutation(vector<vector<int>>& ans, vector<int>& nums, vector<int>& cur, bool used[]){
    if (nums.size() == cur.size()){
        ans.push_back(cur);
        return;
    }
    for (int i = 0; i<nums.size(); i++){
        if (used[i])
            continue;
        used[i] = true;
        cur.push_back(nums[i]);
        recursivePermutation(ans, nums, cur, used);
        cur.pop_back();
        used[i] = false;
    }
}

vector<vector<int>> permute(vector<int>& nums) {
    vector<vector<int>> ans;
    vector<int> vec;
    bool used[10];
    recursivePermutation(ans, nums, vec, used);

    return ans;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 50, 53, 54] 문제 풀이  (0) 2021.04.06
[LeetCode # 47 ~ 49] 문제 풀이  (0) 2021.04.02
[LeetCode # 38 ~ 40] 문제 풀이  (0) 2021.03.30
[LeetCode # 34 ~ 36] 문제 풀이  (0) 2021.03.24
[LeetCode # 31 ~ 33] 문제 풀이  (0) 2021.03.21
반응형

# 38. Count and Say

숫자 n 이 주어졌을 때, n-1 로 만들어지는 문자열의 숫자를 Count 하는 문제

CountAndSay(n) = CountAndSay(CountAndSay(n-1))

CountAndSay(1) = "1"

 

ex) CountAndSay(2) = CountAndSay(CountAndSay(1)) = CountAndSay("1")
"1" --> One 1 => "11"

 

이 문제는 Recursive Function 을 만들어서 C&S(1) ~ C&S(n) 까지 만들어 나가는 식으로 해결했다.

C&S(1) 은 위와 같이 단순 "1"이고, C&S(2) 부터는 해당 문자열을 탐색하면서 연속되는 숫자의 개수를 확인하는 방식으로 해당 Index 문제를 해결할 수 있도록 했다.

 

string recursive(int n) {
	if (n == 1)
		return "1";
	string child = recursive(n - 1), ret = "";
	int cur = child[0] - '0', cnt = 1;
	for (int i = 1; i <= child.length(); i++) {
		if (i == child.length()) {
			ret += to_string(cnt);
			ret += to_string(cur);
			break;
		}
		if (child[i] - '0' == cur) {
			cnt++;
		}
		else {
			ret += to_string(cnt);
			ret += to_string(cur);
			cur = child[i] - '0';
			cnt = 1;
		}
	}
	return ret;
}

string countAndSay(int n) {
	return recursive(n);
}

# 39. Combination Sum

정수형 배열이 주어지고 목표로 하는 값이 주어졌을 때, 더해서 주어진 값을 만들 수 있는 경우를 모두 찾는 문제.

* 배열에는 중복된 값이 주어지지 않고 배열에서 하나의 값이 여러 번 사용될 수 있다.

 

이 문제는 DFS 방식으로 문제를 풀었는데 함수 인자로 현재 탐색 중인 배열의 인덱스 값을 주고 그 위치부터 뒤로만 값을 추가할 수 있도록 했다. 최적화한 부분은, 현재까지의 합이 목표값을 넘어간 경우 탐색을 중단하도록 했다.

 

void recursiveSearch(vector<vector<int>>& ans, vector<int>& candidates, int idx, vector<int>& cur_vec, int cur_sum, int target) {
	if (cur_sum > target)
		return;
	if (cur_sum == target) {
		ans.push_back(cur_vec);
		return;
	}

	for (int i = idx; i < candidates.size(); i++) {
		cur_vec.push_back(candidates[i]);
		recursiveSearch(ans, candidates, i, cur_vec, cur_sum + candidates[i], target);
		cur_vec.pop_back();
	}
}

vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
	vector<vector<int>> ans;
	vector<int> tmp;
	recursiveSearch(ans, candidates, 0, tmp, 0, target);
	return ans;
}

# 40. Combination Sum II

# 39. 와 유사하지만 차이점은, 배열에 중복값이 존재한다는 점과 Target 값을 만드는 조합이 유일해야 한다는 차이가 있는 문제

 

이 문제도 위와 마찬가지로 DFS 방식으로 문제를 해결했는데 중복된 값이 동일한 위치에 두 번 이상 사용되면 안 되기 때문에 함수 인자로 인덱스를 사용했고, 현재 인덱스 값과 다음 인덱스 값이 같을 경우 그 값을 넘기고 탐색하도록 했다.

 

void recursiveSearch(vector<vector<int>>& ans, vector<int>& candidates, int idx, vector<int>& cur_vec, int cur_sum, int target) {
	if (cur_sum > target)
		return;
	if (cur_sum == target) {
		ans.push_back(cur_vec);
		return;
	}

	for (int i = idx; i < candidates.size(); i++) {
		cur_vec.push_back(candidates[i]);
		recursiveSearch(ans, candidates, i + 1, cur_vec, cur_sum + candidates[i], target);
		cur_vec.pop_back();

		while (i < candidates.size() - 1 && candidates[i] == candidates[i + 1])
			i++;
	}
}

vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
	sort(candidates.begin(), candidates.end());

	vector<vector<int>> ans;
	vector<int> tmp;
	recursiveSearch(ans, candidates, 0, tmp, 0, target);
	return ans;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 47 ~ 49] 문제 풀이  (0) 2021.04.02
[LeetCode # 43, 45, 46] 문제 풀이  (0) 2021.04.01
[LeetCode # 34 ~ 36] 문제 풀이  (0) 2021.03.24
[LeetCode # 31 ~ 33] 문제 풀이  (0) 2021.03.21
[LeetCode # 26 ~ 28] 문제 풀이  (0) 2021.03.19
반응형

# 34. Find First and Last Position of Element in Sorted Array

정렬된 정수 Array 와 Target 정수값이 주어졌을 때, 해당 Target 값이 나타나는 인덱스의 시작 위치와 끝 위치를 찾는 문제.

* O(logN) 에 해결할 수 있는지.

 

이 문제는 전형적인 Binary Search 로 생각해 풀었다. Binary Search 탐색을 위해 시작/끝 인덱스를 사용하고 그 값을 찾았을 경우에 left  / right 값에 현재까지 찾은 값들 중 가장 작은, 큰 인덱스 값을 대입하도록 했다.

 

void binarySearch(vector<int>& v, int t, int s, int e, int &l, int &r) {
	if (s >= e) {
		if (s == e && v[s] == t) {
			if (l == -1 || s < l)
				l = s;
			if (r == -1 || s > r)
				r = s;
		}
		return;
	}
	int m = (s + e) / 2;
	binarySearch(v, t, s, m, l, r);
	binarySearch(v, t, m + 1, e, l, r);
}

vector<int> searchRange(vector<int>& nums, int target) {
	if (nums.empty()) {
		vector<int> ans = { -1, -1 };
		return ans;
	}

	int left, right;
	left = right = -1;
	binarySearch(nums, target, 0, nums.size() - 1, left, right);
	vector<int> ans = { left, right };
	return ans;
}

# 35. Search Insert Position

중복되지 않는 정렬된 정수형 Array 가 주어졌을 때, Target 값을 주고 그 값이 존재한다면 그 인덱스 위치를, 존재하지 않으면 그 값이 들어가야 할 인덱스 위치를 찾는 문제.

 

이 문제도 마찬가지로 전형적인 Binary Search 문제로 생각되어 풀었는데 굳이 Binary Search 를 사용하지 않고 라이브러리 함수를 사용해 문제를 해결했다. lower_bound 를 사용했지만 중복되는 값이 없기 때문에 upper_bound 를 사용했어도 결과는 같을 것으로 생각된다.

 

int searchInsert(vector<int>& nums, int target) {
	vector<int>::iterator it = lower_bound(nums.begin(), nums.end(), target);
	return (it - nums.begin());
}

# 36. Valid Sudoku

스도쿠가 주어졌을 때, 이 스도쿠가 제대로 구성되었는지 확인하는 문제

* 이 스도쿠 문제를 해결 가능한 지를 보는 것이 아니라, 현재 상태에서 오류가 없는 지만 확인.

 

단순하게 문제를 해결하는 방식으로 구현했다. 각 Row, Col, Box 별로 저장되어 있는 값을 확인해서 중복되는 값이 없는 지를 확인하도록 했다.

 

bool check_row[9][10];
bool check_col[9][10];
bool check_box[9][10];

bool isValidSudoku(vector<vector<char>>& board) {
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (board[i][j] == '.')
				continue;
			int r = i, c = j, b = (i / 3) * 3 + j / 3;
			int val = board[i][j] - '0';
			if (check_row[r][val])
				return false;
			if (check_col[c][val])
				return false;
			if (check_box[b][val])
				return false;

			check_row[r][val] = check_col[c][val] = check_box[b][val] = true;
		}
	}
	return true;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 43, 45, 46] 문제 풀이  (0) 2021.04.01
[LeetCode # 38 ~ 40] 문제 풀이  (0) 2021.03.30
[LeetCode # 31 ~ 33] 문제 풀이  (0) 2021.03.21
[LeetCode # 26 ~ 28] 문제 풀이  (0) 2021.03.19
[LeetCode # 23 ~ 24] 문제 풀이  (0) 2021.03.19
반응형

# 31. Next Permutation

next permutation Library 함수를 구현하는 문제. 정수 배열이 주어지고, 이 배열의 다음 permutation 을 찾아야 한다.

 

이 문제는 Solution 을 참고해서 문제를 해결했는데 문제 해결 방식은 다음과 같다.

1. 배열의 뒤에서부터 탐색을 하며, 값이 처음으로 작아지는 위치 pos 를 찾는다.

2. pos + 1 부터 배열 끝까지 탐색을 하면서, pos 위치 값보다 더 작은 값의 위치 pos2 를 찾는다.

    (찾지 못한 경우 pos2 는 Last Index 로 지정한다.)

3. pos 값과 pos2 - 1 의 값을 서로 교환한다.

4. pos + 1 부터 배열의 끝까지 값을 뒤집는다.

코딩도 하고 했는데 아직도 로직이 헷갈리는 걸 보니 제대로 이해를 못한 것 같다..

 

void nextPermutation(vector<int>& nums) {
	int i, size = nums.size();
	// 일단 뒤에서부터 탐색하면서 작아지는 첫 번째 위치 탐색
	for (i = size - 1; i > 0; i--) {
		if (nums[i - 1] < nums[i]) {
            cout << nums[i - 1] << " " << nums[i] << "\n";
			// 여기서 i - 1 이 처음 작아진 위치
			for (int j = i; j < size; j++) {
				// 여기서 j 가 마지막 위치거나, j + 1 의 값이 i - 1 보다 작으면 j 랑 i - 1 값 교체
				if (j == size - 1 || nums[i - 1] >= nums[j + 1]) {
                    cout << "swap " << nums[i - 1] << " with " << nums[j] << "\n";
					swap(nums[i - 1], nums[j]);
					break;
				}
			}
			break;
		}
	}
	reverse(nums.begin() + i, nums.end());
}

# 32. Longest Valid Parentheses

괄호 '(', ')' 의 열고 닫음 관계가 올바르게 사용된 것을 찾는 문제인데, 주어진 문자열에서 가장 긴 괄호 문자열을 찾는 문제이다.

 

이 문제를 O(n) 으로 해결할 수 있을 것 같다는 생각은 들었지만, 문제 풀이 아이디어가 떠오르지 않아 솔루션을 참고했다.

스택을 사용한 방식으로 문제를 해결할 수 있었는데, 기존 문제 해결 방식과 달리 push / pop 을 통해 괄호 관계를 판별하는 걸 넘어 스택에 index 를 저장해 두었다가 중간중간 length 를 저장할 수 있도록 했다.

 

int longestValidParentheses(string s) {
    int ans = 0;
    stack<int> idxStack;
    idxStack.push(-1);
    for (int i = 0; i<s.length(); i++){
        if (s[i] == '('){
            idxStack.push(i);
        }
        else {
            idxStack.pop();
            if (idxStack.empty())
                idxStack.push(i);
            else
                ans = ans > i - idxStack.top() ? ans : i - idxStack.top();
        }
    }
    return ans;
}

# 33. Search in Rotated Sorted Array

Rotated Sorted Array 가 주어졌을 때, 그 Array 에서 원하는 값을 찾는 문제

* Rotated Sorted Array 는 이전 문제에서 풀었던, Sorted Array 에서 일정 pivot 앞과 뒤를 반전시킨 Sorted Array

 

이 문제는 Binary Search 함수를 일부 변형해 문제를 해결할 수 있었는데, 풀이는 다음과 같이 했다.

원래 Binary Search 의 경우, index 의 시작부터 끝까지 값이 증가하는 정렬된 자료구조에서 시행되기 때문에 찾고자 하는 값이 시작 index ~ 끝 index 의 값 사이에 없으면 그 구간은 탐색을 하지 않는다.

하지만 이 문제의 경우는, 시작 index 값이 끝 index 값보다 작다는 것이 보장되지 않는다.

예를 들어, [4, 5, 6, 0, 1, 2, 3] 과 같이 배열이 주어지면 [4, 5, 6, 0] 구간은 시작 index 값이 더 크게 된다.

이 때문에 탐색 조건에 한 가지를 추가할 필요가 있었는데 시작 index 값과 끝 index 값을 비교해 그 구간이 증가하는 구간인 지를 먼저 확인한 후 그 구간 내에 탐색하고자 하는 값이 없을 경우에만 구간 탐색을 포기하도록 만들었다.

그 외는 기존 Binary Search 와 동일하게 구현해서 문제를 해결했다.

 

int binarySearch(vector<int>& nums, int target, int s, int e) {
	if (s >= e) {
		if (s == e && target == nums[s])
			return s;
		return -1;
	}

	if (nums[s] < nums[e] && (nums[s] > target || target > nums[e])) {
		return -1;
	}
	int m = (s + e) / 2;
	int l = binarySearch(nums, target, s, m);
	int r = binarySearch(nums, target, m + 1, e);
	if (l != -1)
		return l;
	if (r != -1)
		return r;
	return -1;
}

int search(vector<int>& nums, int target) {
	return binarySearch(nums, target, 0, nums.size() - 1);
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 38 ~ 40] 문제 풀이  (0) 2021.03.30
[LeetCode # 34 ~ 36] 문제 풀이  (0) 2021.03.24
[LeetCode # 26 ~ 28] 문제 풀이  (0) 2021.03.19
[LeetCode # 23 ~ 24] 문제 풀이  (0) 2021.03.19
[LeetCode # 20 ~ 22] 문제 풀이  (0) 2021.03.18
반응형

# 26. Remove Duplicates from Sorted Array

중복값이 존재하는 정렬된 정수 배열이 주어졌을 때, 모든 값들이 한 번씩만 등장하도록 만드는 문제

 

Sorted Array 를 순차적으로 탐색하면서, 바뀌는 값이 등장할 때마다 이를 배열에 저장하는 방식으로 구현했다.

 

int removeDuplicates(vector<int>& nums) {
	if (nums.size() == 0)
		return 0;
	int i, j;
	for (i = j = 1; j < nums.size(); j++) {
		if (nums[j - 1] != nums[j]) {
			nums[i++] = nums[j];
		}
	}
	return i;
}

# 27. Remove Element

정수 배열과 Target 값이 주어졌을 때, 배열에서 해당 값을 삭제하는 문제

 

위의 문제와 유사하게, 두 개의 인덱스를 가지고 탐색을 하면서 삭제하고자 하는 값이 등장하면 그 값을 제외하고 배열에 저장하는 식으로 문제를 해결했다.

 

int removeElement(vector<int>& nums, int val) {
	int i, j;
	for (i = j = 0; j < nums.size(); j++) {
		if (nums[j] == val) {
			continue;
		}
		nums[i++] = nums[j];
	}
	return i;
}

# 28. Implement strStr()

두 문자열이 주어졌을 때, 부분 문자열의 시작 위치를 찾는 문제

 

본래 문자열에서 찾고자 하는 부분 문자열의 길이만큼 Substr 을 저장하고, 슬라이딩 윈도우 방식으로 앞의 문자를 빼고 뒤의 문자를 빼면서 부분 문자열과 비교를 해서 위치를 찾는 방식으로 문제를 해결했다.

 

int strStr(string haystack, string needle) {
	if (needle.size() > haystack.size())
		return -1;
	else if (needle.size() == haystack.size() && needle != haystack)
		return -1;

	string comp;
	int i;
	comp = haystack.substr(0, needle.size());
	if (comp == needle)
		return 0;
	for (i = 1; i + needle.size() - 1 < haystack.size(); i++) {
		comp = comp.substr(1) + haystack[i + needle.size() - 1];
		if (comp == needle)
			return i;
	}
	return -1;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 34 ~ 36] 문제 풀이  (0) 2021.03.24
[LeetCode # 31 ~ 33] 문제 풀이  (0) 2021.03.21
[LeetCode # 23 ~ 24] 문제 풀이  (0) 2021.03.19
[LeetCode # 20 ~ 22] 문제 풀이  (0) 2021.03.18
[LeetCode # 17 ~ 19] 문제 풀이  (0) 2021.03.18
반응형

# 23. Merge k Sorted Lists

k 개의 정렬된 리스트가 주어질 때, 하나의 리스트로 이를 합치는 문제

 

리스트 별로 Pointer 를 놓고, 그 중 값이 제일 작은 노드를 찾아서 이를 연결해도 문제를 풀 수 있지만 이렇게 할 경우 k 가 커지면 하나하나 비교하는 게 시간이 오래 걸릴 것 같았다.

그래서 Counting Sort 의 방식을 사용해서, 모든 노드들이 갖는 값을 찾고 각각의 값들이 등장한 회수를 저장한 다음 그 횟수만큼 리스트에 추가하도록 구현했다.

 

int cnt[20001];

ListNode* mergeKLists(vector<ListNode*>& lists) {
	int total_cnt = 0;
	for (auto list : lists) {
		for (ListNode* tmp = list; tmp != nullptr; tmp = tmp->next) {
			cnt[tmp->val + 10000]++;
			total_cnt++;
		}
	}

	ListNode *dummy = new ListNode(0);
	ListNode *cur = dummy;

	for (int i = 0; i < 20001; i++) {
		if (total_cnt == 0)
			break;
		while (cnt[i]--) {
			cur->next = new ListNode(i - 10000);
			cur = cur->next;
			total_cnt--;
		}
	}
	return dummy->next;
}

# 24. Swap Nodes in Pairs

리스트가 주어졌을 때, 각각 인접한 노드들끼리 저장된 값을 Swap 하는 문제

 

단순히 리스트를 순차 탐색하면서 두 노드마다 한 번씩 앞뒤로 값을 바꿔주도록 만들었다.

 

void swap(ListNode* l1, ListNode* l2) {
	int tmp = l1->val;
	l1->val = l2->val;
	l2->val = tmp;
}

ListNode* swapPairs(ListNode* head) {
	bool flag = true;
	for (ListNode* tmp = head; tmp != nullptr; tmp = tmp->next) {
		if (flag && tmp->next != nullptr) {
			swap(tmp, tmp->next);
		}
		flag = !flag;
	}
	return head;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 31 ~ 33] 문제 풀이  (0) 2021.03.21
[LeetCode # 26 ~ 28] 문제 풀이  (0) 2021.03.19
[LeetCode # 20 ~ 22] 문제 풀이  (0) 2021.03.18
[LeetCode # 17 ~ 19] 문제 풀이  (0) 2021.03.18
[LeetCode # 14 ~ 16] 문제 풀이  (0) 2021.03.09
반응형

# 20. Valid Parentheses

괄호로 이루어진 문자열이 주어졌을 때, 이 문자열의 괄호 구조가 적절한 지 확인하는 문제

 

이 문제는 단순히 스택을 활용해서 여는 괄호면 push, 닫는 괄호면 pop 해서 확인하는 방식으로 문제를 해결했다.

bool isValid(string s) {
	stack<char> st;

	for (auto c : s) {
		if (c == '(' || c == '[' || c == '{')
			st.push(c);
		else {
			if (st.empty())
				return false;
			switch (c) {
			case ')':
				if (st.top() != '(')
					return false;
				break;
			case ']':
				if (st.top() != '[')
					return false;
				break;
			case '}':
				if (st.top() != '{')
					return false;
				break;
			}
			st.pop();
		}
	}
	if (!st.empty())
		return false;
	return true;
}

# 21. Merge Two Sorted Lists

정렬된 두 리스트가 주어졌을 때, 정렬을 유지한 상태로 두 리스트를 하나로 합치는 문제

 

간단하게 Two Pointer 사용해서 순서대로 비교하고, 하나의 리스트로 합치도록 만들었다.

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
	ListNode dummyHead = ListNode(0);
	ListNode *tmp = &dummyHead;
	while (l1 != nullptr || l2 != nullptr) {
		if (l1 == nullptr) {
			tmp->next = l2;
			tmp = tmp->next;
			l2 = l2->next;
		}
		else if (l2 == nullptr) {
			tmp->next = l1;
			tmp = tmp->next;
			l1 = l1->next;
		}
		else {
			if (l1->val < l2->val) {
				tmp->next = l1;
				tmp = tmp->next;
				l1 = l1->next;
			}
			else {
				tmp->next = l2;
				tmp = tmp->next;
				l2 = l2->next;
			}
		}
	}
	return dummyHead.next;
}

# 22. Generate Parentheses

Parentheses 쌍의 개수 n 이 주어졌을 때, 가능한 괄호 "()" 쌍의 조합을 모두 구하는 문제

 

주어진 n 개의 여는 괄호 / 닫는 괄호의 가능한 모든 조합을 그냥 Recursive 함수로 찾도록 구현

사용된 여는 괄호 개수만큼만 닫는 괄호를 사용할 수 있도록 해 불가능한 괄호 조합은 만들지 않도록 했다.

vector<string> generateParenthesis(int n) {
	vector<string> ans;
	recursiveGenerate(ans, "", n, n);
	return ans;
}

void recursiveGenerate(vector<string>& v, string s, int l, int r) {
	if (l == 0 && r == 0) {
		v.push_back(s);
		return;
	}

	if (l > 0) {
		recursiveGenerate(v, s + "(", l - 1, r);
	}
	if (r > l) {
		recursiveGenerate(v, s + ")", l, r - 1);
	}
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 26 ~ 28] 문제 풀이  (0) 2021.03.19
[LeetCode # 23 ~ 24] 문제 풀이  (0) 2021.03.19
[LeetCode # 17 ~ 19] 문제 풀이  (0) 2021.03.18
[LeetCode # 14 ~ 16] 문제 풀이  (0) 2021.03.09
[LeetCode # 11 ~ 13] 문제 풀이  (0) 2021.02.28
반응형

# 17. Letter Combinations of a Phone Number

각 문자가 '2-9' 정수로 이루어진 문자열이 주어졌을 때, 해당 버튼을 abc keyboard 에서 눌렀을 때 만들 수 있는 모든 경우를 구하는 문제

ex ) 2 - abc, 3 - def, ... 9 - wxyz

말 그대로 각 숫자 별로 출력 가능한 문자들이 정해져 있어 이 문자들의 조합을 만들도록 코드를 구현했다.

// 각 숫자 별로 입력 가능한 문자들 저장
string letters[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

vector<string> letterCombinations(string digits) {
    if (digits.empty()){
        return {};
    }
    vector<string> result;
    result.push_back("");

    for (auto digit : digits) {
        vector<string> tmp;
        for (auto s : result) {
            for (auto candidate : letters[digit - '0']) {
                tmp.push_back(s + candidate);
            }
        }
        result.swap(tmp);
    }
    return result;
}

# 18. 4 Sum

3 Sum 과 유사한 문제로, 정수형 배열이 주어졌을 때 a + b + c + d = target 값이 되는 a, b, c, d 의 조합을 찾는 문제

3 Sum 은 하나의 값만 정해놓고 left, right 인덱스 두 개로 탐색했지만 이 문제는 두 값을 정해놓고 left, right 인덱스 두 개로 탐색

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> ans;

    for (int i = 0; i < nums.size(); i++) {
        int t1 = target - nums[i]; // 연산량을 줄이기 위해 앞에서 미리 계산
        for (int j = i + 1; j < nums.size(); j++) {
            int t2 = t1 - nums[j];
            int l = j + 1, r = nums.size() - 1;
            while (l < r) {
                int sum = nums[l] + nums[r];
                if (sum < t2) {
                    l++;
                }
                else if (sum > t2) {
                    r--;
                }
                else {
                    vector<int> v(4, 0);
                    v[0] = nums[i];
                    v[1] = nums[j];
                    v[2] = nums[l];
                    v[3] = nums[r];
                    ans.push_back(v);

                    while (l < r && nums[l] == v[2]){
                        l++;
                    }
                    while (l < r && nums[r] == v[3]){
                        r--;
                    }
                }
            }
            while (j < nums.size() - 1 && nums[j] == nums[j + 1]){
                j++;
            }
        }
        while (i < nums.size() - 1 && nums[i] == nums[i + 1]){
            i++;
        }
    }
    return ans;
}

# 19. Remove Nth Node From End of List

리스트가 주어졌을 때, n 번째 노드를 리스트에서 삭제하는 문제

Single Linked List 가 주어지기 때문에 단순히 뒤에서부터 n 개를 탐색할 수는 없었다.

대신 앞에서부터 탐색을 하되 총 노드의 개수를 저장하고 각각의 노드를 배열에 저장함으로써 뒤에서 n 번째 노드를 바로 찾고, 그 앞의 노드를 그 다음 노드로 연결하도록 했다.

ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode *arr[31] = {0, }, *tmp, dummy;
    int size;
    dummy = ListNode(0, head);
    arr[0] = &dummy;

    for (tmp = head, size = 1; tmp != nullptr; tmp = tmp->next, size++) {
        arr[size] = tmp;
    }    
    if (size == 2) {
        return nullptr;
    }
    arr[size - n - 1]->next = arr[size - n + 1];
    return arr[0]->next;
}

'Algorithm > LeetCode' 카테고리의 다른 글

[LeetCode # 23 ~ 24] 문제 풀이  (0) 2021.03.19
[LeetCode # 20 ~ 22] 문제 풀이  (0) 2021.03.18
[LeetCode # 14 ~ 16] 문제 풀이  (0) 2021.03.09
[LeetCode # 11 ~ 13] 문제 풀이  (0) 2021.02.28
[LeetCode # 7 ~ 9] 문제 풀이  (0) 2021.02.26

+ Recent posts