대학가 홀로서기를 도전하는 나무
홀로서기를 도전하는 나무의 꽃
대학가 홀로서기를 도전하는 나무
홀로서기를 도전하는 나무의 꽃
함수는 총 세 가지로 작성하였습니다.
getDivisors(int) : 약수를 구하는 함수
perm(number list) : 숫자 배열의 모든 가능한 배열을 추출하는 함수
Decrypt(암호문, 암호문길이, 키) : 암호문을 각각의 키 배열로 브루트 포싱 공격하여 문자열을 얻어내는 함수
main함수에서는 단순히 Decrypt 함수를 불러내는 역할만 하면 되기 때문에 공격 이전에 암호문을 입력받고, 암호문의 길이와 가능한 키 블록의 크기를 알려주도록 하였습니다.
코드는 아래와 같습니다.
import sys #Get Divisors, if 28 ==> 1,2,4,7,14,28 def getDivisors(num): half = int(num/2) divisors = [] while half > 0: if num % half == 0: divisors.append(half) half -= 1 divisors.append(num) return sorted(divisors) #numlist_a is like [1,2,3,4] def perm(numlist_a): length = len(numlist_a) if length == 1: return [numlist_a] else: result = [] for i in numlist_a: numlist_b = numlist_a.copy() numlist_b.remove(i) numlist_b.sort() for j in perm(numlist_b): j.insert(0, i) if j not in result: result.append(j) return result #Decryption Module def Decrypt(encString, encLen, U_Key): F = open(Your_Directory, 'w') # Your_Directory is not Defined... Please Define your own directory msgsize = encLen keysize = len(U_Key) ret = '' blocksize = int(msgsize/keysize) buffer = [''] * keysize d_buffer = [''] * keysize pos = 0 U_Key = perm(U_Key) for i in range(keysize): decString = encString[pos:pos + blocksize] buffer[i] = decString pos += blocksize for each_key in U_Key: for num, d_num in enumerate(each_key): d_buffer[d_num-1] = buffer[num-1] F.write(''.join(d_buffer)) F.write("\n") F.close() if __name__ == "__main__": EncryptedMessage = input("Input Encrypted Message : ") EncryptedLen = len(EncryptedMessage) KeyLenSeries = getDivisors(EncryptedLen) print("\nYour Key Lengths are : ", KeyLenSeries) KeyLen = int(input("\nSelect your key length : ")) if KeyLen not in KeyLenSeries: print("Please Check Your Key Length Again.\nProcess Exit.") sys.exit(0) UseKey = [] for i in range(1,KeyLen+1): UseKey.append(i) Decrypt(EncryptedMessage, EncryptedLen, UseKey)
동작 구조는 다음과 같습니다.
초기 키 값은 처음 생성된 키 배열을 의미합니다.
키 길이 약수가 만약 4로 선택되었다면, [1,2,3,4]가 되겠죠.
Perm은 모든 배열의 가짓수를 구하는 함수이며, 해당 함수에서 나오는 값은 [1,2,3,4], [1,2,4,3], [1,3,2,4], [1,3,4,2] ..... [4,3,2,1]과 같은 모든 가짓수를 한 배열에 저장하게 됩니다.
그리고 이를 이용하여 각각 복호문을 만들게 되는 것입니다.
Python [Windows] Process List Check (2) | 2017.01.15 |
---|---|
Python2 시스템 종료 (Python2 Shutdown) (0) | 2017.01.13 |
제가 설치한 owncloud의 버전은 9.1.4입니다.
또한 php는 버전이 7이상으로 되어 있기 때문에 명령어가 다릅니다.
01. Apache/MySQL/PHP 설치
먼저 APM을 설치해야 합니다. APM이란 Apache2, PHP, MySQL의 줄임말입니다.
가장 최신의 버전을 추구하는 우리는 업데이트나 설치도 굉장히 최신 녀석을 지향해야 합니다.
설치에 앞서 apt-get을 업데이트 해주도록 합시다.
업데이트와 업그레이드를 모두 수행하기 위한 명령어는 다음과 같습니다.
# sudo apt-get update |
# sudo apt-get upgrade -y |
업데이트가 완려되었다면, Apache2를 설치하도록 합시다.
Apache2를 설치하는 명령어는 다음과 같습니다.
# sudo apt-get install apache2 -y |
이제 Apache2가 설치가 잘 완료됐는지 확인해보도록 합시다.
다음과 같은 명령어를 통해 설치가 잘 이루어졌는지 확인할 수 있습니다.
# sudo apache2ctl configtest |
아마도 다음과 같은 답이 나올 것으로 예상됩니다.
Output Systax OK |
또한, Apache2가 제대로 동작하는지 확인해야 합니다.
다음과 같은 명령어를 사용하여 제대로 동작하는지 확인할 수 있습니다.
# sudo ufw app list |
여기서 ufw는 ubuntu firewall의 줄임말입니다.
해당 명령어의 결과로, 동작하고 있는 어플리케이션의 리스트를 보여줄 것입니다.
Available applications: Apache Apache Full Apache Secure OpenSSH |
대략적으로 위와 같은 내용이 나올것입니다.
apache2가 잘 설치되었고 잘 실행이 된 것을 확인했으니, 이제 MySQL을 설치하도록 합시다.
MySQL을 설치하는 명령어는 다음과 같습니다.
# sudo apt-get install mysql-server -y |
MySQL을 설치하면서 패스워드를 입력하라고 나옵니다.
적당히 잘 입력해주신 후 MySQL을 실행시켜주도록 합시다.
# mysql -u root -p |
MySQL을 실행하고 우리가 입력했던 패스워드를 입력하면, 우리가 설치한 MySQL로 들어가지게 될 것입니다.
설치가 완료되었음을 확인했으니, exit 명령어를 통해 MySQL의 커맨드 창에서 빠져나도록 합시다.
이제 Apache2와 MySQL을 모두 설치하였습니다.
마지막으로 PHP를 설치하도록 하겠습니다.
PHP의 경우, php5를 더 이상 지원하지 않는다고 합니다.
따라서 설치할 때 php라는 명령어로 모두 통합되었습니다.
여기서 설치할 목록은 php, libapache2-mod-php, php-mcrypt, php-mysql, php-cli를 설치할 것입니다.
# sudo apt-get install php libapache2-mod-php php-mcrypt php-mysql php-cli -y |
이제 PHP가 설치가 완료되었으니, PHP가 잘 로드될 수 있도록 Apache2를 재시작해줍시다.
# sudo systemctl restart apache2 |
02. owncloud 9.x 설치
owncloud 설치에 앞서 우리는 올바른 owncloud를 설치할 수 있도록 일종의 GPS를 설정해줘야 합니다.
아마 기존의 apt-get update나 upgrade로는 owncloud를 설치할 수 없을 것입니다.
때문에 다음과 같은 설정을 해줘야 합니다.
# curl https://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/Release.key | sudo apt-key add - # echo 'deb http://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/ /' | sudo tee /etc/apt/sources.list.d/owncloud.list |
해당 설정은 apt-get에 아직 다운로드 되지 않은 설정입니다.
좌표를 설정해주었으니 이제 update를 해야겠지요.
# sudo apt-get update |
update가 완료되면 이제 apt-get 명령어로 owncloud를 설치할 수 있을 것입니다.
# sudo apt-get install owncloud -y |
설치는 몇 분 정도 소요될 것입니다. 해당 설치를 완료하고 이제 Apache2를 재시작 해주어야 합니다.
# sudo systemctl restart apache2 |
03. Owncloud 설정
owncloud를 설치했다고 해서 모두 완료된 것이 아닙니다.
owncloud가 사용하는 Database를 설정해주어야 합니다.
다시 MySQL로 들어가보도록 합시다.
# mysql -u root -p |
여기서 owncloud가 사용할 Database를 만들어주어야 합니다.
mysql > CREATE DATABASE owncloud; |
이제 DB가 만들어졌습니다.
DB는 누가 사용할 수 있는지 권한을 만들어주도록 합시다.
mysql > GRANT ALL ON owncloud.* to '사용자 이름'@'localhost' IDENTIFIED BY '패스워드'; |
처음 우분투를 설치할 때 사용했던 아이디로 해도 괜찮고, root로 해도 괜찮습니다.
저는 처음 설치할 때 사용했던 아이디로 생성했습니다.
mysql > FLUSH PRIVILEGES; mysql > exit |
mysql에서 위와 같은 설정을 모두 마쳤다면, 우리가 설치했던 서버로 들어가서 나머지 설정을 완료해주도록 합시다.
http://서버주소:port/owncloud |
서버로 들어가게 되면 위와 같이 나오게 됩니다.
관리자 계정 만들기는 다음과 같습니다.
사용자 이름 : [관리자 아이디] 암호 : [관리자 비밀번호] |
데이터베이스를 MySQL/MarialDB로 설정해준다면 자동적으로 데이터 폴더가 /var/www/owncloud/data로 지정될 것입니다.
그리고 이제 데이터베이스 사용자, 암호, 이름을 작성해주도록 합시다.
데이터베이스 사용자는 우리가 owncloud라는 DB에 권한을 주었던 아이디와 암호, 그리고 데이터베이스 이름에는 owncloud라고 작성하도록 합니다.
[Ubuntu] 우분투 16.04 MySQL 설치 (0) | 2019.02.24 |
---|---|
Ubuntu에서 NMAP 최신 버전 설치하기 (0) | 2017.04.29 |
이전에 Python3와 원격을 포스팅했었습니다.
이는 모두 Git 최신 버전을 설치하기 위함이었습니다!
이제 Git느님을 영접하기 위해 빨리 원격으로 들어가보도록 합시다.
[그림 01] 원격 데스크톱 화면
원격으로 들어오니 제가 바탕화면에 만들어두었던 디렉토리들이 빼꼼히 인사를 건네내요.
반갑게 맞이해주었습니다.
각설하고 이제 원격이 되었으니, git 최신 버전을 인터넷에서 다운로드 하도록 합시다.
[그림 02] git 최신버전 확인 및 다운로드
Download URL : https://www.kernel.org/pub/software/scm/git/
해당 URL을 들어가면 가장 아래에 있는 최신 git 버전을 다운로드하도록 합시다.
제가 설치한 git은 git-2.12.0.tar.gz로 압축되어 있는 버전입니다.
[그림 03] git 압축 해제
압축 해제하고 git 디렉토리로 들어가보도록 합시다.
해당 디렉토리로 들어가서, 터미널을 열어서 명령어를 쭉 입력해주도록 합시다.
$ make configure $ ./configure --prefix=/usr $ make all doc info $ sudo make install install-doc install-html install-info |
[그림 04] git 설치 확인
CentOS7 ElasticSearch Setup (CentOS7 ElasticSearch 설치) (3) | 2017.05.21 |
---|---|
CentOS7 xrdp, tiger-vncserver 원격데스크톱 (0) | 2017.03.09 |
CentOS 7에 파이썬 3.4 버전 설치 (CentOS 7 python3.4 install) (3) | 2017.03.08 |
CentOS 7 SSH 포트 변경 (CentOS 7 SSH Port modify) (0) | 2017.03.05 |
CentOS7에서 다음과 같은 과정을 통해 원격 데스크톱이 지원되도록 만들 수 있습니다.
설치과정은 다음과 같습니다.
01. 필요 도구 설치 및 설정
필요한 도구는 epel, xrdp, tigervnc-server가 있습니다.
저는 epel과 xrdp, tigervnc-server를 나누어서 설치를 수행하였습니다.
먼저 다운로드 하는 명령어는 다음과 같습니다.
$ yum install epel-release xrdp tigervnc-server |
필요한 도구를 모두 설치하셨다면, 원격 설정을 먼저 해주고 서비스를 실행시키도록 합시다.
다음 명령어를 수행하시면 Password와 Verify라는 입력창이 뜹니다.
원하시는 비밀번호를 입력하고 다시 한 번 입력하시면 됩니다.
$ vncpasswd Password:******** Verify:******** |
설치가 완료되면, 서비스를 시작해주어야 합니다.
설치를 했을 때, 먼저 서비스의 상태를 사용가능으로 바꿔줘야 합니다.
이후 서비스를 실행하도록 합시다.
서비스를 시작하는 명령어는 다음과 같습니다.
서비스 사용가능하게 하는 명령어
$ systemctl enable xrdp |
$ systemctl start xrdp |
이제 해당 동작이 원활하게 되었는지 확인해보도록 합시다.
다음 명령어를 통해 xrdp 서비스가 잘 실행되고 있는지 확인합니다.
$ netstat -antup | grep xrdp |
xrdp에 대한 서비스가 몇 개 검색되면 설정이 잘 완료된 것입니다.
다음으로 방화벽을 통해 우리가 원격 데스크톱으로 사용할 서비스 포트를 열어주어야 합니다.
시스템은 우리가 단순히 서비스를 구동한다고 하여 네트워크에 대한 보안을 간과하지 않습니다.
02. 방화벽 설정
우리가 방화벽에서 설정해 줄 것은 원격 데스크톱으로 사용할 포트번호를 방화벽에서 들어올 수 있도록 열어주는 작업입니다
방화벽에서 열어줄 포트를 설정해주는 명령어는 다음과 같습니다.
$ firewall-cmd --permanent --zone=public --add-port=3389/tcp |
만약 Windows에서 사용하신다면 3389로 설정하는 것이 좋습니다.
Windows에서 사용하는 기본 원격 데스크톱 포트번호가 3389이기 때문에 IP만 입력해주시면 바로 원격으로 들어가지게 됩니다.
우리가 사용할 포트번호를 입력하셨다면, 해당 설정을 방화벽에 적용하기 위해 다시 로드해주어야 합니다.
다시 로드하는 명령어는 다음과 같습니다.
$ firewall-cmd --reload |
03. 기타 설정
여기서 우리가 기타로 설정할 수 있는 기능은 [한글화] 및 [포트번호 변경]이 있습니다.
만약 한글 버전으로 원격을 들어가고 싶다면, 다음과 같은 설정을 추가해주면 될 것 같습니다.
$ vi /etc/xrdp/startwm.sh . . . export LANG=ko_KR.UTF-8 |
먼저 /etc/xrdp/startwm.sh를 수정하셔야 하는데, 해당 내용 중에 export LANG이 있습니다.
여기에 한글을 사용하고자 하시는 분은 ko_KR.UTF-8의 내용을 입력해주시면 됩니다.
이후 한글로 보일 것입니다.
또한 포트번호도 변경할 수 있는데, 포트 변경은 보안을 위해 가급적이면 필수적으로 생각하셔야 할 것 같습니다.
포트번호는 접속하기 위해 입력해야 하는 포트번호를 말합니다.
만약 위의 방화벽 설정에서 열린 포트를 3389로 설정하였다면, 해당 포트번호도 3389로 설정해주셔야 합니다.
하지만, 포트번호를 기존의 번호와 다르게 변경하고자 하시면, 반드시 방화벽의 포트번호도 다르게 열어주셔야 합니다.
포트번호는 다음 파일 내에서 변경할 수 있습니다.
$ vi /etc/xrdp/xrdp.ini . . . port=[원하는 포트 변경] |
먼저 /etc/xrdp/xrdp.ini를 열어보시면, port 라는 부분에 우리가 기존의 포트번호가 작성되어 있을 것입니다.
해당 영역의 값을 우리가 원하는 번호로 입력해주셔야 합니다.
04. 원격 접속 방법
윈도우즈에서 원격 데스크톱를 사용할 때 우리는 3389포트를 기본적으로 사용합니다.
만약 방화벽과 포트번호를 3389로 설정하셨다면 원격 데스크톱을 이용하여 IP만 입력하여 접속하시면 됩니다
하지만 우리가 사용할 포트번호를 따로 설정하셨다면, 뒤에 포트번호를 입력해주셔야 합니다.
원격 데스크톱 접속 방법은 다음과 같습니다.
3389로 설정하였을 시 명령어
원격 데스크톱 창 입력 : [아이피] |
3389가 아닌 다른 포트로 입력하였을 시
원격 데스크톱 창 입력 : [아이피] : [우리가 입력한 포트 번호] |
CentOS7 ElasticSearch Setup (CentOS7 ElasticSearch 설치) (3) | 2017.05.21 |
---|---|
CentOS7에 Git 최신 버전 설치하기 (0) | 2017.03.09 |
CentOS 7에 파이썬 3.4 버전 설치 (CentOS 7 python3.4 install) (3) | 2017.03.08 |
CentOS 7 SSH 포트 변경 (CentOS 7 SSH Port modify) (0) | 2017.03.05 |
CentOS 7 특성상 파이썬 3버전을 설치하는 데에 어려움이 있습니다.
저도 CentOS 7에 파이썬 3버전을 설치하려고 했는데, 아무런 해결책이 보이지 않았습니다.
그러던 도중 StackOverflow에서 다음과 같은 소스가 저를 구해주었습니다.
01. 파이썬 셋업 툴 설치
먼저 파이썬 셋업툴을 설치해주어야 합니다.
파이썬 셋업툴을 설치하는 명령어는 다음과 같습니다.
$ sudo yum install python34-setuptools |
이를 이용하여 파이썬을 설치하게 되면 파이썬 3.4를 설치할 수 있게 됩니다.
02. 파이썬 pip 설치
이후 파이썬에서 제공하는 easy_install-3.4을 이용하여 pip를 설치해주도록 합니다.
설치 명령어는 다음과 같습니다.
$ sudo easy_install-3.4 pip |
파이썬에서 제공하는 명령어를 사용하기 때문에 yum install을 사용하지 않습니다.
03. 파이썬 설치 확인
위의 두 과정을 통해 설치가 완료되었다면 버전을 확인해보도록 합니다.
파이썬 버전을 확인하는 명령어는 다음과 같습니다.
$ python3 --version |
혹은
$ python3 -V |
CentOS7 ElasticSearch Setup (CentOS7 ElasticSearch 설치) (3) | 2017.05.21 |
---|---|
CentOS7에 Git 최신 버전 설치하기 (0) | 2017.03.09 |
CentOS7 xrdp, tiger-vncserver 원격데스크톱 (0) | 2017.03.09 |
CentOS 7 SSH 포트 변경 (CentOS 7 SSH Port modify) (0) | 2017.03.05 |
설치한 버전은 CentOS-7-x86_64-Everything-1611입니다. 이 중에서 Desktop 버전입니다.
/etc/ssh/sshd_config 파일을 수정해야 합니다.
00. SSH 설정에 앞서
먼저 SSH 서비스가 설치되어있는지 확인해야 합니다.
설치 방법은 다음과 같습니다.
$ sudo yum install openssh-server openssh-clients openssh-askpass |
SSH 서비스가 설치되어있다면 바로 "01. SSH 설정 파일 수정"으로 넘어가주시면 됩니다.
만약 설치가 되지 않으시는 분들은 네트워크 설정이 잘 되어있는지, 혹은 yum의 업데이트가 잘 돼있는지 확인해보시기 바랍니다.
01. SSH 설정 파일 수정
먼저 /etc/ssh/sshd_config 내에 있는 port번호를 변경해주어야 합니다.
명령어는 다음과 같이 해주어야 합니다.
$ vim /etc/ssh/sshd_config . . . 포트 번호가 작성되어 있는 부분 수정 . . [그림 01] 참고 |
[그림 01] SSH 포트번호 변경
[그림 01]은 원래 포트번호가 22로 설정되어 있었지만, 자신이 원하는 포트번호로 변경해줄 수 있습니다.
저는 32123 번호로 수정하였습니다.
02. SSH 다시 시작
설정을 바꿔줬다고 하여 바로 수정된 설정이 적용되는 것은 아닙니다.
따라서 SSH 서비스를 다시 시작하여 우리가 설정했던 내용이 적용되도록 해주어야 합니다.
이를 위해 다음과 같은 명령어를 입력해줍니다.
$ systemctl restart sshd.service |
만약 Putty나 기타 SSH에 접속하여 해당 작업을 수행하더라도 문제가 없습니다.
세션(Session)이 유지되기 때문에 시버스를 다시시작해도 현재 접속은 끊기지 않습니다.
문제가 발생하면 곤란하니 접속을 끊지 않고 작업하는 게 좋습니다.
03. SELINUX 설정
위의 설정을 다 하시더라도 문제가 있을 수 있습니다.
제 경우는 SELINUX 설정을 해줘야 변경이 되더군요..
단순히 포트를 열어주거나 해도 문제는 그대로였습니다.
SELINUX를 설정하는 명령어는 다음과 같습니다.
$ semanage port -a -t ssh_port_t -p tcp 32123 |
04. 방화벽 설정
SELINUX만 설정한다고 어떤 OS라도 아이구야 하며, 우리가 설정한 포트번호를 들여보내주지 않습니다.
이런 경우는 우리가 설정한 포트번호가 정상적인 것임을 방화벽에 알려야 합니다.
따라서, 방화벽에 우리가 추가했던 포트 번호를 추가해주어야 합니다.
CentOS7에서의 방화벽 설정은 다음과 같이 할 수 있습니다.
$ firewall-cmd --permanent --zone=public --add-port=32123/tcp |
위의 명령어는 방화벽에 우리가 설정한 포트번호를 tcp 프로토콜로 허용한다는 의미입니다.
해당 작업을 수행하고, 우리가 수정한 내용을 방화벽에 로드해주어야 합니다.
방화벽을 다시 로드하는 명령어는 다음과 같습니다.
$ firewall-cmd --reload |
$ systemctl restart firewalld |
CentOS7 ElasticSearch Setup (CentOS7 ElasticSearch 설치) (3) | 2017.05.21 |
---|---|
CentOS7에 Git 최신 버전 설치하기 (0) | 2017.03.09 |
CentOS7 xrdp, tiger-vncserver 원격데스크톱 (0) | 2017.03.09 |
CentOS 7에 파이썬 3.4 버전 설치 (CentOS 7 python3.4 install) (3) | 2017.03.08 |
[그림 01] Problem 012 문제
문제 설명
문제 이름 : 많이 나누어지는 삼각수
문제 내용 : 삼각수는 자연수를 더해서 생성되는 숫자입니다. 예로 7번째의 삼각수를 구해보면 1 + 2 + 3 + 4 + 5 + 6 + 7을 계산하여 28이라는 숫자가 나옵니다. 그리고 28은 1, 2, 4, 7, 14, 28 이라는 6개의 약수를 가집니다. 그렇다면, 5개 이상의 약수를 가지는 숫자 중 가장 작은 삼각수는 28이라는 말이 됩니다. 이러한 조건으로 500개 이상의 약수를 가지는 가장 작은 삼각수를 구하십시오.
문제의 내용을 자세히 읽어보고 조건을 보도록 합시다.
1. 계산을 할 때마다 삼각수를 구해야 합니다.(ex> n번째 삼각수는 1+2+3+4+.....+n-1+n 임)
2. 약수를 구하는 알고리즘을 적용해야 합니다.
제가 처음에 소스코드를 작성할 때 계산할 때마다 삼각수를 구하여 계산하지 않고 1씩 증가시키는 바람에 굉장히 난해한 문제인가... 했습니다. 흑흑...
다음부터는 문제를 좀 더 자세히 읽어보고 해야겠습니다. 좋은 경험을 했습니다.
자 이제 본격적으로 소스코드를 보도록 합시다.
소스코드
- vol 01
첫번째 소스는 매우 단순하게 작성해보았습니다.
#Problem 012 Highly divisible triangular number #python 3 version source #the first triangle number to have over five hundred divisors def getTriangleNum(): triangleNum = 28 next = 8 count = 0 while True: for i in range(1, triangleNum+1): if triangleNum % i == 0: count += 1 if count >= 500: break count = 0 triangleNum += next next += 1 return triangleNum if __name__ == "__main__": Main_triangleNum = getTriangleNum() print(Main_triangleNum)
위의 소스는 7번째부터 구해진 삼각수의 약수를 구하는 알고리즘입니다.
아주 단순하게 이루어진 소스코드로써, 1 ~ 삼각수 만큼 나눠보고 약수를 구합니다.
그리고 triangleNum에는 다음 삼각수가 되기 위한 next를 더하고, next는 += 1을 해주어 그 다음의 삼각수를 기약합니다.
위의 소스는 계산이 매우 많이 이루어지기 때문에 비효율적입니다... 계산을 엄청 많이 하게 될 것이고, 아마 하루종일 해도 답이 나오지 않을 것으로 예상됩니다.
- vol02
두번째 버전의 소스는 첨부하지 않겠습니다.
위의 소스에서 소수를 모두 제외한 계산을 해보도록 하기 위해 sieve를 첨가하였습니다. 그러나 계산의 가지수는 조금 줄어들 뿐 달라지는 건 거의 없었습니다.
- vol03
세번째 버전의 소스는 다음과 같은 알고리즘을 적용했습니다.
좀 더 효율적인 계산을 위해 미리 약수를 구하는 좋은 수학을 적용시켜 보았습니다.
알고리즘에 대한 설명은 [그림 02]와 같습니다.
[그림 02] 약수 구하는 효율적인 알고리즘
이제 이 알고리즘을 이용하여 소스코드를 작성하면 다음과 같습니다.
#Problem 012 Highly divisible triangular number #python 3 version source #the first triangle number to have over five hundred divisors import math def getTriangleNum(): triangleNum = 28 next = 8 divisor = [] while True: for i in range(1, int(math.sqrt(triangleNum))+1): if triangleNum % i == 0: divisor.append(i) if len(divisor) >= 250: break divisor = [] triangleNum += next next += 1 return triangleNum, divisor if __name__ == "__main__": Main_triangleNum, d = getTriangleNum() print(Main_triangleNum, d)
소스를 설명하자면, 기존의 1 ~ 삼각수까지 range로 잡았다면 범위를 1 ~ log(n)까지 잡았습니다.
그리고 약수의 개수가 500개 이상임을 체크하기 위해서는 그의 절반인 250개 이상으로 보면 됩니다.
vol03의 소스는 5.54초 가량 걸렸습니다.
vol03과 vol01의 계산 효율은 n과 log(n)의 차이입니다.... 훨씬 차이 많이 납니다.
아, 그리고 이번에는 s-anand에서 소스코드를 첨부하지 않을 생각입니다.
이전의 소스코드에도 있었듯이, prime이라는 모듈을 첨부하여 계산하였습니다. prime이라는 모듈은 찾을 수가 없더군요...
그래서 어차피 설명도 이해도 할 수 없는 소스코드니깐 첨부하지 않을 것입니다.
Problem_011_Largest product in a grid (0) | 2017.01.26 |
---|---|
Problem_010_Summation of primes (0) | 2017.01.20 |
Problem_009_Special Pythagorean triplet (0) | 2017.01.20 |
Problem_008_Largest product in a series (0) | 2017.01.09 |
Problem_007_10001st prime (0) | 2017.01.09 |
Problem_006_Sum square difference (0) | 2017.01.07 |
Problem_005_Smallest Multiple (0) | 2017.01.06 |
Problem_004_Largest palindrome product (0) | 2017.01.03 |
Iterator(반복자)를 먼저 알아보기 전에 Iterable이 무엇인지 알아야 하겠죠?
먼저 Python doc의 Iterable 정의를 보도록 합시다.
Iterable
An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict and file and objects of any classes you define with an __iter__() or __getitem__() method. Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), ...). When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object. This iterator is good for one pass over the set of values. When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop. See also iterator, sequence, and generator.
iterable을 정리해보면 member를 하나씩 반환할 수 있는 object를 말합니다.
iterable의 예로는 sequence type인 list, str, tuple이 있습니다.
데이터 타입에 상관 없이 순회를 구현하고자 하는 필요성은 파이썬에만 있었던 것은 아니었다고 합니다. Iterator Pattern은 이미 하나의 디자인 패턴으로 정형화 되어 있는 것 중 하나입니다. 데이터 타입의 내부 구현을 노출하지 않고 포함하고 있는 요소들을 순회할 수 있는 방법을 제공하는 패턴을 이터레이터 패턴이라고 합니다.
※ 대부분 언어에서 이터레이터 패턴을 콜렉션 라이브러리의 구현 방식이나 문법 요소로 제공하고 있기는 하지만 파이썬 만큼 언어 자체에 자연스럽게 녹아 있는 경우는 많지 않다록 합니다.
사실 단순한 for문의 range도 iterable할 수 있는 list가 생성되었기 때문에 차례대로 사용할 수 있었던 것입니다.
for i in range(0,3): print(i) #0 #1 #2
즉, range로 생성된 list가 iterable 할 수 있기 때문에 차례대로 member를 불러와 쓸 수 있다는 것입니다.
그리고 dictionary의 type인 dict도 iterable 할 수 있습니다. 그래서 다음과 같은 결과를 가지고 옵니다.
x = ['a':1, 'b':2, 'c':3] for i in x: print(i) #a #b #c
그리고 __iter__()나 __getitem__() 메소드로 정의된 class는 모두 iterable 할 수 있다고 합니다.
iterable은 for loop말고도 zip(), map()과 같이 sequence 한 특징을 필요로 하는 작업을 하는 데 유용합니다.
zip([iterable, ...])
This function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables.
map(function, iterable, ...)
Apply function to every item of iterable and return a list of the results.
zip()과 map()을 보면 argument를 iterable로 받는 것을 알 수 있습니다.
그리고 이제 iterator를 보도록 합시다.
iterator를 보기 앞서 먼저 Python docs의 정의를 살펴보도록 하지요.
Iterator
An object representing a stream of data. Repeated calls to the iterator’s next() method return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.
iterator는 next()함수로 데이터를 순차적으로 호출 가능한 object입니다. 만약 마지막 데이터를 불러오고도 next()를 하거나 next()함수로 데이터를 가져올 수 없는 경우는 StopIteration exception을 발생시킵니다.
그렇다면 Iterable한 object는 iterator일까요?
결론부터 말씀드리자면, iterable하다고 해서 무조건 iterator라고 할 수는 업습니다.
저는 처음 iterator를 공부할 때, list를 iter()함수를 통해 iterable하게 만들어서 object를 생성해보았었습니다.
list는 iterable이지만 next()함수로는 순차적으로 불러올 수 없었습니다. list로 선언된 것은 보통 a[0], a[1] ...등으로 불러오지요.
list는 순회 가능한(iterable) 오브젝트이지만 __getitem__() 함수를 IndexError가 발생할 때까지 0부터 차례로 호출하기 때문에 개념이 약간 다르다고 할 수 있습니다.
Iterator의 자세한 원리
만약 iterable하더라도 iterator가 아닙니다.
x = [1,2,3,4,5] next(x) Traceback (most recent call last): File ..... iterx = iter(x) next(iterx) #1
그리고 이제 list를 통해 예시를 설명하도록 하겠습니다.
아래의 소스를 보면 type이 어떻게 정의도는 지를 알 수 있습니다.
x = [1,2,3,4,5] type(x) #<class 'list'> iterx = iter(x) type(iterx) #<class 'list_iterator'>
그리고 이제 python 3.x, python 2.7.x의 기준으로 next()를 사용하는 법을 보도록 하겠습니다.
x = [1,2] type(x) #<class 'list'> iterx = iter(x) type(iterx) #<class 'list_iterator'> #=-=-=-=-=-=-=-=-=-=-=- python 2 version iterx.next() #1 iterx.next() #2 iterx.next() #Traceback (most recent ... #StopIteration #=-=-=-=-=-=-=-=-=-=-=- python 3 version next(iterx) #1 next(iterx) #2 #Traceback (most recent ... #StopIteration
list는 1, 2로 이루어져 있으니, 3번째를 가져올 때 StopIteration을 하도록 되어 있습니다.
[그림 01]을 보면 더 확실하게 알 수 있겠습니다. ㅎㅅㅎ
[그림 01] python 2.7.x 와 python 3.x의 next()함수 사용법 비교
자, 그렇다면 next()함수를 통해 다음을 가져온다는 것은 알았는데, 살짝 더 들여다봅시다.
다음 소스는 4개의 list를 iterable한 list(list_iterator)를 구현하고 출력하는 프로그램입니다.
#iterator Test #python 3 version source List_first = [1,2,3,4,5] List_second = ['a','b','c','d'] List_third = ["Third String", "Is", "List_Third~~"] List_forth = [10] List_sum = [] List_sum.append(List_first) List_sum.append(List_second) List_sum.append(List_third) List_sum.append(List_forth) print("print List_sum : ", List_sum) iterList = iter(List_sum) print("\nmake it iterable!!!=-=-=-=-=-=-=-=-\n") for i in range(4): print("print List_next()", next(iterList))
위의 소스를 실행시키면 [그림 02]와 같은 결과를 볼 수 있습니다.
[그림 02] list내의 list를 하나의 iterator로 생성
단순히 list를 가져온다는 것이 아니라 하나의 요소를 가져오는 것으로 이해하시면 더 좋을 것 같아 예시를 넣었습니다.
이러한 iteration은 [그림 03]과 같은 구조로 표현할 수 있습니다.
[그림 03] Iteration 구조
참고 URL : bluese05 님의 글
참고 URL : friberry 님의 글
[Python] 스트링 앞에 0 채우는 방법(zfill, rjust) (0) | 2019.01.30 |
---|---|
Python Yield란?? What is the Yield?? (3) | 2017.01.26 |
Python2.X Python3.X 함께 쓰기 (0) | 2017.01.02 |
Python으로 파일 다운로드 (5) | 2015.08.07 |