SMALL

KMP 알고리즘이란?

  • KMP 알고리즘은 문자열 검색 알고리즘 중 하나로, 문자열에서 특정 패턴을 찾는데 사용됩니다. KMP 알고리즘은 문자열 내에서 특정 패턴이 나타나는 위치를 찾을 때, 일반적으로 사용되는 브루트 포스 알고리즘보다 훨씬 빠르게 동작합니다.

 

KMP 알고리즘의 원리

  • KMP 알고리즘의 핵심 아이디어는, 일치하지 않는 문자열 부분을 다시 검색하지 않고 이전 검색 결과를 활용하여 패턴을 찾아가는 것입니다. 이를 위해 패턴 문자열의 접두사와 접미사에 대한 정보를 미리 계산해두고, 이를 이용하여 문자열을 검색합니다.

 

 

KMP 알고리즘

  • C언어
#include <stdio.h>
#include <string.h>

void computeLPSArray(char* pattern, int M, int* lps);

void KMPSearch(char* text, char* pattern)
{
    int M = strlen(pattern);
    int N = strlen(text);

    int lps[M];
    computeLPSArray(pattern, M, lps);

    int i = 0, j = 0;
    while (i < N) {
        if (pattern[j] == text[i]) {
            j++;
            i++;
        }
 
        if (j == M) {
            printf("Pattern found at index %d\n", i - j);
            j = lps[j - 1];
        }
        else if (i < N && pattern[j] != text[i]) {
            if (j != 0)
                j = lps[j - 1];
            else
                i++;
        }
    }
}

void computeLPSArray(char* pattern, int M, int* lps)
{
    int len = 0;
    int i = 1;
    lps[0] = 0;
    while (i < M) {
        if (pattern[i] == pattern[len]) {
            len++;
            lps[i] = len;
            i++;
        }
        else {
            if (len != 0) {
                len = lps[len - 1];
            }
            else {
                lps[i] = 0;
                i++;
            }
        }
    }
}
  • C#
using System;

class GFG {

	void KMPSearch(string pat, string txt)
	{
		int M = pat.Length;
		int N = txt.Length;

		int[] lps = new int[M];
		int j = 0;


		computeLPSArray(pat, M, lps);

		int i = 0; 
		while (i < N) {
			if (pat[j] == txt[i]) {
				j++;
				i++;
			}
			if (j == M) {
				Console.Write("Found pattern "
							+ "at index " + (i - j));
				j = lps[j - 1];
			}

			// mismatch after j matches
			else if (i < N && pat[j] != txt[i]) {
				if (j != 0)
					j = lps[j - 1];
				else
					i = i + 1;
			}
		}
	}

	void computeLPSArray(string pat, int M, int[] lps)
	{

		int len = 0;
		int i = 1;
		lps[0] = 0;


		while (i < M) {
			if (pat[i] == pat[len]) {
				len++;
				lps[i] = len;
				i++;
			}
			else 
			{

				if (len != 0) {
					len = lps[len - 1];


				}
				else 
				{
					lps[i] = len;
					i++;
				}
			}
		}
	}


	public static void Main()
	{
		string txt = "ABABDABACDABABCABAB";
		string pat = "ABABCABAB";
		new GFG().KMPSearch(pat, txt);
	}
}
  • 파이썬
def kmp(text, pattern):
    n = len(text)
    m = len(pattern)
    lps = compute_lps(pattern)
    
    i, j = 0, 0
    while i < n:
        if text[i] == pattern[j]:
            i += 1
            j += 1
        if j == m:
            return i - j
        elif i < n and text[i] != pattern[j]:
            if j != 0:
                j = lps[j-1]
            else:
                i += 1
    return -1
    
def compute_lps(pattern):
    m = len(pattern)
    lps = [0] * m
    length = 0
    i = 1
    while i < m:
        if pattern[i] == pattern[length]:
            length += 1
            lps[i] = length
            i += 1
        else:
            if length != 0:
                length = lps[length-1]
            else:
                lps[i] = 0
                i += 1
    return lps

 

예제 문제

 

 

 

LIST
SMALL

넓우선탐색(Breadth-First Search, BFS)란?

  • 넓이 우선 탐색(Breadth-First Search, BFS)은 그래프 탐색 알고리즘 중 하나로, 루트 노드에서 시작해서 인접한 노드를 먼저 모두 탐색한 후에, 그 인접한 노드들을 시작점으로 다시 인접한 노드를 모두 방문하는 방법이다.

 

BFS의 원리

BFS는 큐(Queue) 자료구조를 이용하여 구현할 수 있다. 큐에 먼저 시작 노드를 넣고, 해당 노드와 인접한 모든 노드들을 큐에 추가한다. 그리고 큐에서 하나씩 노드를 빼서 그 노드와 인접한 노드들을 다시 큐에 추가한다. 이 과정을 큐가 빌 때까지 반복하면 된다. 큐를 이용하기 때문에 먼저 들어온 것이 먼저 처리되기 때문에 넓이 우선 탐색이라고 부른다.

 

BFS는 최단 경로 탐색 등에 자주 사용됩니다. 또한, 미로 찾기와 같은 문제에서도 사용할 수 있습니다. 단점으로는 BFS는 깊이 우선 탐색(DFS)에 비해 탐색하는 노드의 수가 많아지기 때문에, 탐색 속도가 느리다는 점이 있습니다.

 

넓이 우선 탐색(BFS)

  • C언어
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;

typedef struct tagNode
{
    ElementType Data;
} Node;

typedef struct tagCircularQueue
{
    int   Capacity;
    int   Front;
    int   Rear;

    Node* Nodes;
} CircularQueue;

void        CQ_CreateQueue(CircularQueue** Queue, int Capacity);
void        CQ_DestroyQueue(CircularQueue* Queue);
void        CQ_Enqueue(CircularQueue* Queue, ElementType Data);
ElementType CQ_Dequeue(CircularQueue* Queue);
int         CQ_GetSize(CircularQueue* Queue);
int         CQ_IsEmpty(CircularQueue* Queue);
int         CQ_IsFull(CircularQueue* Queue);
int         CQ_Front(CircularQueue* Queue);
int         CQ_Back(CircularQueue* Queue);


void  CQ_CreateQueue(CircularQueue** Queue, int Capacity)
{
    //  큐를 자유 저장소에 생성 
    (*Queue) = (CircularQueue*)malloc(sizeof(CircularQueue));

    //  입력된 Capacity+1 만큼의 노드를 자유 저장소에 생성 
    (*Queue)->Nodes = (Node*)malloc(sizeof(Node) * (Capacity + 1));

    (*Queue)->Capacity = Capacity;
    (*Queue)->Front = 0;
    (*Queue)->Rear = 0;
}

void CQ_DestroyQueue(CircularQueue* Queue)
{
    free(Queue->Nodes);
    free(Queue);
}

void CQ_Enqueue(CircularQueue* Queue, ElementType Data)
{
    int Position = 0;

    if (Queue->Rear == Queue->Capacity)
    {
        Position = Queue->Rear;
        Queue->Rear = 0;
    }
    else
        Position = Queue->Rear++;

    Queue->Nodes[Position].Data = Data;
}

ElementType CQ_Dequeue(CircularQueue* Queue)
{
    int Position = Queue->Front;

    if (Queue->Front == Queue->Capacity)
        Queue->Front = 0;
    else
        Queue->Front++;

    return Queue->Nodes[Position].Data;
}

int CQ_GetSize(CircularQueue* Queue)
{
    if (Queue->Front <= Queue->Rear)
        return Queue->Rear - Queue->Front;
    else
        return Queue->Rear + (Queue->Capacity - Queue->Front) + 1;
}

int CQ_IsEmpty(CircularQueue* Queue)
{
    return (Queue->Front == Queue->Rear);
}
int CQ_IsFull(CircularQueue* Queue)
{
    if (Queue->Front < Queue->Rear)
        return (Queue->Rear - Queue->Front) == Queue->Capacity;
    else
        return (Queue->Rear + 1) == Queue->Front;
}
int CQ_Front(CircularQueue* Queue)
{
    return Queue->Nodes[Queue->Front].Data;
}
int CQ_Back(CircularQueue* Queue)
{
    return Queue->Nodes[Queue->Rear - 1].Data;
}
int n = 5;
int visited[100];
int list[100][100];

void bfs(int v) {
    CircularQueue* queue = NULL;
    CQ_CreateQueue(&queue, 5);
    CQ_Enqueue(queue,v);
    visited[v] = true;
    printf("%d\n", v);
    while (CQ_IsEmpty(queue)) {
        int temp = CQ_Dequeue(queue);
        for (int i = n-1; i >= 0; i--) {
            if (list[temp][i] && !visited[i]) {
                CQ_Enqueue(queue, i);
                printf("%d\n", i);
            }
        }
    }
}
int main(void) {
    n = 5;
    list[0][1] = 1;
    list[0][2] = 1;
    list[1][0] = 1;
    list[1][2] = 1;
    list[1][3] = 1;
    list[1][4] = 1;
    list[2][0] = 1;
    list[2][1] = 1;
    list[3][1] = 1;
    list[4][1] = 1;

    //노드 방문
    for (int i = 0; i < n; i++) {
        if (!visited[i]) {
            bfs(i);
        }
    }
}
  • C#
using System;
using System.Collections.Generic;

namespace yongyong2
{
    internal class Program
    {
        static int N;
        static int[,] Map;
        static bool[] dfsbool;
        static bool[] bfsbool;

        static void Main(string[] args)
        {
            string[] input1 = Console.ReadLine().Split();
            N = int.Parse(input1[0]);
            int M = int.Parse(input1[1]);
            int V = int.Parse(input1[2]);

            Map = new int[N + 1, N + 1];
            bfsbool = new bool[N + 1];

            for (int i = 0; i < M; i++)
            {
                string[] input2 = Console.ReadLine().Split();
                int temps = int.Parse(input2[0]);
                int tempe = int.Parse(input2[1]);
                Map[temps, tempe] = 1;
                Map[tempe, temps] = 1;
            }


            BFS(N, V);
        }

        public static void BFS(int N, int V)
        {
            Queue<int> queue = new Queue<int>();
            queue.Enqueue(V);
            bfsbool[V] = true;
            Console.Write(V + " ");

            while (queue.Count > 0)
            {
                int temp = queue.Dequeue();

                for (int i = 1; i < N + 1; i++)
                {
                    if (Map[temp, i] == 1 && bfsbool[i] == false)
                    {
                        queue.Enqueue(i);
                        Console.Write(i + " ");
                        bfsbool[i] = true;
                    }
                }
            }
        }
    }
}

예제 문제

 

[C#]백준 1260번: DFS와 BFS

https://www.acmicpc.net/problem/1260 1260번: DFS와 BFS 첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는

yongyongyee.tistory.com

 

 

 

[C#]백준 24444번: 알고리즘 수업 - 넓이 우선 탐색 1

https://www.acmicpc.net/problem/24444 24444번: 알고리즘 수업 - 너비 우선 탐색 1 첫째 줄에 정점의 수 N (5 ≤ N ≤ 100,000), 간선의 수 M (1 ≤ M ≤ 200,000), 시작 정점 R (1 ≤ R ≤ N)이 주어진다. 다음 M개 줄에 간

yongyongyee.tistory.com

 

LIST

'공부 > 알고리즘' 카테고리의 다른 글

[알고리즘]KMP 알고리즘  (0) 2023.03.11
[알고리즘] 깊이 우선 탐색(DFS)  (0) 2023.03.05
[알고리즘] 에라토스테네스의 체  (0) 2023.02.02
SMALL

깊이우선탐색(Depth-First Search, DFS)란?

  • 깊이 우선 탐색(Depth-First Search, DFS)은 그래프를 탐색하는 알고리즘 중 하나이다. 이 알고리즘은 한 경로를 따라 최대한 깊이 내려가면서 그래프를 탐색하는 방식이다.

 

DFS의 원리

이 알고리즘은 스택(Stack) 자료구조를 사용하여 구현할 수 있습니다. 구체적으로는, 시작 노드를 스택에 넣고, 스택이 비어있지 않은 동안 아래의 과정을 반복합니다.

  1. 스택에서 노드를 꺼냅니다.
  2. 해당 노드가 방문한 적이 없다면, 방문 처리를 합니다.
  3. 해당 노드에서 인접한 노드들 중에서 방문하지 않은 노드가 있다면, 스택에 넣습니다.

위 과정을 반복하면서 모든 노드를 방문할 수 있다. 만약, 탐색 도중 목표 노드를 찾으면 탐색을 종료하거나, 모든 노드를 방문해도 목표 노드를 찾지 못하면 탐색을 종료한다.

 

 

DFS는 모든 경로를 탐색하기 때문에 최적의 해를 보장하지 않는다. 하지만, 그래프가 깊은 경우 BFS에 비해 적은 메모리를 사용하여 구현할 수 있기 때문에 유용하게 사용된다. 또한, DFS는 백트래킹(Backtracking)과 같은 알고리즘에서 사용되기도 한다.

 

깊이 우선 탐색(DFS)

  • C언어
#ifndef ARRAYSTACK_H
#define ARRAYSTACK_H
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
typedef int ElementType;

typedef struct tagNode
{
    ElementType Data;
} Node;

typedef struct tagArrayStack
{
    int   Capacity;
    int   Top;
    Node* Nodes;
} ArrayStack;

void        AS_CreateStack(ArrayStack** Stack, int Capacity);
void        AS_DestroyStack(ArrayStack* Stack);
void        AS_Push(ArrayStack* Stack, ElementType Data);
ElementType AS_Pop(ArrayStack* Stack);
ElementType AS_Top(ArrayStack* Stack);
int         AS_GetSize(ArrayStack* Stack);
int         AS_IsEmpty(ArrayStack* Stack);
int         AS_IsFull(ArrayStack* Stack);

#endif


void  AS_CreateStack(ArrayStack** Stack, int Capacity)
{
    //  스택을 자유 저장소에 생성 
    (*Stack) = (ArrayStack*)malloc(sizeof(ArrayStack));

    //  입력된 Capacity만큼의 노드를 자유 저장소에 생성 
    (*Stack)->Nodes = (Node*)malloc(sizeof(Node) * Capacity);

    //  Capacity 및 Top 초기화 
    (*Stack)->Capacity = Capacity;
    (*Stack)->Top = -1;
}

void AS_DestroyStack(ArrayStack* Stack)
{
    //  노드를 자유 저장소에서 해제 
    free(Stack->Nodes);

    //  스택을 자유 저장소에서 해제 
    free(Stack);
}

void AS_Push(ArrayStack* Stack, ElementType Data)
{
    Stack->Top++;
    Stack->Nodes[Stack->Top].Data = Data;
}

ElementType AS_Pop(ArrayStack* Stack)
{
    int Position = Stack->Top--;
    return Stack->Nodes[Position].Data;
}

ElementType AS_Top(ArrayStack* Stack)
{
    return Stack->Nodes[Stack->Top].Data;
}

int AS_GetSize(ArrayStack* Stack)
{
    return Stack->Top + 1;
}

int AS_IsEmpty(ArrayStack* Stack)
{
    return (Stack->Top == -1);
}
int AS_IsFull(ArrayStack* Stack)
{
    return (Stack->Top + 1 == Stack->Capacity);

}

int visited[100];
int list[100][100];
int n;

void dfs(int v) {
    ArrayStack* stack = NULL;
    AS_CreateStack(&stack, 5);
    AS_Push(stack, v);
    while (!AS_IsEmpty(stack)) {
        int temp = AS_Pop(stack);
        if (!visited[temp]) {
            visited[temp] = 1;
            printf("%d\n", temp);
            for (int i = n - 1; i >= 0; i--) {
                if (list[temp][i] && !visited[i]) {
                    AS_Push(stack, i);
                }
            }
        }
    }
}

int main(void)
{
    //그래프 입력
    n = 5;
    list[0][1] = 1;
    list[0][2] = 1;
    list[1][0] = 1;
    list[1][2] = 1;
    list[1][3] = 1;
    list[1][4] = 1;
    list[2][0] = 1;
    list[2][1] = 1;
    list[3][1] = 1;
    list[4][1] = 1;

    //노드 방문
    for (int i = 0; i < n; i++) {
        if (!visited[i]) {
            dfs(i);
        }
    }
}
  • C#
using System;
using System.Collections.Generic;

using System;
using System.Collections.Generic;

class DFS
{

    static int[,] list = new int[100, 100];
    static bool[] visited = new bool[100];
    static int n;

    static void dfs(int v)
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(v); // 시작 노드 스택에 삽입

        while (stack.Count > 0)
        {
            int temp = stack.Pop(); // 스택에서 노드 꺼내기
            if (!visited[temp]) // 해당 노드를 방문하지 않았다면
            {
                visited[temp] = true; // 방문 처리
                Console.Write(temp + "\n");

                for (int i = n - 1; i >= 0; i--) // 해당 노드의 인접 노드들을 역순으로 스택에 삽입
                {
                    if (list[temp, i] == 1 && !visited[i]) // 인접 노드 중 방문하지 않은 노드가 있다면
                    {
                        stack.Push(i);
                    }
                }
            }
        }
    }

    static void Main()
    {
        n = 5;
        list[0, 1] = 1;
        list[0, 2] = 1;
        list[1, 0] = 1;
        list[1, 2] = 1;
        list[1, 3] = 1;
        list[1, 4] = 1;
        list[2, 0] = 1;
        list[2, 1] = 1;
        list[3, 1] = 1;
        list[4, 1] = 1;


        for (int i = 0; i < n; i++)
        {
            if (!visited[i])
            {
                dfs(i);
            }
        }
    }
}

예제 문제

 

[C#]백준 1260번: DFS와 BFS

https://www.acmicpc.net/problem/1260 1260번: DFS와 BFS 첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는

yongyongyee.tistory.com

 

 

[C#]백준 24479번: 알고리즘 수업-깊이 우선 탐색 1

https://www.acmicpc.net/problem/24479 24479번: 알고리즘 수업 - 깊이 우선 탐색 1 첫째 줄에 정점의 수 N (5 ≤ N ≤ 100,000), 간선의 수 M (1 ≤ M ≤ 200,000), 시작 정점 R (1 ≤ R ≤ N)이 주어진다. 다음 M개 줄에 간

yongyongyee.tistory.com

 

LIST

'공부 > 알고리즘' 카테고리의 다른 글

[알고리즘]KMP 알고리즘  (0) 2023.03.11
[알고리즘] 넓이 우선 탐색(BFS)  (0) 2023.03.05
[알고리즘] 에라토스테네스의 체  (0) 2023.02.02
SMALL

에라토스테네스의 체란?

  • 소수를 판별하는 알고리즘.
  • 소수들을 대량으로 빠르게 구할 수 있는 알고리즘이다.

 

에라토스테네스의 체의 원리

단일 숫자의 소수 여부를 확인하는 가장 기초적인 방법은 소인수분해를 통해 약수의 개수를 확인하는 것이다.
에라토스테네스의 체는 1부터 N까지의 소수를 알고 싶을 때 사용하기 좋은 방법으로 N보다 작은 자연수 K의 몫과 나머지 중 하나는 N의 제곱근보다 작거나 같다는 성질을 이용하는 것이다.
N의 제곱근보다 작은 수의 배수만 모두 확인하면 N까지 소수가 아닌 수를 전부 지울 수 있게 된다. 

 

대량으로 소수를 한번에 판별해야 할 경우 '에라토스테네스의 체'를 이용한다.

  1. 배열을 생성하여 초기화한다.
  2. 2부터 시작해서 특정 수의 배수에 해당하는 수를 모두 지운다.
  3. 2부터 시작하여 남아있는 수를 모두 출력한다.

에라토스테네스의 체

  • C언어
#include <stdio.h>

int number = 100000;
int sieve[1000001];

void Sieve() {

    // 1. 배열을 생성하여 초기화한다.
    for(int i=2;i<=number;i++) {
        sieve[i] = i;
    }

    // 2. 2부터 시작해서 특정 수의 배수에 해당하는 수를 모두 지운다.
    // (지울 때 자기자신은 지우지 않고, 이미 지워진 수는 건너뛴다.)
    for(int i=2;i<=number;i++) {
        if(sieve[i]==0) continue; // 이미 지워진 수라면 건너뛰기

        // 이미 지워진 숫자가 아니라면, 그 배수부터 출발하여, 가능한 모든 숫자 지우기
        for(int j=2*i;j<=number; j+=i) {
            sieve[j] = 0;
        }
    }

    // 3. 2부터 시작하여 남아있는 수를 모두 출력한다.
    for(int i=2;i<=number;i++) {
        if(sieve[i]!=0) printf("%d ", sieve[i]);
    }
}

int main(void) {
    Sieve();
    return 0;
}
  • C#
internal class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();
            SIEVE(10000);
            void SIEVE(int num)
            {
                int[] sieve = new int[num + 1];
                for (int i = 2; i <= num; i++)
                {
                    sieve[i] = i;
                }
                for (int i = 2; i <= num; i++)
                {
                    if (sieve[i] == 0) continue;
                    for (int j = i + i; j <= num; j += i)
                    {
                        sieve[j] = 0;
                    }
                }
                for(int i = 2; i <= num; i++)
                {
                    if (sieve[i] != 0)
                    {
                        sb.Append(sieve[i]+" ");
                    }
                }
            }
            Console.WriteLine(sb.ToString());

        }
    }

예제 문제

 

[C언]백준 2960번: 에라토스테네스의 체

https://www.acmicpc.net/problem/2960 2960번: 에라토스테네스의 체 2, 4, 6, 8, 10, 3, 9, 5, 7 순서대로 지워진다. 7번째 지워진 수는 9이다. www.acmicpc.net 문제 문제풀이 에라토스테네스의 체를 알아야한다. 코드 1

yongyongyee.tistory.com

 

 

LIST

'공부 > 알고리즘' 카테고리의 다른 글

[알고리즘]KMP 알고리즘  (0) 2023.03.11
[알고리즘] 넓이 우선 탐색(BFS)  (0) 2023.03.05
[알고리즘] 깊이 우선 탐색(DFS)  (0) 2023.03.05

+ Recent posts