├── .env
├── .gitignore
├── .python-version
├── .travis.yml
├── Pipfile
├── Pipfile.lock
├── README.md
├── README.rst
├── algorithms
├── __init__.py
├── array.py
├── basic.py
├── dp.py
├── math.py
├── queue.py
├── search.py
├── sort.py
├── stack.py
├── string.py
└── tree.py
├── setup.py
└── tests
├── __init__.py
├── test_array.py
├── test_basic.py
├── test_dp.py
├── test_math.py
├── test_queue.py
├── test_search.py
├── test_sort.py
├── test_stack.py
├── test_string.py
├── test_tree.py
└── test_with_unittest.py
/.env:
--------------------------------------------------------------------------------
1 | pyenv shell 3.7.0
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | *.swp
3 | .DS_Store
4 | *.pyc
5 | algo_venv/
6 | venv/
7 | build/
8 | *~
9 | dist/
10 | /*.egg-info
11 | *.ropeproject/
12 | docs/_build
13 | .idea/*
14 | .cache/*
15 | .vscode/*
--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------
1 | 3.7.0
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - 2.7
4 | - 3.7
5 | install:
6 | - pip install tox-travis
7 | - pip install pytest-cov coveralls
8 | script:
9 | - tox
10 | after_success:
11 | - coveralls
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | requests = "*"
8 |
9 | [dev-packages]
10 | pytest = "*"
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "e76ae491d793d659f05c7f7eab261fd6167dc062efcba08f17be68e73eb87665"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {},
8 | "sources": [
9 | {
10 | "name": "pypi",
11 | "url": "https://pypi.org/simple",
12 | "verify_ssl": true
13 | }
14 | ]
15 | },
16 | "default": {
17 | "certifi": {
18 | "hashes": [
19 | "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
20 | ],
21 | "version": "==2018.11.29"
22 | },
23 | "chardet": {
24 | "hashes": [
25 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
26 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
27 | ],
28 | "version": "==3.0.4"
29 | },
30 | "idna": {
31 | "hashes": [
32 | "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
33 | ],
34 | "version": "==2.8"
35 | },
36 | "requests": {
37 | "hashes": [
38 | "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
39 | "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
40 | ],
41 | "index": "pypi",
42 | "version": "==2.21.0"
43 | },
44 | "urllib3": {
45 | "hashes": [
46 | "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
47 | "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
48 | ],
49 | "version": "==1.24.1"
50 | }
51 | },
52 | "develop": {
53 | "atomicwrites": {
54 | "hashes": [
55 | "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
56 | "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
57 | ],
58 | "version": "==1.2.1"
59 | },
60 | "attrs": {
61 | "hashes": [
62 | "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69",
63 | "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"
64 | ],
65 | "version": "==18.2.0"
66 | },
67 | "more-itertools": {
68 | "hashes": [
69 | "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
70 | "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc",
71 | "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
72 | ],
73 | "version": "==5.0.0"
74 | },
75 | "pluggy": {
76 | "hashes": [
77 | "sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616",
78 | "sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a"
79 | ],
80 | "version": "==0.8.1"
81 | },
82 | "py": {
83 | "hashes": [
84 | "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694",
85 | "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"
86 | ],
87 | "version": "==1.7.0"
88 | },
89 | "pytest": {
90 | "hashes": [
91 | "sha256:41568ea7ecb4a68d7f63837cf65b92ce8d0105e43196ff2b26622995bb3dc4b2",
92 | "sha256:c3c573a29d7c9547fb90217ece8a8843aa0c1328a797e200290dc3d0b4b823be"
93 | ],
94 | "index": "pypi",
95 | "version": "==4.1.1"
96 | },
97 | "six": {
98 | "hashes": [
99 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
100 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
101 | ],
102 | "version": "==1.12.0"
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## python-algorithms
3 |
4 | 이 공간은 Problem Solving 이하 PS 스터디를 위한 공간입니다.
5 |
6 | ## Get Started
7 |
8 | #### Install Python
9 |
10 | 파이썬은 공식 사이트인 [python.org](https://www.python.org/)에서 다운로드할 수 있다. 설치가 매우 간단하며 OSX 사용자라면 이미 파이썬이 설치되어 있을 것이다.
11 |
12 | 가능하면 가장 최신의 버전의 python3를 설치하는 것을 권장한다. 설치 후 커맨드 라인에서 아래와 같이 입력하면, 파이썬 Interpeter를 통해 프로그래밍할 수 있는 환경이 갖추어진다.
13 |
14 | ```
15 | $ python3
16 | Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
17 | [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
18 | Type "help", "copyright", "credits" or "license" for more information.
19 | >>>
20 | ```
21 |
22 | #### IDLE과 PyCharm IDE
23 |
24 | Interpreter 언어인 파이썬은 위와 같은 Interactive 모드를 통해 별도의 도구 없이 한 줄 한 줄 프로그래밍 하도록 도와준다.
25 |
26 | 이 REPL은 매우 유용하지만 앞으로 파이썬 코드를 파일에 작성하고자 한다면 JetBrain의 [PyCharm IDE](https://www.jetbrains.com/pycharm/)를 사용하는 것을 추천한다.
27 |
28 | > 파이썬에는 파일에 작성하기 위한 기본 도구인 IDLE를 포함하고 있다.
29 |
30 | 자 뻔한 과정은 생략하고 아래와 같이 Hello World를 출력하는 첫 파이썬 프로그램을 작성해보자.
31 |
32 | ```
33 | $ echo "print('Hello World!')" > hello_world.py
34 | ```
35 |
36 | 파일에 작성된 코드 역시 파이썬 Interpreter에 의해서 실행되며 방법은 아래와 같다. 정상적으로 출력이 된다면 우리는 파이썬 프로그래밍을 위한 모든 준비를 마쳤다!
37 |
38 | ```
39 | $ python3 hello_world.py
40 | Hello World!
41 | ```
42 |
43 | ## TDD로 Python 시작하기
44 |
45 | 만약 파이썬이 처음이라면 TDD를 통해 프로젝트를 구성하고 파이썬을 더욱 멋지게 활용할 수 있는 아래의 글을 참고하도록 하자. 프로젝트의 소스코드는 현재 지금의 Repo 되시겠다. 도움이 될 듯하다면 ★ Star를 누르는 센스도 잊지 말자!
46 |
47 | - [시작하기](https://www.holaxprogramming.com/2017/06/15/python-get-started/)
48 | - [unittest와 함께하는 파이썬 테스트](https://www.holaxprogramming.com/2017/06/17/python-with-test/)
49 | - [파이썬 프로젝트의 구조](https://www.holaxprogramming.com/2017/06/28/python-project-structures/)
50 | - [파이썬 실행 환경을 지탱하는 도구들](https://www.holaxprogramming.com/2017/07/15/python-virtual-environments/)
51 |
52 | ## Run
53 |
54 | ```
55 | $ python3 -m unittest
56 | ```
57 |
58 | ## How to prepare coding interviews
59 |
60 | - [Google](https://careers.google.com/how-we-hire/interview/)
61 | - [Facebook](https://www.facebook.com/notes/facebook-engineering/get-that-job-at-facebook/10150964382448920/)
62 |
63 | ## PS Sites
64 |
65 | - [Hacker Rank](https://www.hackerrank.com/dashboard)
66 | - [LeetCode](https://leetcode.com/)
67 | - [Codility](https://codility.com/programmers/)
68 | - [Kaggle](https://www.kaggle.com/)
69 | - [Visualgo](https://visualgo.net/en)
70 | - [Algorithm Visualizer](http://algo-visualizer.jasonpark.me/#path=backtracking/knight's_tour/basic)
71 |
72 | ## Contents
73 |
74 | - [Testing](#testing)
75 | - [Time Complexity](#time-complexity)
76 | - [Big-O Notations](#big-o-notations)
77 | - [Space Complexity](#space-complexity)
78 | - [Algorithm Solving Strategies](#algorithm-solving-strategies)
79 | - [Divide and Conquer](#divide-and-conquer)
80 | - [Dynamic Programming](#dynamic-programming)
81 | - [Greedy Method](#greedy-method)
82 | - [Combinatorial Search](#combinatorial-search)
83 | - [Combinatorial Optimization](#combinatorial-optimization)
84 | - [Algorithms](#algorithms)
85 | - [Numerical Analysis](#numerical-analysis)
86 | - [Number Theory](#number-theory)
87 | - [Computational Geometry](#computational-geometry)
88 | - [Data Structures](#data-structures)
89 | - [Bitmask](#bitmask)
90 | - [Dynamic Array](#dynamic-array)
91 | - [Linked List](#linked-list)
92 | - [Queue](#queue)
93 | - [Stack](#stack)
94 | - [String](#string)
95 | - [Tree](#tree)
96 | - [Graph](#graph)
97 |
98 | ## Testing
99 |
100 | #### Time Complexity와 Space Complexity
101 |
102 | 알고리듬을 테스트하면서 가장 고려할 요소는 Time Complexity와 Space complexity이다.
103 |
104 | #### Time Complexity
105 |
106 |
107 |
108 | Time Complexity(시간 복잡도)는 문제를 해결하는데 걸리는 시간과 입력의 함수 관계를 표현한다. 얼마나 많은 데이터를 입력 받았는지 그에 따라 CPU는 얼마나 사용하는지 수행 시간은 얼마나 걸리는지를 표현할 수 있다.
109 |
110 | 가장 많이 쓰이는 표현법으로는 알고리듬의 실행 시간의 상한을 나타내는 `Big-O` 표기법이 있다.
111 |
112 | #### Big-O Notations
113 |
114 |
115 |
116 | Big-O | Operations for 10 things | Operations for 100 things
117 | --|--|--
118 | O(1) | 1 | 1
119 | O(log n) | 3 | 7
120 | O(n log n) | 30 | 700 |
121 | 0(n^2) | 100 | 10000 |
122 |
123 | > Solutions - https://www.martinkysel.com/codility-solutions/
124 |
125 | `O(1) - Constant Time`
126 |
127 | 입력되는 데이터양과 상관없이 일정한 실행 시간을 가진다.
128 |
129 | `O(log n) - Logarithmic Time`
130 |
131 | - 입력 데이터 양이 많아져도 수행 시간이 조금씩 늘어난다.
132 | - 시간에 비례하여, 탐색 가능한 데이터양이 2의 n승이 된다.
133 |
134 | > Binary Search
135 |
136 |
137 | `O(n) - Linear Time`
138 |
139 | - 입력 데이터 양에 따라 수행 시간이 정비례한다.
140 |
141 | > 선형 탐색, for 문을 통한 탐색을 생각하면 되겠다.
142 |
143 | `O(n log n) - Linearithmic time`
144 |
145 | - 입력 데이터 양이 n배 많이 진다면, 수행 시간은 n배 보다 조금 더 많아 진다.
146 | - 정비례하지 않는다.
147 |
148 | > 예를 들면, 이진 트리 정렬은 n 크기의 배열 각 요소를 하나하나 삽입하여 이진 트리를 만든다. 자가 균형 이진 탐색 트리의 삽입 연산은 O(log n)시간이 걸리기 때문에, 전체 알고리즘은 Linearithmic time이 걸린다.
149 |
150 | `O(n^2) - Quadratic Time`
151 |
152 | - 입력 데이터의 양에 따라 수행 시간은 제곱에 비례한다.
153 |
154 | > Bubble Sort
155 |
156 | #### Space Complexity
157 |
158 | #### `이하 컨텐츠를 채우는데 함께하고 싶은 분은 PR을 보내주세요! 🤗`
159 |
160 | ## Algorithm Solving Strategies
161 |
162 | #### Divide and Conquer
163 |
164 | #### Dynamic Programming
165 |
166 | #### Greedy Method
167 |
168 | ## Algorithms
169 |
170 | #### Numerical Analysis
171 |
172 | #### Number Theory
173 |
174 | #### Computational Geometry
175 |
176 | ## Data Structures
177 |
178 | #### Bitmask
179 |
180 | #### Dynamic Arra
181 |
182 | #### Linked List
183 |
184 | #### Queue
185 |
186 | #### Stack
187 |
188 | #### String
189 |
190 | #### Tree
191 |
192 | #### Graph
193 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 |
2 | python-algorithms
3 | ==================
4 |
5 | Practices to solve problems with Python
--------------------------------------------------------------------------------
/algorithms/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Description for Package
3 | """
4 | __version__ = '1.0.0'
5 |
--------------------------------------------------------------------------------
/algorithms/array.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Array(object):
4 | def __init__(self, numbers):
5 | self.numbers = numbers
6 |
7 | def __len__(self):
8 | return len(self.numbers)
9 |
10 | def __str__(self):
11 | result = '['
12 | for n in self.numbers:
13 | result += str(n) + ', '
14 | return result[:-2] + ']'
15 |
16 | def sum(self, size):
17 | if size != len(self.numbers):
18 | raise Exception('array size is not matched')
19 | result = sum(self.numbers)
20 | return result
21 |
22 | def rotate(self, shift):
23 | head = shift % len(self.numbers)
24 | self.numbers = self.numbers[head:] + self.numbers[:head]
25 | return self.numbers
26 |
27 | @staticmethod
28 | def pop(numbers):
29 | numbers.pop()
30 |
31 |
32 |
--------------------------------------------------------------------------------
/algorithms/basic.py:
--------------------------------------------------------------------------------
1 | """
2 | Basic algorithms
3 | """
4 | from collections import Counter
5 |
6 |
7 | class Basic:
8 |
9 | @classmethod
10 | def factorial(cls, number):
11 | """
12 | :return: recursive pattern if n = 5, 5 * 4 * 3 * 2 * 1 = 120
13 | """
14 | if number == 1:
15 | return 1
16 | return number * cls.factorial(number - 1)
17 |
18 | @classmethod
19 | def fibonacci(cls, index):
20 | """
21 | :return: 0, 1, 1, 2, 3, 5, 8, 13, 21 ...
22 | """
23 | if index == 0 or index == 1:
24 | return index
25 | return cls.fibonacci(index - 2) + cls.fibonacci(index - 1)
26 |
27 | @classmethod
28 | def time_conversion(cls, formatted_time: str):
29 | hours = int(formatted_time[:2])
30 | mins = int(formatted_time[3:5])
31 | seconds = int(formatted_time[6:8])
32 | if 'PM' in formatted_time and hours == 12:
33 | pass
34 | elif 'PM' in formatted_time:
35 | hours += 12
36 | elif hours >= 12:
37 | hours -= 12
38 | return '{:02}:{:02}:{:02}'.format(hours, mins, seconds)
39 |
40 | @staticmethod
41 | def multiple_sum(num1, num2, end):
42 | total = 0
43 | for i in range(1, end):
44 | if i % num1 == 0 or i % num2 == 0:
45 | total += i
46 | return total
47 |
48 | @staticmethod
49 | def ransom_note(magazine: str, ransom: str):
50 | magazine_words = magazine.split(' ')
51 | ransom_words = ransom.split(' ')
52 | magazine_word_counts = Counter(magazine_words)
53 | ransom_word_counts = Counter(ransom_words)
54 | for word in ransom_words:
55 | if magazine_word_counts[word] < ransom_word_counts[word]:
56 | return False
57 | return True
58 |
59 | @staticmethod
60 | def compare_the_triplets(alice_points, bob_points):
61 | alice_score = 0
62 | bob_score = 0
63 | for i in range(len(alice_points)):
64 | if alice_points[i] > bob_points[i]:
65 | alice_score += 1
66 | elif alice_points[i] == bob_points[i]:
67 | pass
68 | else:
69 | bob_score += 1
70 | return ' '.join(map(lambda x: str(x), [alice_score, bob_score]))
71 |
72 |
73 |
--------------------------------------------------------------------------------
/algorithms/dp.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class DP:
4 |
5 | def __init__(self, max_size=100):
6 | self.values = [0] * max_size
7 | self.values[1] = 1
8 |
9 | def fibonacci(self, index):
10 | if index == 0 or index == 1:
11 | return self.values[index]
12 | if self.values[index] != 0:
13 | return self.values[index]
14 | self.values[index] = self.fibonacci(index - 2) + self.fibonacci(index - 1)
15 | return self.values[index]
16 |
17 |
18 |
--------------------------------------------------------------------------------
/algorithms/math.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Math(object):
4 |
5 | @staticmethod
6 | def lonely_integer(numbers: list):
7 | value = 0
8 | for number in numbers:
9 | value = value ^ number
10 | return value
11 |
12 | @staticmethod
13 | def bin(value: int):
14 | buffer = [''] * 16
15 | char_index = len(buffer)
16 | while value > 0:
17 | char_index -= 1
18 | buffer[char_index] = '01'[value % 2]
19 | value = int(value / 2)
20 | return ''.join(buffer)
21 |
22 | @staticmethod
23 | def oct(value: int):
24 | buffer = [''] * 16
25 | char_index = len(buffer)
26 | while value > 0:
27 | char_index -= 1
28 | buffer[char_index] = '01234567'[value % 8]
29 | value = int(value / 8)
30 | return ''.join(buffer)
31 |
32 | @staticmethod
33 | def prime(value: int):
34 | if value == 0 or value == 1:
35 | return False
36 | if value == 2 or value == 3:
37 | return True
38 | if value % 2 == 0 or value % 3 == 0:
39 | return False
40 | j = 5
41 | while (j ** 2) <= value:
42 | if value % j == 0 or value % (j + 2) == 0:
43 | return False
44 | j += 6
45 | return True
46 |
47 |
48 |
--------------------------------------------------------------------------------
/algorithms/queue.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class AbstractQueue(object):
4 |
5 | def __init__(self):
6 | self.head = 0
7 | self.size = 0
8 | self.items = []
9 |
10 | def put(self):
11 | raise NotImplementedError()
12 |
13 | def get(self):
14 | raise NotImplementedError()
15 |
16 | def qsize(self):
17 | return self.size;
18 |
19 | def empty(self):
20 | return not self.qsize()
21 |
22 | def full(self):
23 | return self.qsize() == self.size
24 |
25 |
26 | class Queue(AbstractQueue):
27 |
28 | def __init__(self, capacity=10):
29 | self.head = 0
30 | self.size = 0
31 | self.items = [None] * capacity
32 |
33 | def put(self, item):
34 | self.items[(self.head + self.size) % len(self.items)] = item
35 | self.size += 1
36 |
37 | def get(self):
38 | if self.empty():
39 | raise IndexError('Queue is empty')
40 | self.size -= 1
41 | result = self.items[self.head]
42 | self.head = (self.head + 1) % len(self.items)
43 | return result
44 |
45 |
46 |
--------------------------------------------------------------------------------
/algorithms/search.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Search:
4 |
5 | @staticmethod
6 | def binary_search(numbers, x):
7 | return Search.binary_search_recursive(numbers, x, 0, len(numbers) - 1)
8 |
9 | @staticmethod
10 | def binary_search_recursive(numbers, x, left, right):
11 | if left > right:
12 | return -1
13 | mid = int(left + (right - left) / 2)
14 | if numbers[mid] == x:
15 | return mid
16 | elif x < numbers[mid]:
17 | return Search.binary_search_recursive(numbers, x, left, mid - 1)
18 | elif x > numbers[mid]:
19 | return Search.binary_search_recursive(numbers, x, mid + 1, right)
20 | else:
21 | return -1
22 |
23 | @staticmethod
24 | def binary_search_iterative(numbers, x):
25 | left = 0
26 | right = len(numbers) - 1
27 | mid = int(left + (right - left) / 2)
28 | while left <= right:
29 | if numbers[mid] == x:
30 | return mid
31 | elif x < numbers[mid]:
32 | right = mid - 1
33 | mid = int(left + (right - left) / 2)
34 | elif x > numbers[mid]:
35 | left = mid + 1
36 | mid = int(left + (right - left) / 2)
37 | else:
38 | return -1
39 | return -1
40 |
41 | @staticmethod
42 | def index(flavors: list, value, exclude):
43 | for i in range(0, len(flavors)):
44 | if flavors[i] == value and i != exclude:
45 | return i
46 | return -1
47 |
48 | @staticmethod
49 | def ice_cream_parlor(money, flavors: list):
50 | """
51 | https://www.hackerrank.com/challenges/ctci-ice-cream-parlor
52 | """
53 | sorted_flavors = sorted(flavors)
54 | for i, flavor in enumerate(sorted_flavors):
55 | complement = money - flavor
56 | location = Search.binary_search_iterative(sorted_flavors, complement)
57 | if 0 <= location < len(sorted_flavors):
58 | a = Search.index(flavors, sorted_flavors[i], -1)
59 | b = Search.index(flavors, complement, a)
60 | return ' '.join(map(lambda x: str(x), [min(a + 1, b + 1), max(a + 1, b + 1)]))
--------------------------------------------------------------------------------
/algorithms/sort.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class SortType(Enum):
5 | ASC = 1
6 | DESC = 2
7 |
8 |
9 | class Sorting:
10 | def __init__(self, numbers: list):
11 | self.numbers = numbers
12 |
13 | def bubble_sort(self):
14 | print('bubble_sort = {}'.upper().format(self.numbers))
15 | for i in range(len(self.numbers)):
16 | swapped = False
17 | for j in range(len(self.numbers) - 1):
18 | if self.numbers[j] > self.numbers[j + 1]:
19 | self.numbers[j], self.numbers[j + 1] = self.numbers[j + 1], self.numbers[j]
20 | swapped = True
21 | if not swapped:
22 | break
23 | print('{}'.format(self.numbers))
24 | return self.numbers
25 |
26 | def selection_sort(self, sort_type=SortType.ASC):
27 | print('selection_sort(type={}) = {}'.upper().format(sort_type, self.numbers))
28 | for i in range(len(self.numbers)):
29 | index = i
30 | for j in range(i, len(self.numbers)):
31 | if sort_type == SortType.ASC and self.numbers[index] > self.numbers[j]:
32 | index = j
33 | if sort_type == SortType.DESC and self.numbers[index] < self.numbers[j]:
34 | index = j
35 | self.numbers[i], self.numbers[index] = self.numbers[index], self.numbers[i]
36 | return self.numbers
37 |
38 | def selection(self, k, sort_type=SortType.ASC):
39 | for i in range(len(self.numbers)):
40 | index = i
41 | for j in range(i, len(self.numbers)):
42 | if sort_type == SortType.ASC and self.numbers[index] > self.numbers[j]:
43 | index = j
44 | if sort_type == SortType.DESC and self.numbers[index] < self.numbers[j]:
45 | index = j
46 | self.numbers[i], self.numbers[index] = self.numbers[index], self.numbers[i]
47 | if i == k - 1:
48 | return self.numbers[i]
49 |
50 | def merge_sort(self):
51 | print('merge_sort = {}'.upper().format(self.numbers))
52 | temp = [0] * len(self.numbers)
53 | self.merge_sort_recursive(temp, 0, len(self.numbers) - 1)
54 |
55 | def merge_sort_recursive(self, temp, left_start, right_end):
56 | if left_start >= right_end:
57 | return
58 | mid = int((left_start + right_end) / 2)
59 | self.merge_sort_recursive(temp, left_start, mid)
60 | self.merge_sort_recursive(temp, mid + 1, right_end)
61 | self.merge(temp, left_start, right_end)
62 |
63 | def merge(self, temp, left_start, right_end):
64 | left_end = int((right_end + left_start) / 2)
65 | right_start = left_end + 1
66 |
67 | size = right_end - left_start + 1
68 | left = left_start
69 | right = right_start
70 | index = left_start
71 | print('MERGE > left={} right={} index={} size={}'.format(left, right, index, size))
72 | while left <= left_end and right <= right_end:
73 | if self.numbers[left] <= self.numbers[right]:
74 | temp[index] = self.numbers[left]
75 | left += 1
76 | else:
77 | temp[index] = self.numbers[right]
78 | right += 1
79 | index += 1
80 |
81 | Sorting.array_copy(self.numbers, left, temp, index, left_end - left + 1)
82 | Sorting.array_copy(self.numbers, right, temp, index, right_end - right + 1)
83 | Sorting.array_copy(temp, left_start, self.numbers, left_start, size)
84 | print(self.numbers)
85 |
86 | @staticmethod
87 | def array_copy(src: list, src_pos: int, dest: list, dest_pos: int, size: int):
88 | for i in range(size):
89 | dest[dest_pos + i] = src[src_pos + i]
90 |
91 |
92 |
--------------------------------------------------------------------------------
/algorithms/stack.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Stack:
4 | def __init__(self, max_size=10):
5 | self.items = [None] * max_size
6 | self.max_size = max_size
7 | self.top = -1
8 |
9 | def push(self, item):
10 | if self.is_full():
11 | self.expand()
12 | self.top += 1
13 | self.items[self.top] = item
14 |
15 | def pop(self):
16 | if self.is_empty():
17 | raise IndexError("Stack is empty")
18 | item = self.items[self.top]
19 | self.items[self.top] = None
20 | self.top -= 1
21 | return item
22 |
23 | def expand(self):
24 | self.max_size = self.max_size * 2
25 | new_items = [None] * (self.max_size)
26 | for index, item in enumerate(self.items):
27 | new_items[index] = item
28 | self.items = new_items
29 |
30 | def is_empty(self):
31 | return self.top == -1
32 |
33 | def is_full(self):
34 | return self.top == (self.max_size - 1)
35 |
36 | def has(self, value):
37 | return value in self.items
38 |
39 | BRACKET_PAIRS = {"{": "}", "[": "]", "(": ")"}
40 |
41 | def balanced_brackets(expression: str):
42 | if not type(expression) is str or not expression:
43 | return False
44 | stack = Stack()
45 | for char in expression:
46 | if char in BRACKET_PAIRS:
47 | stack.push(BRACKET_PAIRS[char])
48 | elif not stack.is_empty() and stack.has(char):
49 | stack.pop()
50 | else:
51 | return False
52 | return stack.is_empty()
53 |
54 |
--------------------------------------------------------------------------------
/algorithms/string.py:
--------------------------------------------------------------------------------
1 | """
2 | About String
3 |
4 | Ascii - 1 byte 0-255, 0x00-0xFF, A(65)
5 | Unicode - 2 bytes 가(0xAC00)
6 | EUC-KR - 2 bytes
7 | UTF-8 - 2 bytes+ Korean 3 bytes
8 | UTF-16 - 2 bytes+ Korean 4 bytes
9 | """
10 |
11 |
12 | class String:
13 |
14 | @classmethod
15 | def reverse(cls, word: str):
16 | if (word is None) or (word == ''):
17 | return None
18 | start = 0
19 | end = len(word) - 1
20 | char_list = list(word)
21 | while start < end:
22 | temp = char_list[start]
23 | char_list[start] = char_list[end]
24 | char_list[end] = temp
25 | start += 1
26 | end -= 1
27 | return ''.join(char_list)
28 |
29 | @classmethod
30 | def check_anagrams(cls, str1: str, str2: str):
31 | if str1 == '' or str1 is None or str2 == '' or str2 is None:
32 | return False
33 | if len(str1) != len(str2):
34 | return False
35 | str1 = ''.join(sorted(str1))
36 | str2 = ''.join(sorted(str2))
37 | return str1 == str2
38 |
39 | @classmethod
40 | def making_anagrams(cls, str1: str, str2: str):
41 | delete_count = 0
42 | letter_counts = [0] * (ord('z') - ord('a') + 1)
43 |
44 | for char in str1:
45 | letter_counts[ord(char) - ord('a')] += 1
46 |
47 | for char in str2:
48 | letter_counts[ord(char) - ord('a')] -= 1
49 |
50 | for number in letter_counts:
51 | delete_count += abs(number)
52 |
53 | return delete_count
54 |
55 | @classmethod
56 | def advanced_anagrams(cls, input: str):
57 | if not (len(input) % 2) == 0:
58 | return -1
59 | str1 = input[0:int(len(input) / 2)]
60 | str2 = input[int(len(input) / 2):]
61 | letter_counts = [0] * (ord('z') - ord('a') + 1)
62 | count = 0
63 |
64 | for i in range(len(str1)):
65 | letter_counts[ord(str1[i]) - ord('a')] += 1
66 | letter_counts[ord(str2[i]) - ord('a')] -= 1
67 |
68 | for number in letter_counts:
69 | count += abs(number)
70 |
71 | return count / 2
72 |
73 | @staticmethod
74 | def pangrams(sentence: str):
75 | sentence = sentence.lower().replace(' ', '')
76 | letter_counts = [0] * (ord('z') - ord('a') + 1)
77 |
78 | for letter in sentence:
79 | letter_counts[ord(letter) - ord('a')] += 1
80 |
81 | for count in letter_counts:
82 | if count == 0:
83 | return False
84 | return True
85 |
86 | @staticmethod
87 | def is_iterative_pattern(sentence: str):
88 | if sentence is None or sentence == '':
89 | return False
90 | if len(sentence) == 1:
91 | return True
92 | divide_number = 2
93 | while divide_number <= len(sentence):
94 | if len(sentence) % divide_number != 0:
95 | divide_number += 1
96 | continue
97 | parts = String.split(sentence, divide_number)
98 | divide_number += 1
99 | if String.is_matched(parts):
100 | return True
101 | return False
102 |
103 | @staticmethod
104 | def split(sentence: str, divide_number: int):
105 | size = int(len(sentence) / divide_number)
106 | array = []
107 | for i in range(divide_number):
108 | start = i * size
109 | end = (i + 1) * size
110 | array.append(sentence[start:end])
111 | return array
112 |
113 | @staticmethod
114 | def is_matched(parts: list):
115 | for i in range(1, len(parts)):
116 | if parts[i] != parts[0]:
117 | return False
118 | return True
119 |
--------------------------------------------------------------------------------
/algorithms/tree.py:
--------------------------------------------------------------------------------
1 | """
2 | Example 1:
3 | 2
4 | / \
5 | 1 3
6 | Binary tree [2,1,3], return true.
7 | Example 2:
8 | 1
9 | / \
10 | 2 3
11 | Binary tree [1,2,3], return false.
12 | """
13 |
14 |
15 | class Node:
16 |
17 | def __init__(self, value=0):
18 | self.value = value
19 | self.left = None
20 | self.right = None
21 |
22 | @classmethod
23 | def check_bst(cls, root, min_value, max_value):
24 | if root is None:
25 | return True
26 | return (
27 | min_value < root.value < max_value and
28 | Node.check_bst(root.left, min_value, root.value) and
29 | Node.check_bst(root.right, root.value, max_value))
30 |
31 | @classmethod
32 | def is_binary_search_tree(cls, root):
33 | return Node.check_bst(root, -float('inf'), float('inf'))
34 |
35 |
36 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import io
2 | from setuptools import find_packages, setup
3 |
4 |
5 | # Read in the README for the long description on PyPI
6 | def long_description():
7 | with io.open('README.rst', 'r', encoding='utf-8') as f:
8 | readme = f.read()
9 | return readme
10 |
11 | setup(name='python-algorithms',
12 | version='1.0.0',
13 | description='Practices to solve problems with Python',
14 | long_description=long_description(),
15 | url='https://github.com/stunstunstun/python-algorithms',
16 | author='stunstunstun',
17 | license='MIT',
18 | packages=find_packages(),
19 | python_requires='>=3',
20 | classifiers=[
21 | 'Programming Language :: Python :: 2.7',
22 | 'Programming Language :: Python :: 3',
23 | 'Programming Language :: Python :: 3.6',
24 | ],
25 | zip_safe=False)
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stunstunstun/python-algorithms/c38ac55090d90deb421bfed1b48ece0a5f56351f/tests/__init__.py
--------------------------------------------------------------------------------
/tests/test_array.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.array import Array
3 |
4 |
5 | class TestArray(unittest.TestCase):
6 | """
7 | Create class instance
8 | """
9 | def setUp(self):
10 | self.array = Array([1, 11, 98, 3, 50, 72, 22, 29, 99, 2])
11 |
12 | def test_sum(self):
13 | """
14 | Test that the result sum of all numbers
15 | """
16 | result = self.array.sum(10)
17 | self.assertEqual(result, 387)
18 |
19 | def test_sum_raise_exception(self):
20 | """
21 | Tests that an exception occurs when the number of arguments is different
22 | """
23 | self.assertRaises(Exception, lambda: self.array.sum(5))
24 |
25 | def test_rotate(self):
26 | self.assertEqual(self.array.rotate(2), [98, 3, 50, 72, 22, 29, 99, 2, 1, 11])
27 |
28 | def test_reference(self):
29 | numbers = [98, 3, 50, 72, 22, 29, 99, 2, 1, 11]
30 | Array.pop(numbers)
31 | self.assertEqual(numbers, [98, 3, 50, 72, 22, 29, 99, 2, 1])
32 |
33 | def tearDown(self):
34 | """
35 | Print array elements
36 | """
37 | print('length = {}, elements = {}'.format(self.array.__len__(), self.array))
38 |
--------------------------------------------------------------------------------
/tests/test_basic.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.basic import Basic
3 |
4 |
5 | class TestBasic(unittest.TestCase):
6 |
7 | def test_range_loop(self):
8 | # 1 2 3
9 | n = [1, 2]
10 | n.append(3)
11 | # 3 2 1
12 | n = list(reversed(n))
13 | self.assertEqual(n, [3, 2, 1])
14 | self.assertEqual(n, list(range(3, 0, -1)))
15 | # 1 3 5
16 | n = [1, 3, 5]
17 | self.assertEqual(n, list(range(1, 6, 2)))
18 |
19 | def test_factorial(self):
20 | self.assertEquals(Basic.factorial(5), 120)
21 |
22 | def test_fibonacci(self):
23 | self.assertEquals(Basic.fibonacci(0), 0)
24 | self.assertEquals(Basic.fibonacci(1), 1)
25 | self.assertEquals(Basic.fibonacci(2), 1)
26 | self.assertEquals(Basic.fibonacci(3), 2)
27 | self.assertEquals(Basic.fibonacci(4), 3)
28 | self.assertEquals(Basic.fibonacci(5), 5)
29 | self.assertEquals(Basic.fibonacci(6), 8)
30 | self.assertEquals(Basic.fibonacci(7), 13)
31 | self.assertEquals(Basic.fibonacci(8), 21)
32 | self.assertEquals(Basic.fibonacci(9), 34)
33 | self.assertEquals(Basic.fibonacci(31), 1346269)
34 |
35 | def test_time_conversion(self):
36 | self.assertEquals(Basic.time_conversion('07:05:45PM'), '19:05:45')
37 | self.assertEquals(Basic.time_conversion('12:40:22AM'), '00:40:22')
38 | self.assertEquals(Basic.time_conversion('12:45:54PM'), '12:45:54')
39 |
40 | def test_multiple_sum(self):
41 | # 3 5 6 9 10 12 15 18
42 | self.assertEqual(Basic.multiple_sum(3, 5, 1000), 233168)
43 |
44 | def test_hash_table(self):
45 | self.assertEqual(Basic.ransom_note('give me one grand today night', 'give one grand today'), True)
46 | self.assertEqual(Basic.ransom_note('apgo clm w lxkvg mwz elo bg elo lxkvg elo apgo apgo w elo bg', 'elo lxkvg bg mwz clm w'), True)
47 |
48 | def test_compare_the_triplets(self):
49 | result = Basic.compare_the_triplets([5, 6, 7], [3, 6, 10])
50 | self.assertEquals(result, '1 1')
51 |
52 |
53 |
--------------------------------------------------------------------------------
/tests/test_dp.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.dp import DP
3 |
4 |
5 | class TestDP(unittest.TestCase):
6 |
7 | def test_fibonacci(self):
8 | dp = DP(100)
9 | self.assertEquals(dp.fibonacci(0), 0)
10 | self.assertEquals(dp.fibonacci(1), 1)
11 | self.assertEquals(dp.fibonacci(2), 1)
12 | self.assertEquals(dp.fibonacci(3), 2)
13 | self.assertEquals(dp.fibonacci(4), 3)
14 | self.assertEquals(dp.fibonacci(5), 5)
15 | self.assertEquals(dp.fibonacci(6), 8)
16 | self.assertEquals(dp.fibonacci(7), 13)
17 | self.assertEquals(dp.fibonacci(8), 21)
18 | self.assertEquals(dp.fibonacci(9), 34)
19 | self.assertEquals(dp.fibonacci(31), 1346269)
20 | self.assertEquals(dp.fibonacci(40), 102334155)
21 |
--------------------------------------------------------------------------------
/tests/test_math.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.math import Math
3 |
4 |
5 | class TestMath(unittest.TestCase):
6 |
7 | def test_lonely_integer(self):
8 | self.assertEqual(Math.lonely_integer([0, 0, 1, 2, 1]), 2)
9 | self.assertEqual(Math.lonely_integer([1]), 1)
10 | self.assertEqual(Math.lonely_integer([1, 1, 2]), 2)
11 |
12 | def test_format(self):
13 | self.assertEqual(Math.bin(10), '1010')
14 | self.assertEqual(Math.bin(255), '11111111')
15 | self.assertEqual(Math.oct(10), '12')
16 | self.assertEqual(Math.oct(255), '377')
17 |
18 | def test_prime(self):
19 | self.assertEqual(Math.prime(0), False)
20 | self.assertEqual(Math.prime(1), False)
21 | self.assertEqual(Math.prime(2), True)
22 | self.assertEqual(Math.prime(3), True)
23 | self.assertEqual(Math.prime(4), False)
24 | self.assertEqual(Math.prime(5), True)
25 | self.assertEqual(Math.prime(13), True)
26 | self.assertEqual(Math.prime(1000000007), True)
27 | self.assertEqual(Math.prime(1000003), True)
28 |
--------------------------------------------------------------------------------
/tests/test_queue.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.queue import Queue
3 |
4 |
5 | class TestQueue(unittest.TestCase):
6 |
7 | def test_queue(self):
8 | q = Queue()
9 | self.assertEqual(q.empty(), True)
10 |
11 | q.put(0)
12 | q.put(1)
13 | self.assertEqual(q.get(), 1)
14 | self.assertEqual(q.qsize(), 1)
15 | self.assertEqual(q.empty(), False)
16 |
17 | for i in range(2, 10):
18 | print(i)
19 | q.put(i)
20 |
21 | self.assertEqual(q.full(), True)
22 |
23 | def test_queue(self):
24 | q = Queue()
25 | self.assertRaises(IndexError, q.get)
26 |
--------------------------------------------------------------------------------
/tests/test_search.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.search import Search
3 |
4 |
5 | class TestSearch(unittest.TestCase):
6 |
7 | def test_binary_search_recursive(self):
8 | self.assertEqual(Search.binary_search([1, 2, 3, 11, 22, 29, 50, 72, 98, 99], 11), 3)
9 |
10 | def test_binary_search_iterative(self):
11 | self.assertEqual(Search.binary_search_iterative([1, 2, 3, 11, 22, 29, 50, 72, 98, 99], 11), 3)
12 | self.assertEqual(Search.binary_search_iterative([1, 2, 3, 4, 5], 3), 2)
13 |
14 | def test_ice_cream_parlor(self):
15 | self.assertEqual(Search.ice_cream_parlor(4, [1, 4, 5, 3, 2]), '1 4')
16 | self.assertEqual(Search.ice_cream_parlor(4, [2, 2, 4, 3]), '1 2')
17 |
--------------------------------------------------------------------------------
/tests/test_sort.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.sort import Sorting, SortType
3 |
4 |
5 | class TestSort(unittest.TestCase):
6 | """
7 | Create class instance
8 | """
9 | def setUp(self):
10 | self.sorting = Sorting([1, 11, 98, 3, 50, 72, 22, 29, 99, 2])
11 |
12 | def test_bubble_sort(self):
13 | self.assertEqual(self.sorting.bubble_sort(), [1, 2, 3, 11, 22, 29, 50, 72, 98, 99])
14 |
15 | def test_selection_sort(self):
16 | self.assertEqual(self.sorting.selection_sort(), [1, 2, 3, 11, 22, 29, 50, 72, 98, 99])
17 | self.assertEqual(self.sorting.selection_sort(sort_type=SortType.DESC), [99, 98, 72, 50, 29, 22, 11, 3, 2, 1])
18 |
19 | def test_selection(self):
20 | self.assertEqual(self.sorting.selection(1), 1)
21 | self.assertEqual(self.sorting.selection(2), 2)
22 | self.assertEqual(self.sorting.selection(3), 3)
23 | self.assertEqual(self.sorting.selection(4), 11)
24 | self.assertEqual(self.sorting.selection(5), 22)
25 |
26 | self.assertEqual(self.sorting.selection(1, sort_type=SortType.DESC), 99)
27 | self.assertEqual(self.sorting.selection(2, sort_type=SortType.DESC), 98)
28 | self.assertEqual(self.sorting.selection(3, sort_type=SortType.DESC), 72)
29 |
30 | def test_merge_sort(self):
31 | self.sorting.merge_sort()
32 | self.assertEqual(self.sorting.numbers, [1, 2, 3, 11, 22, 29, 50, 72, 98, 99])
33 |
--------------------------------------------------------------------------------
/tests/test_stack.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.stack import Stack, balanced_brackets
3 |
4 |
5 | class TestStack(unittest.TestCase):
6 |
7 | def test_stack(self):
8 | stack = Stack()
9 | stack.push(2)
10 | stack.push(4)
11 | stack.push(6)
12 |
13 | self.assertEqual(stack.pop(), 6)
14 | self.assertEqual(stack.is_empty(), False)
15 | self.assertEqual(stack.top, 1)
16 | self.assertEqual(stack.has(4), True)
17 | self.assertEqual(stack.is_full(), False)
18 |
19 | for i in range(8):
20 | stack.push(i)
21 | self.assertEqual(stack.is_full(), True)
22 | self.assertEqual(stack.top, stack.max_size - 1)
23 |
24 | for i in range(10):
25 | stack.push(i)
26 | self.assertEqual(stack.is_full(), True)
27 | self.assertEqual(stack.top, stack.max_size - 1)
28 |
29 | def test_balanced_brackets(self):
30 | self.assertEqual(balanced_brackets(0), False)
31 | self.assertEqual(balanced_brackets(''), False)
32 | self.assertEqual(balanced_brackets('aabb'), False)
33 | self.assertEqual(balanced_brackets('{[(}])'), False)
34 | self.assertEqual(balanced_brackets('{[()]}'), True)
35 | self.assertEqual(balanced_brackets('}][}}(}][))]'), False)
36 | self.assertEqual(balanced_brackets('[](){()}'), True)
37 | self.assertEqual(balanced_brackets('({}([][]))[]()'), True)
38 | self.assertEqual(balanced_brackets('{)[](}]}]}))}(())('), False)
39 |
--------------------------------------------------------------------------------
/tests/test_string.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import binascii
3 | from algorithms.string import String
4 |
5 |
6 | class TestString(unittest.TestCase):
7 |
8 | def test_reverse(self):
9 | self.assertEqual(String.reverse('abcde'), 'edcba')
10 | self.assertEqual(String.reverse(None), None)
11 | self.assertEqual(String.reverse(''), None)
12 |
13 | def test_binary(self):
14 | self.assertEqual(int('1010', 2), 10)
15 | self.assertEqual(hex(255), '0xff')
16 |
17 | def test_ascii(self):
18 | for i in range(0, 256, 1):
19 | print('{} {:03} {} {}'.format(chr(i), i, hex(i).upper(), bin(i)))
20 | self.assertEqual(chr(65), 'A')
21 | self.assertEqual(chr(44032), '가')
22 |
23 | def test_unicode(self):
24 | for i in range(ord(u'A'), ord(u'Z'), 1):
25 | print('{} {:03} {} {}'.format(chr(i), i, hex(i).upper(), bin(i)))
26 | for i in range(ord(u'가'), ord(u'겮'), 1):
27 | print('{} {:03} {} {}'.format(chr(i), i, hex(i).upper(), bin(i)))
28 | self.assertEqual(hex(ord(u'가')), '0xac00')
29 |
30 | b = u'A'.encode(encoding='utf-8')
31 | print('{} {} {}'.format('A', 'utf-8', binascii.hexlify(b)))
32 | self.assertEqual(len(b), 1)
33 | b = u'A'.encode(encoding='euc-kr')
34 | print('{} {} {}'.format('A', 'euc-kr', binascii.hexlify(b)))
35 | self.assertEqual(len(b), 1)
36 | b = u'A'.encode(encoding='utf-16')
37 | print('{} {} {}'.format('A', 'utf-16', binascii.hexlify(b)))
38 | self.assertEqual(len(b), 4)
39 |
40 | b = u'가'.encode(encoding='utf-8')
41 | print('{} {} {}'.format('가', 'utf-8', binascii.hexlify(b)))
42 | self.assertEqual(len(b), 3)
43 | b = u'가'.encode(encoding='euc-kr')
44 | print('{} {} {}'.format('가', 'euc-kr', binascii.hexlify(b)))
45 | self.assertEqual(len(b), 2)
46 | b = u'가'.encode(encoding='utf-16')
47 | print('{} {} {}'.format('가', 'utf-16', binascii.hexlify(b)))
48 | self.assertEqual(len(b), 4)
49 | b = u'가'.encode()
50 | self.assertEqual(len(b), 3)
51 |
52 | def test_check_anagrams(self):
53 | self.assertEqual(String.check_anagrams('abc', 'cab'), True)
54 | self.assertEqual(String.check_anagrams('bat', 'tab'), True)
55 | self.assertEqual(String.check_anagrams('abc', 'eft'), False)
56 | self.assertEqual(String.check_anagrams('ba', 'tab'), False)
57 | self.assertEqual(String.check_anagrams('abc', 'cb'), False)
58 | self.assertEqual(String.check_anagrams('', ''), False)
59 | self.assertEqual(String.check_anagrams(None, None), False)
60 |
61 | def test_making_anagrams(self):
62 | self.assertEqual(String.making_anagrams('cde', 'abc'), 4)
63 | self.assertEqual(String.making_anagrams('fcrxzw', 'jxjw'), 6)
64 | self.assertEqual(String.making_anagrams('fcrxzwscanmligyxyvym', 'jxwtrhvujlmrpdoqbisbwhmgpmeoke'), 30)
65 |
66 | def test_advanced_anagrams(self):
67 | self.assertEqual(String.advanced_anagrams('aaabbb'), 3)
68 | self.assertEqual(String.advanced_anagrams('ab'), 1)
69 | self.assertEqual(String.advanced_anagrams('abc'), -1)
70 | self.assertEqual(String.advanced_anagrams('mnop'), 2)
71 | self.assertEqual(String.advanced_anagrams('xyyx'), 0)
72 | self.assertEqual(String.advanced_anagrams('xaxbbbxx'), 1)
73 | self.assertEqual(String.advanced_anagrams('xaxbbbxa'), 1)
74 | self.assertEqual(String.advanced_anagrams('abxxabbx'), 1)
75 |
76 | self.assertEqual(String.advanced_anagrams('hhpddlnnsjfoyxpciioigvjqzfbpllssuj'), 10)
77 | self.assertEqual(String.advanced_anagrams('xulkowreuowzxgnhmiqekxhzistdocbnyozmnqthhpievvlj'), 13)
78 | self.assertEqual(String.advanced_anagrams('dnqaurlplofnrtmh'), 5)
79 | self.assertEqual(String.advanced_anagrams('aujteqimwfkjoqodgqaxbrkrwykpmuimqtgulojjwtukjiqrasqejbvfbixnchzsahpnyayutsgecwvcqngzoehrmeeqlgknnb'), 26)
80 | self.assertEqual(String.advanced_anagrams('lbafwuoawkxydlfcbjjtxpzpchzrvbtievqbpedlqbktorypcjkzzkodrpvosqzxmpad'), 15)
81 | self.assertEqual(String.advanced_anagrams('drngbjuuhmwqwxrinxccsqxkpwygwcdbtriwaesjsobrntzaqbe'), -1)
82 | self.assertEqual(String.advanced_anagrams('ubulzt'), 3)
83 | self.assertEqual(String.advanced_anagrams('vxxzsqjqsnibgydzlyynqcrayvwjurfsqfrivayopgrxewwruvemzy'), 13)
84 | self.assertEqual(String.advanced_anagrams('xtnipeqhxvafqaggqoanvwkmthtfirwhmjrbphlmeluvoa'), 13)
85 | self.assertEqual(String.advanced_anagrams('gqdvlchavotcykafyjzbbgmnlajiqlnwctrnvznspiwquxxsiwuldizqkkaawpyyisnftdzklwagv'), -1)
86 |
87 | def test_pangrams(self):
88 | self.assertEqual(String.pangrams('We promptly judged antique ivory buckles for the next prize'), True)
89 | self.assertEqual(String.pangrams('We promptly judged antique ivory buckles for the prize'), False)
90 |
91 | def test_matched_pattern(self):
92 | self.assertEqual(String.is_iterative_pattern('a'), True)
93 | self.assertEqual(String.is_iterative_pattern('aaa'), True)
94 | self.assertEqual(String.is_iterative_pattern('abcabc'), True)
95 | self.assertEqual(String.is_iterative_pattern('ababab'), True)
96 |
97 | self.assertEqual(String.is_iterative_pattern(''), False)
98 | self.assertEqual(String.is_iterative_pattern('ab'), False)
99 | self.assertEqual(String.is_iterative_pattern('ababc'), False)
100 |
101 |
--------------------------------------------------------------------------------
/tests/test_tree.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from algorithms.tree import Node
3 |
4 |
5 | class TestTree(unittest.TestCase):
6 |
7 | def test_is_binary_search_tree(self):
8 | tree = Node(4)
9 | tree.left = Node(2)
10 | tree.right = Node(6)
11 | tree.left.left = Node(1)
12 | tree.left.right = Node(3)
13 | tree.right.left = Node(5)
14 | tree.right.right = Node(7)
15 | self.assertEqual(Node.is_binary_search_tree(tree), True)
16 |
17 | tree = Node(3)
18 | tree.left = Node(2)
19 | tree.right = Node(6)
20 | tree.left.left = Node(1)
21 | tree.left.right = Node(4)
22 | tree.right.left = Node(5)
23 | tree.right.right = Node(7)
24 | self.assertEqual(Node.is_binary_search_tree(tree), False)
25 |
--------------------------------------------------------------------------------
/tests/test_with_unittest.py:
--------------------------------------------------------------------------------
1 | """
2 | available by this command
3 | $ python3 tests/test_with_unittest.py
4 | """
5 | import unittest
6 |
7 |
8 | class Array:
9 |
10 | def __init__(self, size, numbers):
11 | self.number_of_swaps = 0
12 | self.size = size
13 | self.numbers = numbers
14 | self.count = 0
15 |
16 | def bubble_sort(self):
17 | for i in range(self.size):
18 | is_swap = False
19 | for j in range(self.size - 1):
20 | self.count += 1
21 | if self.numbers[j] > self.numbers[j + 1]:
22 | self.numbers[j], self.numbers[j + 1] = self.numbers[j + 1], self.numbers[j]
23 | self.number_of_swaps += 1
24 | is_swap = True
25 | if not is_swap:
26 | break
27 |
28 |
29 | class TestArray(unittest.TestCase):
30 |
31 | def test_bubble_sort(self):
32 | numbers = [3, 10, 9, 2, 100, 1, 99, 1000, 232, 7]
33 | print(numbers)
34 | array = Array(10, numbers)
35 | array.bubble_sort()
36 |
37 | number_of_swaps = array.number_of_swaps
38 | numbers = array.numbers
39 |
40 | self.assertEqual(array.number_of_swaps, 17)
41 | self.assertEqual(array.numbers, [1, 2, 3, 7, 9, 10, 99, 100, 232, 1000])
42 |
43 | print('Array is sorted in {} swaps.'.format(number_of_swaps))
44 | print(array.numbers)
45 |
46 | if __name__ == "__main__":
47 | unittest.main()
48 |
--------------------------------------------------------------------------------