Skip to content

Latest commit

 

History

History
320 lines (264 loc) · 8.76 KB

알고리즘 모아보기.md

File metadata and controls

320 lines (264 loc) · 8.76 KB

알고리즘 모아보기

최대공약수 GCD(Grateast Common Divisor)

//	재귀
public long gcd(int w, int h) {
  if (h == 0) {
    return w;
  }
  return gcd(h, w % h);
}

// 반복문
public static long gcd2(int w, int h) {
  int n;

  if (w < h) {
    int temp = w;
    w=h;
    h = temp;
  }

  while (h != 0) {
    n = w % h;
    w=h;
    h = n;
  }

  return w;
}

최소공배수 LCM(Least Common Multiple)

(각 숫자 / 최대공약수) * 최대공약수 // 두 개만 비교할 때에 두 수의 곱 / 최대공약수가 최소공배수가 됨


순열과 조합(Permutation and Conbination)

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9};
        int[] combArr = new int[3];
        boolean[] visit = new boolean[5];
//        combination(visit, 5, 3, 0, arr);
        permutation(visit, 5, 3, arr, combArr, 0);
    }

    private static void combination(boolean[] visit, int totalCount, int leftPick, int start, int[] givenArr) {
        if (leftPick == 0) {
            for (int i = 0; i < visit.length; i++) {
                if(visit[i]) System.out.print(givenArr[i]+" ");
            }
            System.out.println();
            return;
        }
        for (int i = start; i < totalCount; i++) {
            visit[i] = true;
            combination(visit, totalCount, leftPick - 1, i + 1, givenArr);
            visit[i] = false;
        }
    }

    private static void permutation(boolean[] visit, int totalCount, int pick, int[] givenArr, int[] combArr, int index) {
        if (pick == index) {
            for (int i = 0; i < 3; i++) {
                System.out.print(combArr[i]+" ");
            }
            System.out.println();
            return;
        }

        for (int i = 0; i < totalCount; i++) {
            if(visit[i]) continue;
            combArr[index] = givenArr[i];
            visit[i] = true;
            permutation(visit, totalCount, pick, givenArr, combArr, index + 1);
            visit[i] = false;
        }
    }

LowerBound, UpperBound

LowerBound : 찾고자 하는 값 이상이 처음 발견되는 위치를 찾기 위한 알고리즘
UpperBound : 찾고자 하는 값 초과 값이 처음 발견되는 위치를 찾기 위한 알고리즘

// lowerBound
    private static int lowerBound(List<Integer> value, int score) {
        int left = 0;
        int right = value.size();		//해당 list의 가장 큰 값 보다 큰 값이 들어올 수 있으니 size()로 시작
        while (right > left) {
            int mid = (left + right) / 2;
            if (value.get(mid) < score) {
                left = mid + 1;
                continue;
            }
            right = mid;
        }
        return right;
    }

//upperBound
    private static int upperBound(List<Integer> value, int score) {
        int left = 0;
        int right = value.size();
        while (right > left) {
            int mid = (left + right) / 2;
            if (value.get(mid) <= score) {	//lowerBound와 이곳이 다름. lowerBound는 같아도 시작점을 찾아야 하니 좌측으로 이동, upperBound는 같으면 그 초과값을 찾아야하니 우측으로 이동이라고 생각하면 된다.
                left = mid + 1;
                continue;
            }
            right = mid;
        }
        return right;
    }

플로이드 와샬(Floyd-Warshall)

모든 정점에서 다른 모든 정점까지의 최단 거리를 구하는 알고리즘

        for (int i = 1; i < length; i++) {
            for (int j = 1; j < length; j++) {
                for (int k = 1; k < length; k++) {
                    if (adjDistance[j][i] == 1 && adjDistance[i][k] == 1) {
                        adjDistance[j][k] = 1;
                    }
                }
            }
        }

위의 코드는 프로그래머스 순위 문제의 코드이다. 형식은 같다.
i -> j, j -> k 일 때에 i -> k 가 가능하다가 기본전제이다. 유의할 점은 가운데 끼는 정점이 기준이 되어야 한다.
따라서 위의 코드를 보면 알 수 있듯이 첫 번째 for문의 변수인 i가 중간에 끼는 점인 것을 알 수 있다.
위의 조건식인 if (adjDistance[j][i] == 1 && adjDistance[i][k] == 1) 을 문제에 맞게 변환해서 사용하면 된다.


프림(Prim), 크루스칼(Kruskal)

프림 알고리즘과 크루스칼 알고리즘은 MST(Minimum Spanning Tree)를 구하는 알고리즘이다.
프림은 정점을 기준으로 삼고, 크루스칼은 간선을 기준으로 삼는다.

프림 : O(n^2)
크루스칼 : O(e log(2e))

간선이 많다면 프림, 그렇지 않다면 크루스칼을 사용하면 된다.

프림 알고리즘

    public static class Edge implements Comparable<Edge> {
        public int to;
        public int weight;

        public Edge(int to, int weight) {
            this.to = to;
            this.weight = weight;
        }

        @Override
        public int compareTo(Edge o) {
            return this.weight - o.weight;
        }
    }

		public static int solution(int n, int[][] costs) {
        int[][] adj = new int[n][n];
        for (int[] cost : costs) {
            adj[cost[0]][cost[1]] = cost[2];
            adj[cost[1]][cost[0]] = cost[2];
        }

        return prim(n, adj);
    }

    private static int prim(int n, int[][] adj) {
        Queue<Integer> edgeQue = new LinkedList<>();
        PriorityQueue<Edge> pq = new PriorityQueue<>();
        boolean[] visit = new boolean[n];
        edgeQue.add(0);

        int totalWeight = 0;

        while (!edgeQue.isEmpty()) {
            Integer currentEdge = edgeQue.poll();
            visit[currentEdge] = true;
            for (int i = 0; i < n; i++) {
                if (adj[currentEdge][i] != 0 && !visit[i]) {
                    pq.add(new Edge(i, adj[currentEdge][i]));
                }
            }
            while (!pq.isEmpty()) {
                Edge edge = pq.poll();
                if (!visit[edge.to]) {
                    edgeQue.add(edge.to);
                    totalWeight += edge.weight;
                    break;
                }
            }
        }

        return totalWeight;
    }

//Queue를 사용하지 않고 풀 수도 있다.  
private static int prim(int n, int[][] adj) {
    PriorityQueue<Edge> pq = new PriorityQueue<>();
    boolean[] visit = new boolean[n];
    int currentEdge = 0;

    int totalWeight = 0;

    while (true) {
        visit[currentEdge] = true;
        for (int i = 0; i < n; i++) {
            if (adj[currentEdge][i] != 0 && !visit[i]) {
                pq.add(new Edge(i, adj[currentEdge][i]));
            }
        }
			 currentEdge = -1;
       while (!pq.isEmpty()) {
            Edge edge = pq.poll();
            if (!visit[edge.to]) {
                totalWeight += edge.weight;
                currentEdge = edge.to;
                break;
            }
        }
        if (currentEdge == -1) {
            break;
        }
    }

    return totalWeight;
}

크루스칼 알고리즘
싸이클을 확인하기 위해서 유니온 파인드를 이용한다.

    public static class Edge implements Comparable<Edge> {
        public int from;
        public int to;
        public int weight;

        public Edge(int from, int to, int weight) {
            this.from = from;
            this.to = to;
            this.weight = weight;
        }

        @Override
        public int compareTo(Edge o) {
            return this.weight - o.weight;
        }
    }

    public static int solution(int n, int[][] costs) {
        int totalWeight = 0;
        int[] parent = new int[n];
        List<Edge> edges = new ArrayList<>();
        Arrays.fill(parent, -1);

        for (int[] cost : costs) {
            edges.add(new Edge(cost[0], cost[1], cost[2]));
        }
        Collections.sort(edges);

        for (Edge edge : edges) {
            if (isCycle(edge.to, edge.from, parent)) {
                continue;
            }
            totalWeight += edge.weight;
            union(edge.to, edge.from, parent);
        }

        return totalWeight;
    }

    private static void union(int a, int b, int[] parent) {
        int aRoot = find(a, parent);
        int bRoot = find(b, parent);
        if (aRoot == bRoot) {
            return;
        }
        if (aRoot < bRoot) {
            parent[bRoot] += parent[aRoot];
            parent[aRoot] = bRoot;
            return;
        }
        parent[aRoot] += parent[bRoot];
        parent[bRoot] = aRoot;
    }

    private static boolean isCycle(int to, int from, int[] parent) {
        return find(to, parent) == find(from, parent);
    }

    private static int find(int node, int[] parent) {
        if (parent[node] < 0) {
            return node;
        }
        return parent[node] = find(parent[node], parent);
    }