반응형
1.4 회문 순열
주어진 문자열이 회문(palindrome)의 순열인지 아닌지 확인하는 함수를 작성하라. 회문이란 앞으로 읽으나 뒤로 읽으나 같은 단어 혹은 구절을 의미하며, 순열이란 문자열을 재배치하는 것을 뜻한다. 회문이 꼭 사전에 등장하는 단어로 제한될 필요는 없다.
-
unordered_map
자료구조를 사용하는 경우 - O(n)#include <iostream> #include <unordered_map> #include <algorithm> #include <string> using namespace std; bool solution(string input) { unordered_map<char, int> umap; size_t len = input.length(); int odd_count = 0; transform(input.begin(), input.end(), input.begin(), tolower); for (char &c : input) { if (c == ' ') { len -= 1; continue; } auto itr = umap.find(c); if (itr != umap.end()) { umap[c] = itr->second + 1; continue; } umap[c] = 1; } if (len % 2 == 0) { for (auto itr = umap.begin(); itr != umap.end(); itr++) { if (itr->second % 2 != 0) return false; } } else { for (auto itr = umap.begin(); itr != umap.end(); itr++) { if (itr->second % 2 != 0) odd_count++; if (odd_count > 1) return false; } } return true; } int main() { string input = "Tact Coa"; bool res; res = solution(input); cout << boolalpha << res << endl; }
transform
함수를 사용해 입력으로 들어온 문자열을 모두 소문자로 만든다.
-
공백 문자를 검사한다. 만일 공백 문자면
continue
를 통해 그 다음 문자를 읽는다(공백일 경우len
변수의 값을 1 빼준다) -
tact coa
라는 문자열이 들어오면 (a,2), (c,2), (o, 1), (t, 2) 와 같이 저장한다. -
문자열의 길이를 짝수, 홀수로 구분하여 회문 순열을 검사한다.
- 짝수인 경우 : 짝수인 경우 각 문자의 개수가 모두 짝수여야 한다. 만일 한 문자라도 홀수 개일 경우
false
를 리턴한다. - 홀수인 경우 : 홀수인 경우 한 문자만 홀수 개여야 하고 나머지 문자는 모두 짝수 개여야 한다.
- 짝수인 경우 : 짝수인 경우 각 문자의 개수가 모두 짝수여야 한다. 만일 한 문자라도 홀수 개일 경우
-
개선할 수 있는 부분
-
개선 전
if (len % 2 == 0) { for (auto itr = umap.begin(); itr != umap.end(); itr++) { if (itr->second % 2 != 0) return false; } } else { for (auto itr = umap.begin(); itr != umap.end(); itr++) { if (itr->second % 2 != 0) odd_count++; if (odd_count > 1) return false; } } return true;
- 개선 후
bool found_odd = false; // 새로운 변수 선언, len 변수 삭제 for (auto ir = umap.begin(); itr != umap.end(); itr++) { if (itr->second % 2 == 1) { if (found_odd) { return false; } found_odd = true; } } return true;
found_odd
와 같은 변수 하나만으로중복
을 판별할 수 있음을 기억하자.
-
-
비트벡터를 사용하는 경우(대소문자, 공백을 고려하지 않은 풀이)
#include <iostream> using namespace std; int get_char_number(char c) { return c - 'a'; } int toggle(int bitVector, int index) { if (index < 0) return bitVector; int mask = 1 << index; if ((bitVector & mask) == 0) { bitVector |= mask; } else { bitVector &= ~mask; } return bitVector; } bool check_exactly_one_bit_set(int bitVector) { return (bitVector & (bitVector - 1)) == 0; } bool solution(string input) { int bitVector = 0; for (char &c : input) { int x = get_char_number(c); bitVector = toggle(bitVector, x); } return bitVector == 0 || check_exactly_one_bit_set(bitVector); }
int main()
{
string input = "tactcoa";
bool res;
res = solution(input);
cout << boolalpha << res << endl;
}
- 우선 알파벳을 0~25 사이의 숫자로 치환한 후 해당 문자가 등장할 때마다 치환된 위치의 비트 값을 바꿔준다. 그 다음 한 개 이하의 비트가 1로 셋팅되어 있는지 확인한다.
- 1로 셋팅된 비트가 없는지 확인하고 싶다면 간단한게 이 값이 0과 같은지 확인하면 된다. 하지만 1로 셋팅된 비트가 단 한 개 있다면 다음 내용을 잘 살펴보자.
00010000
과 같은 정수를 생각해 보자. 이 숫자에서1
을 빼 보면00001111
이 된다. 여기서 주목할 점은 두 숫자에 겹치는 비트가 없다는 점이다.
00101000
에서1
을 빼면00100111
이 되고, 이 둘은 겹치는 비트가 존재한다.
- 따라서 어떤 숫자에서 1을 뺀 뒤 AND 연산을 수행 했을 때 그 결과가 0이 아니라 면 해당 숫자는 정확히 한 비트만 1로 셋팅되었다는 것을 알 수 있다.
반응형
'자료구조 및 알고리즘 > 알고리즘' 카테고리의 다른 글
[알고리즘] 코딩인터뷰 완전분석 - 1.8 0행렬 (0) | 2019.05.20 |
---|---|
[알고리즘] 코딩인터뷰 완전분석 - 1.5 하나 빼기 (0) | 2019.05.10 |
[알고리즘] 코딩인터뷰 완전분석 - 1.3 URL화 (0) | 2019.05.01 |
[알고리즘] 코딩인터뷰 완전분석 - 1.2 순열확인 (0) | 2019.04.30 |
[알고리즘] 코딩인터뷰 완전분석 - 1.1 중복이 없는가 (0) | 2019.04.30 |