Kruscal 알고리즘을 공부하다보니,

Union Find 알고리즘 개념을 이해해야 하기때문에 우선 Union Find 알고리즘을 우선 정리하겠습니다.

 

목차
- Union Find란?
Union Find 동작 방식 분석
- 코드 작성

 

 

1. Union Find란?

Union 이란 합집합이라는 뜻을 가지고 있습니다. 그래서 Union Find 알고리즘이란 합집합을 찾는 알고리즘
이라고 이해하면 될 것 같습니다.

주로 그래프 내에서 집합, 순환을 찾기 위해 사용합니다.

 

1-1 .먼저, 집합을 찾는 경우 입니다.

7개의 노드의 연결을 보여주는 그림을 봅시다.

그림 1. Union Find 알고리즘

 

이 경우 위 사진과 같이 2가지 그룹으로 나누어지는데, 이렇게 2가지를 찾아낼때 Union Find 알고리즘을 사용합니다.

 

2-2. 그리고 두번째로 순환 구조를 찾을때 사용합니다.

 

그림 2. 그래프에서 순환 찾기

 

위 그림처럼 왼쪽 그래프처럼 연결되어 있는 상태에서 3번 노드와 5번 노드를 연결한다면, 그림 2의 오른쪽 그림처럼
3,4,5는 순환이 되게 됩니다. 그리고 Union Find로 이런 순환을 찾아낼 수 있죠.

크루스칼 알고리즘의 경우 최소 비용으로 그래프를 연결해야 하기 때문에, 순환이 되면 안되는 조건이 있습니다.
이때 Union Find 알고리즘을 이용하는 것이죠!

 

 

2. Union Find 동작 방식 분석

UnionFind 알고리즘을 간단하게 정리하면
"각각의 노드의 부모가 동일하면 합집합, 그렇지 않으면 다른 집합"
이라고 판단하는 것 입니다.

알고리즘 구성은 아래와 같습니다.

1. 노드를 탐색하여 연결되어 있으면 부모 노드를 얻어온다.
2. 부모의 노드가 다르다면 둘 중 큰 번호의 부모 노드를 작은 번호의 부모 노드로 변경

그렇기 때문에 노드들의 부모를 작성해 줄 배열이 하나 필요합니다.
예제는 아래 그림 3 처럼 노드의 수는 7개, 2개의 집합으로 구분 가능한 그래프를 가지고 진행하겠습니다.

그림 3. 예제 그래프

 

 

우선 아래 그림과 같이 노드가 7개니까 길이 7의 parent 배열을 생성하고, 각각의 부보는 자기를 가르키도록 초기화 합니다.

그림 4. parent 배열 생성 및 초기화

 

1부터 시작해서 7까지 탐색합니다.

 

2-1. 노드 1 탐색

1) 1의 노드는 2와 연결되어 있기 때문에 부모 노드를 얻어옵니다.
그리고 1과 2의 부모 노드는 다르기때문에 2의 부모 노드를 1로 변경 합니다.

2) 1의 노드는 4와 연결되어 있기 때문에 부모 노드를 얻어옵니다.
그리고 1과 4의 부모 노드는 다르기때문에 4의 부모 노드를 1로 변경 하며 1의 탐색은 종료합니다.

그림 5.  노드 1 탐색

 

 

2-2. 노드 2 탐색

다음 2 노드를 탐색합니다.

1) 2는 1과 연결되어있습니다.
2) 부모노드를 얻어옵니다.
3) 2개의 노드 모두 부모 노드가 1로 동일 하기때문에 넘어갑니다.

 

2-3. 노드 3 탐색

3 노드를 탐색합니다.

1) 3의 노드는 4와 연결되어 있습니다.
2) 부모노드를 얻어옵니다.
3) 3의 부모와 4의 부모는 다르기 때문에 작은 노드로 변경합니다.
4) 그런데 3의 부모는 3, 4의 부모는 1이기 때문에 3의 부모 노드를 1로 변경합니다.

 

그림 6. 노드 3 탐색

 

2-4. 노드 4 탐색

노드 4는 1, 3 노드와 연결되어 있습니다.
부모의 노드를 얻어오는데, 둘 다 부모의 노드가 동일함으로 넘어갑니다.

 

2-5. 노드 5 탐색

노드 5는 6과 연결되어 있습니다.
둘의 부모 노드가 다르기때문에 6의 부모 노드를 5로 변경합니다.

그림 7. 노드 5 탐색

 

2-6 노드 6 탐색

노드 6은 5와 연결되어있지만 부모 노드가 동일함으로 넘어갑니다.
그리고 노드 7과도 연결되어있습니다.
노드 6과 7의 부모는 다르기때문에 노드 7의 부모를 6의 부모 노드인 5로 변경합니다.

그림 8. 노드 6 탐색

 

2-7. 마지막 노드 7 탐색

노드 7은 6과 연결되어있지만, 둘의 부모노드가 동일하기 때문에 넘어갑니다.

이렇게 프로그램은 종료되고 부모 노드는 아래와 같이 정리 됩니다.

 

그림 9. 종류 후 parent 표 상태

 

이렇게 종료가 된후 부모노드가 1인 그룹과 부모노드가 5인 그룹 이렇게 2개로 구성되어 있음을 알 수 있습니다.

이것이 Union Find 알고리즘 동작 방법입니다.

 

3. 코드 작성

코드로 작성하면 아래와 같습니다.

	//부모노드 찾기
	public int getParent(int parent[],int search) {
		if(parent[search] == search) return search;
		else
			return parent[search] = getParent(parent, parent[search]);
	}
	//합친 후 부모 노드 작은걸로 바꾸어주기
	public int[] changeParent(int parent[], int a, int b) {
		a = getParent(parent, a);
		b = getParent(parent, b);
		if(a<b) parent[b] = a;
		else parent[a] = b;
		
		return parent;
	}
	//부모 노드 찾기
	public boolean findParent(int parent[], int a, int b) {
		a = getParent(parent,a);
		b = getParent(parent,b);
		if(a==b) return true;
		else return false;
	}
    
	public static void main(String[] args) {
		UnionFind f = new UnionFind();
		int n = 8;
		
		int[][] graph = {{1,2},{1,4},{4,3},{5,6},{6,7}};
		int[] parent = new int[n];
		for(int i=1; i<n; i++) { parent[i] = i;}
        
        //부모 노드 바꾸기
        for(int i=0; i<graph.length; i++) {
			f.changeParent(parent, graph[i][0], graph[i][1]);
		}
        //부모 노드 출력
        for(int i=1; i<n; i++)
			System.out.print(parent[i] +" ");
     }

 

 

이 개념을 알면, 크루스칼 알고리즘은 아주아주 쉽게 이해하고 사용할 수 있습니다!

 

 

 

예제는 지난시간에 받아온 프로젝트 project를 이용하겠습니다.

 

1. git push / git pull 

git push는 내 local에서 변경된 사항을 Remote Repository에 적용하는 것 입니다.

git pull은 remote Repository와 버전을 맞추는 것 입니다.

 

아래 그림과 같이 A / B가 같은 프로젝트를 한다고 가정하겠습니다.

그림 1. Git 형상관리 (1)

 

각자의 컴퓨터에 프로젝트를 Clone 해서 현재는 버전이 동일한 상태 입니다.

그리고 A가 코드를 수정한 뒤 Remote로 Push를 하게되면? 아래 사진과 같이 됩니다.

그림 2. Git 형상관리 (2)

 

 

A와 B는 서로 다른 버전을 갖게 됩니다. 이상태에서 B가 코드를 수정한 후 push하면?
Remote의 버전과 B의 버전이 맞지 않기 때문에 에러가 발생하게 됩니다.

그림 3. Git 형상관리 (3)

 

그러면 어떡해야 할까여?

이때 B는 git pull을 받아야 합니다.
충돌이 발생하지 않는 이상 B가 git pull을 받으면 현재 코드와 자동으로 Merge가 됩니다.
이후에 다시 Push를 하면 정상적으로 반영이 됩니다.

그림 4. Git 형상관리 (4)

 

2. git commit

commit은 무엇인가? commit은 Push하기 전 내 local에서 Remote로 push할 내용들을 저장하는 것 입니다.

A가 개발한 a기능과 b기능이 있다고 가정합니다.
1) 그러면, a기능 개발 후 commit , b기능 개발 후 commit 이런식으로 나누어 줍니다.
2) 이후 push를 하게 되면 commit한 내용들이 push가 되는 것 입니다.

그림 5. git commit & push

 

git pull, commit, push의 개념을 이해하려면 먼저 아래 상태표를 알아야 합니다.

★○@!! 

그림 6. file life cycle

그림 6의 출처는 ->Git git-scm.com/book/ko/v2 입니다. 

이 내용은 https://git-scm.com/book/ko/v2/Git%EC%9D%98-%EA%B8%B0%EC%B4%88-%EC%88%98%EC%A0%95%ED%95%98%EA%B3%A0-%EC%A0%80%EC%9E%A5%EC%86%8C%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0 여기보다 더 잘 설명할수가 없어서 링크로 올립니다.

- 읽어보면 더이상의 설명은 필요없을듯 해서 생략 -

 

'IT > Git' 카테고리의 다른 글

reset, revert, stash  (0) 2020.05.03
Git submodule?  (0) 2020.03.07
Git - tag 긋기  (0) 2019.06.21
기존에 있던 프로젝트 Git으로 관리하기  (0) 2019.05.20
Git 개념 - init, clone  (1) 2019.05.20

웹 개발을 공부하다가 문득 궁금해졌습니다.

Data Base를 연동하는 방법을 검색하면 다양한 방식이 나오는데, DB에 연동하는 방법은 몇가지나 있고,
어떤 방식이 적합한지 판단할까요?

그래서 여기저기 찾아보며 정리해본 결과 크게 3가지로 나눌 수 있었습니다.

1. Java에서 지원하는 JDBC를 이용하여 DB와 통신하는 방식
2. JDBC Template을 이용하여 DB와 통신하는 방식
3. MyBatis를 이용해서 DB와 통신하는 방식
   - Mapper Class를 생성해서 쿼리를 작성하는 방식
   - DXML 파일에 쿼리를 작성하고 DAO 객체에서 불러드려 DB에 쿼리를 전송하는 방식

 

물론, 위 3가지 방식에서도 프로젝트 설계에 따라 사용하는 방식은 다릅니다. 그래서 구글에 검색하면 이렇게 해라 저렇게 해라 정보가 너무나도 많아 뭘 써야할지 헷깔리게 됩니다.

어쨋건 세세한 방식은 서서히 알아가도록 하고,  큰 틀에서 개념만 잡도록 하겠습니다.

 

위 3가지 방식을 전부 구현해볼 생각인데, 아래 사진과 같이 개발 구성도와 흐름도는 동일하게 구현할겁니다.

1. 개발환경 및 정보

STS : Spring legacy Project - MVC
MySQL :
- DB URL: Localjdbc:mysql://localhost:3306/using_jdbc
- DB 접속 ID / PW : dan / 1234
- 사용할 DB : 

 

2. 흐름도

그림 1. DB 연동 학습을 위한 프로젝트 흐름도

 

DB 연동 시작해봅시다!

 

기존에 있던 프로젝트를 Git으로 관리하고 싶은 상황이 발생!!

1) 개인 노트북으로 프로그래머스 코딩테스트 문제를 Eclipse를 이용해 풀고있었다.
2) 그러던 중 데스크톱과 연동을 하면 좋을 것 같아서 Git으로 관리하기로 결정
3) 이미 사용하던 프로젝트 Repository와 어떻게 연동할까!?

 

- 순서 요약 정리 (git Bash 사용함)

1. 먼저 내 github 홈페이지에 새로운 Repository를 만든다.
2. 이것을 git Bash를 켜고 내가 관리할 폴더에 Clone 한다.
3. 여기에 기존 프로젝트중 필요한 것들을 clone한 폴더로 복사한다. 
4. 복사 후 폴더로 들어간 다음 git status로 상태를 보면 다음과 같이 방금 변경 된 내용들이 출력 될 것이다.
5. 이것을 모두 add 한다. 
6. 그 다음 commit 이후 push 하면 끝!!!

 

시작

 

1. 먼저 내 github 홈페이지에 새로운 Repository를 만든다.

그림 1. github 홈페이지에 new Repository 생성

 

2. 이것을 git Bash를 켜고 내가 관리할 폴더에 Clone 한다.

그림 2. git clone

clone 방법은 " git clone https://github.com/{Repo 주소}/{Repo 이름.git} {사용할 프로젝트 이름} "을 입력하면 위 사진처럼 clone 된다.

 

3. 여기에 기존 프로젝트중 필요한 것들을 clone한 폴더로 복사한다. 

그림 3. 기존 프로젝트 clone 받은 폴더로 복사

 

4. 복사 후 폴더로 들어간 다음 git status로 상태를 보면 다음과 같이 방금 변경 된 내용들이 출력 될 것이다.

그림 4. git status

 

5. 이것을 모두 add 한다. 

그림 5. git add

 6. 그 다음 commit 이후 push 하면 끝!!!

기존 프로젝트와 새로운 Project를 Merge 하는것이 아닌 이유는, 기존 프로젝트의 양이 엄청 적었기 때문에 걍 새로 추가하는게 더 빠를 것이라고 판단했기 때문이다.

 

Eclipse에서 UI를 이용해서 하는 방법도 물론 있지만, 개인적으로 Bash로 관리하는게 편함
프로젝트 두개를 합치는 방식은 나중에 할일이 생길때 정리하겠음.

단순한게 최고시다 빠이야!!

'IT > Git' 카테고리의 다른 글

reset, revert, stash  (0) 2020.05.03
Git submodule?  (0) 2020.03.07
Git - tag 긋기  (0) 2019.06.21
Git 개념 (2) - pull / commit / push  (0) 2019.05.22
Git 개념 - init, clone  (1) 2019.05.20

git을 사용하려면 git에 대한 개념을 알아야 겠죠.
(관리자 입장이 아니면 사실 pull/ commit /push만 알면 될듯 하네요)

물론, 제가 배운 내용의 출처는 " https://git-scm.com/book/ko/v1 "이며, 해당 책에는 Git에 관한 모든 내용이 완전 잘정리 되어있습니다. 

 

Git - 시작하기

Chapter 1 시작하기 이 장에서는 Git을 처음 접하는 사람에게 필요한 내용을 다룬다. 버전 관리 도구에 대한 약간의 배경지식, Git의 특징, Git을 설치하는 법 그리고 Git을 시작하기에 앞서 필요한 설정을 하는 방법을 설명한다. 이 장을 다 읽고 나면 Git의 탄생 배경과 Git이 사용되는 이유를 이해하고, Git을 시작하기 위한 준비가 되어있을 것이다.

git-scm.com

하지만 저는 급하게 프로젝트 만들거나 혼자서 놀다가 갑자기 생각안날때를 대비해서 정리하도록 하겠습니다.

정리하려는 내용은 개념 기반입니다. 제가 Git을 관리할때 리눅스 서버에서 관리를 했기때문에 'Git Bash'를 이용하여 예제를 만들 것 입니다.

결론적으로 Git 관리 tool선택은 개념이 똑같기 때문에 무엇을 선택하든 상관이없습니다.
(개발환경 내 Git 관리(ex. Spring git 연동관리/ Working tree/ GitHub Desktop... 등) tool을 이용해서 관리해도 되지만, 전 터미널에서 관리하는게 편합니다. 취존부탁ㅎ)

 

 

목차
1. git --help
2. git init
   2-1. git 저장소(repository) 만들기
   2-2. bare 저장소(bare repository) 만들기
3. git clone
   3-1. git clone 사용
4. repository 생성 요약정리

 

 

 

1. git --help

Q. git을 사용할때 명령어가 생각이 안난다면?

A. git --help 치면 아래 사진처럼 다 나옵니다.

사진 1. git --help

 

그래서 1장에 정리할 내용은? start a working area부분

clone과 init 입니다.

 

2. git init

'git init' 은 .git 이라는 하위 폴더를 생성하여 해당 폴더를 git으로 관리할 수 있게 해주는 명령어 입니다.
.git 폴더 내에는 프로젝트 관리를 위해 필요한 내용을 담는 내용물로 구성되어 있습니다.

 

git으로 프로젝트를 관리하려면 git으로 관리할 프로젝트에 'git init' 명령어를 통해 초기화 하여 관리할 수 있게 됩니다.

사진 2. git init 사용

위 사진에서 보듯이 'git init' 명령어를 사용하게 되면 .git 이라는 폴더가 생성 됩니다.
.git 폴더 내에는 git 관리에 필요한 파일들이 있습니다. 

git init 명령어를 통해 .git이 생성 되면 해당 프로젝트는 git으로 관리할 수 있게 되는 것이죠!

2.1 git 저장소(repository) 만들기

그런데, 새로 만들 폴더를 저장소(repository)로 만드려면, repo를 가르키는 master가 필요하고, 이것은 최초 1회 commit을 통해 생성할 수 있습니다.
그렇기 때문에 아래 사진처럼 ReadMe.txt 파일을 add하고 commit을 함으로써 저장소가 생성이 된 것입니다!

사진 3. git repository 생성

 

git의 사용 목적은 다수의 사용자들과 함께 프로젝트를 진행하기 위함입니다.

프로젝트 용량이 커지게 되면, 전체 프로젝트를 왔다갔다 저장소로 옮기기 힘들어 집니다.

그렇기 때문에 원격 저장소는 실제 작업 파일을 가지고 있는 일반 저장소(repository) 보다는
프로젝트의 정보변경 사항만 적용이되는 bare repository가 원격 저장소로 적합합니다.

 

 

2.2  bare 저장소(bare repository) 만들기

 

bare repositroy를 만드는 법은 간단합니다. 아래와 같은 명령어로 만들 수 있습니다.
$ git clone --bare {프로젝트 이름} {프로젝트이름.git}      //(사진 4. 참고)
.git 이름표를 붙이는 이유는 bare repo라는것을 알기 위함입니다.

사진 4. bare repository 생성

 

이렇게 생성된 bare repository는 기존 저장소와 내용물이 다릅니다.

사진 5. bare repo 내용물

 

내용물 대신 프로젝트의 정보를 담고있는 파일들로 저장이 되어 있습니다.

그렇기 때문에 프로젝트의 실제 작업물을 담고있는 no bare 저장소에 비해 변경 사항만 저장되는 bare저장소는 가볍기 때문에 원격저장소로 두기 적절합니다.

그러면, bare repo에서 변경된 내용은 어떻게 저장되는가? 하면 위 사진의 object 폴더 내에 저장이 됩니다. (물론 사람이 알아볼수있게는 안써있음)

 

 

 

3. git clone

git clone이란 저장소(Repository)로 부터 프로젝트를 복제하는 것을 말합니다.

이 개념을 이해 하려면 아래 사진을 보면 됩니다.

사진 6. git 관리 형태

 

간단하게 보면 각 컴퓨터들은 저장소로 수정한 내용을 push하고, pull 받으며 버전을 동일하게 유지합니다. 이러한 과정 덕분에 모든 컴퓨터들은 협업이 가능해지게 되는 것 입니다.

 

3.1 git clone 사용법

Q. 그럼 git clone은 언제 사용할까요?

A. git clone을 사용하는 것은 일반적으로 2가지 입니다. 

1) bare repository를 생성할 때 (최초 생성할때 사용)
2) 저장소에 있는 Project를 내 PC에 설치할때 (자주 사용)

실질적으로 clone은 2번 경우에 자주 사용됩니다.

진행중인 프로젝트에 투입하게 되는 경우, 저장소에 있는 프로젝트를 내 컴퓨터에 설치해야 하는 경우가 많기 때문입니다.

 

- 사용법은 ?

git clone 사용법은 간단합니다.  아래와 같은 형태로 사용합니다.

git clone {프로토콜} {프로젝트 주소}.git 

 

구체적으로 Git에서는 Local, HTTP, SSH, Git 이렇게 4가지 프로토콜을 지원합니다. 따라서 이 프로토콜에 맞게 명령어를 입력하면 clone 할 수 있습니다. 

ssh 예제) $git clone ssh://{서버 계정}@{서버 주소}:/{저장소 위치/받을 프로젝트 이름}.git

http 예제) $git clone https://{url/받을 프로젝트 이름}.git

 

git 지원 프로토콜에 대해 자세히 할고싶다면 여기 클릭

 

그럼 방금 만든 bare repository에서 git clone을 해보겠습니다.

$git clone project_origin.git/ project   
-> Local에서 clone 하기때문에 따로 프로토콜을 이용할 필요는 없습니다.
remoteproject_origin.git의 내용을 project 라는 이름으로 clone 하고자 합니다.

사진 7. git clone 예제

잘 되는군요.

project 폴더 내용과 remote 주소를 볼까요?

사진 8. git clone 예제(2)

정상적으로 clone 된것을 확인할 수 있습니다.

 

4. repository 생성 요약정리

결과적으로 오늘 정리한 내용은 아래 그림 하나로 정리가 가능합니다.
repository 생성 방법만 보려면 이것만 보면 되겠네요.

사진 7. Repository 생성 흐름도

 

오늘은 여기까지!

 

'IT > Git' 카테고리의 다른 글

reset, revert, stash  (0) 2020.05.03
Git submodule?  (0) 2020.03.07
Git - tag 긋기  (0) 2019.06.21
Git 개념 (2) - pull / commit / push  (0) 2019.05.22
기존에 있던 프로젝트 Git으로 관리하기  (0) 2019.05.20

진수를 변환하는 알고리즘을 사용하면 간단하게 풀리는 문제들이 있습니다.

그래서 진수 변환하는 방법을 정리해보도록 하죠

 

1. 10진수 -> 2진수 변환

public void DecimalTobinary(int num) {
		StringBuffer sb = new StringBuffer(); // 거꾸로 출력하기 위한 버퍼 생성
		String answer="";
		while(num>0) {
			answer += num%2;
			num = num/2;
		}
		sb.append(answer); // 버퍼에 answer 저장하고
		System.out.println(sb.reverse()); // 거꾸로 출력하기
	}

 

2. 10진수 -> 8진수 변환

public void DecimalToOctal(int num) {
		StringBuffer sb = new StringBuffer();
		String answer="";
		while(num>0) {
			answer += num%8;  //8로 나눈 나머지 저장
			num = num/8; // 8 나누기
		}
		sb.append(answer);
		System.out.println(sb.reverse());
	}

이제 특징이 보이나여??
10진수 -> N진수로 변환하고 싶으면 원하는 숫자를 0이 될때까지 N으로 나눈 나머지를 출력하면 된다는 것!
(단, N은 1< N < 10을 만족하는 정수)

 

// 2 -> 10
// 8 -> 10
// 16 -> 10 , 10 -> 16 등등 모두 정리하기

3. 

'알고리즘 공부 > 코딩테스트 준비' 카테고리의 다른 글

DFS/BFS 탐색 알고리즘 (행렬 구현)  (0) 2019.06.03
피보나치 수열  (0) 2019.05.20
행렬의 회전  (0) 2019.05.20

피보나치수열을 알면 1분컷 모르면 난이도 헬이 되는 문제들이 많죠

피보나치 수열 문제는 구현이 어렵지 않습니다.
이 문제를 피보나치로 풀 수 있느냐 아니냐를 판단할 수 있는 능력이 더욱 중요할 것 같습니다.

 

시작!

 

1. 피보나치 수열

피보나치는 f(n) = f(n-1) + f(n-2) 라는 공식을 갖는 수열입니다.

f(1) = 1, f(2) = 1 이라고 가정하게 되면 수열은 아래와 같이 진행됩니다.

1 -> 1 -> 2 -> 3 -> 5 -> 8 -> 13 -> 21 -> 34 -> 55 -> 89 -> 144 .....

대표적으로 타일링 문제가 피보나치 수열을 사용하는 문제 중 하나죠.

피보나치를 구현하는 방법은 다양합니다만 오늘 다룰 방식은 1)재귀함수 방식, 2)for문을 이용한 방식
이렇게 2가지로 구현하여 정리 해 볼 예정입니다.

 

2. 재귀함수를 이용하여 피보나치 수열 구현하기

public int fibo_Recursive(int num) {
		//1,1,2,3,5,8,13,21,34,55,89,143 ...
		if(num == 1) {return 1;}
		else if(num == 2) {return 1;}
		else
			return fibo_Recursive(num-2) + fibo_Recursive(num-1);
	}

코드는 간단합니다.

그럼 피포나치 수열 중 6번째 수를 구하는 과정을 보도록 하겠습니다. (1, 1, 2, 3, 5, 8 ...)

그림 1. 피보나치 순환 구조

 

6번째 값을 구하는 과정을 보면 위 그림과 같이  f(5) -> f(4) -> f(3) -> f(2),f(1) 순서로 함수를 호출하며 값을 더해 갑니다.

그런데 이 경우 구현은 쉽지만 재귀함수 특성상 메모리를 많이 사용하기 때문에 코딩테스트에서 사용하기엔 적합하지 않습니다.

그래서 두 번째 방법 반복문을 이용하여 피보나치를 구현하는 것 입니다.

 

2. 반복문을 이용하여 피보나치 수열 구현하기

코드를 먼저 보도록 하겠습니다.

public int fobo_loop(int num) {
		int cur = 1;  // 현재 값
		int next = 1; // 다음 값
		int answer = 0; // 합을 저장할 변수
		
		for(int i=1; i<=num; i++) {
			cur = next;
			next = answer;
			answer = next + cur;
		}
		return answer;
	}

 

for문으로 구현할 경우
1) 현재 값을 저장할 변수 cur 다음 값을 저장할 next, 그리고 두개의 합을 저장할 변수 answer을 생성하고
2) 첫째항부터 원하는 위치까지 하나씩 더하는 과정을 반복 합니다.

6번째 항을 구하는 과정을 그림으로 봅시다.

그림 2. 피보나치 수열 반복문 구조

그림에서 보듯이 첫째 항 : cur = 1,  둘째 항 : next = 2로 두고, 이 두개를 더한 값을 answer에 저장합니다.
처음에 6번째 수를 구하고자 하였으니 6번을 반복하게 되면 원하는 값인 8이 출력되게 됩니다.

반복문으로 구현하게 되면 기대 되는 시간 복잡도는 O(n)이 되기 때문에  재귀함수에 비해 효율적으로 사용할 수 있어 코딩테스트를 할때 사용하기 편리합니다.

 

이상!

'알고리즘 공부 > 코딩테스트 준비' 카테고리의 다른 글

DFS/BFS 탐색 알고리즘 (행렬 구현)  (0) 2019.06.03
진수 변환  (0) 2019.05.20
행렬의 회전  (0) 2019.05.20

코딩 테스트를 준비할때 알아두면 시험볼때 편리 할 코드들을 정리하겠습니다.

 

1.  행렬의 순환

여기서 포스팅하려는 행렬의 순환은 N x M 행렬이 주어지고,
아래 그림과 같이 한 방향으로 순환을 하는 코드를 말합니다.

그림으로 예를 보자면

그림 1. 3 x 3 행렬 순환 하기 (1)

 

1) 코드를 한 번 실행하면 아래 그림과 같이 (1,2)에 있는 동그라미가 (1,3)으로 이동

그림 2. (1,2) 에서 (2,3)으로 이동

 

2) 한번 더 실행하면 (1,3)에 있는 동그라미가 (2,3)으로 이동

그림 3, (1,3)에서 (2,3)으로 이동

 

3) 이것을 반복하면 행렬의 가장자리를 순환하게 됩니다.

이와 같은 행렬의 순환 코드를 정리 해보도록 하겠습니다.

 

2. 가장자리를 한칸 씩 이동하기

여기서 구현해 볼 코드는 그림 1 -> 그림 2 에서 볼때 처럼 (1,2)에 있는 동그라미를 삭제하고
(1,3)에 입력 해서 한번만 수행하는 것이 아닌,
아예 한번 실행하면 (1,1) 부터 가장자리만 한 칸씩 이동하도록 구현해 보겠습니다!!

그림으로 보자면 아래와 같습니다.

1) 한바퀴 돌면 아래 그림과 같이 가장자리를 1칸씩 이동합니다.

그림 4. 가장자리 순환 (1)

2) 한바퀴 더 돌면 아래 그림과 같아집니다.

그림 5. 가장자리 순환 (2)

 

3. 코드로 구현하기

이제 코드로 구현해보겠습니다.

package codingTest_concept;

public class Matrix_circulation {
	
	public void circulation(String[][] matrix) {
		
		int start_h = 0;
		int start_w = 0;
		String temp_1 = matrix[start_h][start_w];
		String temp_2 = "";
		
		//오른쪽 이동
		while(start_w != matrix.length-1) {
			temp_2 = matrix[start_h][start_w+1];
			matrix[start_h][start_w+1] = temp_1;
			temp_1 = temp_2;
			start_w = start_w+1;
		}
		//아래로 이동
		while(start_h != matrix.length-1) {
			temp_2 = matrix[start_h+1][start_w];
			matrix[start_h+1][start_w] = temp_1;
			temp_1 = temp_2;
			start_h = start_h+1;
		}
		//왼쪽으로 이동
		while(start_w != 0) {
			temp_2 = matrix[start_h][start_w-1];
			matrix[start_h][start_w-1] = temp_1;
			temp_1 = temp_2;
			start_w = start_w-1;
		}
		//위로 이동
		while(start_h != 0) {
			temp_2 = matrix[start_h-1][start_w];
			matrix[start_h-1][start_w] = temp_1;
			temp_1 = temp_2;
			start_h = start_h-1;
		}
		
		//출력
		for(int i=0; i<matrix.length; i++) {
			for(int j = 0; j<matrix[i].length; j++ ) {
				System.out.print(matrix[i][j]+" ");
			}
			System.out.println();
		}
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Matrix_circulation m = new Matrix_circulation();
		
		String[][] matrix = {{"A","B","C"},{"H"," ","D"},{"G","F","E"}};
		
		m.circulation(matrix);
		System.out.println();
		m.circulation(matrix);
		

	}

}

 

 

4. 코드 설명

코드가 어떻게 돌아가는건지 그림으로 정리해보져

1. 첫번째로 temp_1, tmep_2를 생성한 후, temp_1에는 시작 위치의 값을 저장합니다.
그리고 오른쪽 이동 while문으로 진입합니다. 그리고 temp_2에 그 오른쪽 위치의 값을 저장합니다.

그림 6. while문 오른쪽 이동 (1)

2. 그 다음 temp_1에 저장된 값을 오른쪽 위치에 저장하고, 현재 위치를 한칸 이동합니다.
(여기까지가 while문 오른쪽 이동 1바퀴 입니다.)

그림 7. while문 오른쪽 이동(2)

3. 다시 1번 부터 반복하게 됩니다.
1)temp_2에 현위치 기준 오른쪽 값을 저장하고,
2)오른쪽 위치에 temp_1에 저장된 값을 삽입합니다.
3) temp_1에 temp_2 값을 저장합니다.
4)그리고 현재 위치를 오른쪽으로 +1 하여 이동시킵니다.
5) 현재 위치가 행렬크기와 같아짐으로 while문을 빠져나옵니다.

그림 8. while문 오른쪽 이동 (3)

 

- while문 아래쪽
오른쪽 이동이 완료되었으니, 아래쪽으로 이동 while문을 시작합니다.
1) temp_2에 현 위치 기준 아래쪽 위치의 값을 저장합니다.
2) temp_1에 저장되어있던 값을 아래쪽 위치에 저장합니다.

그림 9. while문 아래쪽 이동(1)

3) 그리고 아래 그림과 같이 현재 위치를 아래로 한 칸 이동합니다.
(이렇게 하면 아래쪽 while문 한바퀴를 돌게 됩니다.)

그림 10. while문 아래쪽 이동(2)

그림 9, 그림 10 과정을 아래쪽 위치가 행렬의 h 크기와 동일해질때까지 반복합니다.

그림 11. while문 아래쪽 이동(3)

 

그림 12. while문 아래쪽 이동(4)

이렇게 되면 현재 위치와 행렬의 h값과 동일해짐으로 while문을 빠져나옵니다.

그 다음은 왼쪽 이동 while로 진입하게 됩니다.

왼쪽 이동은 오른쪽 이동 반대로, 위쪽 이동은 아래쪽 이동 반대로 진행되기에 그림은 생략하겠습니다.
(귀찮은거 아님)

 

 

왼쪽이동 while을 끝내고 위쪽이동 while을 끝내면 아래 그림과 같이 마무리가 됩니다!

그림 13. while문 위쪽 이동 마지막

 

이렇게 메서드를 실행하면 한바퀴를 돌게 되는 것이죠!

움직이는 미로 탈출이나, 광고판 시뮬레이션 문제를 풀게될때, 이용하면 좋을 것 같아 정리해보았습니다.


while문의 순서를 바꾸면 반 시계방향으로 돌릴 수 있고, 한번 실행 시 2칸씩 이동한다는 조건이 있으면, 위 메서드를 2번 실행시키면 됩니다.

물론, 효율성 문제를 따지는 문제라면 다른 방식을(?) 찾아봐야겠지만요.

 

'알고리즘 공부 > 코딩테스트 준비' 카테고리의 다른 글

DFS/BFS 탐색 알고리즘 (행렬 구현)  (0) 2019.06.03
진수 변환  (0) 2019.05.20
피보나치 수열  (0) 2019.05.20

+ Recent posts