곱연산이 헷갈려서 만들었다.
calc([50, 30, 20]);
function calc(persents){
let value = 1;
let calcPersent = 1;
for(persent of persents){
calcPersent *= (1-(persent/100));
}
value -= calcPersent;
return value*100 + " %";
}
곱연산이 헷갈려서 만들었다.
calc([50, 30, 20]);
function calc(persents){
let value = 1;
let calcPersent = 1;
for(persent of persents){
calcPersent *= (1-(persent/100));
}
value -= calcPersent;
return value*100 + " %";
}
큐는 Stack과 달리 선입선출(FIFO; First-In First-Out) 의 순서로 제어됩니다. 리스트 속에 데이터들의 시작과 끝의 포인터가 존재합니다. 입력(enqueue)시, 리스트의 rear pointer에 추가되며 출력(dequeue)시, 리스트의 front pointer 부분을 꺼내게 됩니다.
목표: 배열과 양방향 연결 리스트 구현시, 연산 복잡도 확인
배열 - 출력시, 모든 개체의 위치를 옮기는 과정에서 O(n) 가 소요
양뱡향 연결 리스트 - 포인터만 변경하게 됨으로 O(1) 소요
dequeue 과정에서 발생한 front pointer 앞의 공간을 재사용하지 못하는 큐의 단점을 개선하여 리스트의 시작과 끝을 이음으로써 재사용 가능
목표: 환형큐의 enqueue, dequeue, peek 구조를 구현
범위가 제한된 배열을 환형으로 이어서 쓴다는점을 감안하여 배열의 끝과 처음을 연속적으로 사용
FIFO 의 특성을 가진 일반적인 큐와 달리 우선순위에 따라 enqueue나 , dequeue의 대상이 선택되는 방식.
목표: 양방향 리스트를 통해 enqueue할 때, 순차검색을 통해 일치하는 위치에 넣는 방식 사용, data의 값이 클수록 높은 우선순위.
enqueue => O(n), dequeue = O(1)
트리구조 사용시 더 유용하나 다음 과정에 진행, 퀵정렬과 비슷한 느낌일것으로 예상
트리의 각 노드를 정해진 순서로 방문하는 것, 순회 (traversal) 연산.
DFT (Depth First Traversal) vs DFS (Depth First Search)? link
- DFT는 DFS를 사용합니다.
- DFS가 연결된 그래프에 적용되는 알고리즘 인 반면, DFT는 일반적으로 연결이 끊어진 그래프에 적용되는 순회입니다.
- DFS는 DFT가 수행하는 동안 각각의 모든 노드를 방문 할 것이라고 보증하지 않았습니다.
하지만 같은것이라 보아도 크게 문제되지 않습니다. 두 용어 모두, 그래프 또는 트리 (모든 트리는 또한 그래프이기도 합니다) 를 대상으로 노드들을 방문하는 순서를 규정하는 방식을 뜻합니다.
근데 tree보단 root모양인데 왜 그렇게 굳어진걸까?
모든 노드의 자식노드; 차수가 2 이하인 트리구조
깊이 우선 순회(DFT; Depth First Traversal)
목표: 이진트리의 depth 값 계산하는 기능 구현
class Node:
# 초기화 & size()
def depth(self):
# 재귀적으로 호출하며 단말노드 부터 체크
l = self.left.depth() if self.left else 0
r = self.right.depth() if self.right else 0
# l 과 r 변수에 좌우 노드의 깊이값 저장
return (l if l > r else r) + 1
class BinaryTree:
# 초기화 & size()
def depth(self):
# 루트값 유무 확인
if self.root:
# root node 부터 depth 확인절차 진행
return self.root.depth()
else:
return 0
목표: 이진트리의 전위순회, 후위순회 연산 기능 구현
class Node:
# 초기화 & inorder()
def preorder(self):
traversal = []
traversal.append(self.data)
if self.left:
traversal += self.left.preorder()
if self.right:
traversal += self.right.preorder()
return traversal
def postorder(self):
traversal = []
if self.left:
traversal += self.left.postorder()
if self.right:
traversal += self.right.postorder()
traversal.append(self.data)
return traversal
class BinaryTree:
# 초기화 & inorder()
def preorder(self):
if self.root:
return self.root.preorder()
else:
return []
def postorder(self):
if self.root:
return self.root.postorder()
else:
return []
BFT는 트리 구조에서 낮은 level 중 왼쪽 노드부터 순회하게 됩니다. 이로써 DFT와 달리 재귀적으로 구현이 불가합니다. 하지만 Queue를 사용하여 다음에 방문할 노드를 enqueue 해두고 dequeue 하게되면 각각의 level별로 노드를 순회하게 됩니다.
목표: 넓이 우선 순회 기능을 구현
def bft(self):
traversal = []
queue = ArrayQueue()
# root 존재여부 확인
if self.root:
queue.enqueue(self.root)
# 하위 노드를 queue에 추가하며 노드의 값을 저장
while not queue.isEmpty():
node = queue.dequeue()
traversal.append(node.data)
if node.left:
queue.enqueue(node.left)
if node.right:
queue.enqueue(node.right)
return traversal
시간복잡도
- Search Operation - O(n)
- Insertion Operation - O(1)
- Deletion Operation - O(n)
퀵정렬의 알고리즘을 트리의 형태로 접근하는 방식으로 생각하면 될 것 같다.
목표: BST 에 insert 기능을 구현
def insert(self, key, data):
# 키 중복시 예외
if self.key is key:
raise KeyError('inserted key is duplicated')
# key의 비중 확인
if self.key > key:
# 하위노드 존재여부 대응
if self.left:
self.left.insert(key, data)
else:
self.left = Node(key, data)
elif self.key < key:
if self.right:
self.right.insert(key, data)
else:
self.right = Node(key, data)
return True
트리노드 삭제시 고려사항 참조
3번을 처리하며 1, 2의 과정 모두 처리가능
def remove(self, key):
node, parent = self.lookup(key)
if node:
nChildren = node.countChildren()
if nChildren is 0: #하위노드 0개
if parent:
if node.key is parent.left.key:
parent.left = None
else:
parent.right = None
else:
self.root = None
elif nChildren is 1: #하위노드 1개
childNode = None
if node.left:
childNode = node.left
else:
childNode = node.right
if parent:
if node.key is parent.left.key:
parent.left = childNode
else:
parent.right = childNode
else:
self.root = childNode
else: #하위노드 2개
parent = node
successor = node.right
while successor.left:
parent = successor
successor = successor.left
node.key = successor.key
node.data = successor.data
if successor.key is parent.left.key:
parent.left = successor.right
else:
parent.right = successor.right
return True
else:
return False
힙 (heap) 도 이진 트리의 한 종류이며 이진 힙 (binary heap) 이라고도 불립니다.
힙에는 최대 힙 (max heap) 과 최소 힙 (min heap) 이 있습니다. 최대 힙과 최소 힙은 데이터 원소의 순서 기준이 내림차순이냐 오름차순이냐만 달라지고 완전히 대칭이므로, 여기에서는 최대 힙을 기준으로 설명을 전개하겠습니다. 최대 힙은 세 가지의 성질을 유지하고 있는 이진 트리입니다. 그 세 가지 성질은:
완전이진트리의 제약조건으로 인해 log(n)
에 비례하는 실행시간을 가짐
배열을 이용해 이진트리 표현시 index 는
*노드 번호 n 기준
목표: 새로운 노드 추가
def insert(self, item):
self.data.append(item)
index = len(self.data)-1
while index > 1:
if(self.data[index] > self.data[index // 2]):
# 아래 방법으로도 손쉽게 값 교환을 할 수 있었다.
# self.data[index], self.data[index // 2] = self.data[index // 2], self.data[index]
self.data[index] = self.data[index // 2]
self.data[index // 2] = item
index = index // 2
else:
break
최대 힙에서의 삭제. logn
의 복잡도
최대/최소 힙의 응용
우선 순위 큐 (priority queue)
삽입(enqueue)시, 느슨한 정렬(=반정렬; 큰값이 상위, 작은값이 하위에 있음)을 이루고 있도록 함.O(logn)
의 복잡도
출력(dequeue)시, 최대값을 순서대로 추출.O(logn)
의 복잡도
힙 정렬 (heap sort)
정렬되지 않은 원소를 최대힙에 삽입, O(logn) X 힙이 빌때까지 삭제순으로 정렬, O(logn) = O(nlogn)
Jenkins
, Travis
등Subversion(SVN)
, Git
, GitLab
등Maven
, Gradle
, Ant
등Junit
, SonarQube
등 public static String solution(int[] numbers) {
String answer ="";
List<String> list = new ArrayList<>();
int length = numbers.length;
for(int i=0; i<length; i++){
list.add(Integer.toString(numbers[i]));
}
int size = list.size();
Collections.sort(list, new Comparator<String>(){
@Override
public int compare(String num1,String num2){
return (num2+num1).compareTo(num1+num2);
}
});
if(list.get(0).equals("0")){
return "0";
}
for(int i=0; i<size; i++){
answer = answer + list.get(i);
}
return answer;
}
public static String solution(int[] numbers) {
// int[0~9][0~n] 2차배열 생성
List<LinkedList<String>> numberGroup = new ArrayList<>();
for (int i = 0; i < 10; i++) {
numberGroup.add(new LinkedList<>());
}
// 맨앞자리 숫자값으로 분류하여 배열 삽입
for (int num : numbers) {
String temp = Integer.toString(num);
int numIndex = Integer.parseInt(temp.substring(0, 1));// 앞부분 때기
numberGroup.get(numIndex).add(temp);
}
// 배열 정렬
for (LinkedList<String> numberList : numberGroup) {
Collections.sort(numberList, Collections.reverseOrder());
}
// 문자열 병합
StringBuilder result = new StringBuilder();
for (int i = numberGroup.size() - 1; i >= 0; i--) {
System.out.println(numberGroup.get(i));
for (String number : numberGroup.get(i)) {
result.append(number);
}
}
return result.toString();
}
참조 - https://n1tjrgns.tistory.com/139public class Main {
public static void main(String[] args) {
// int[] answers = { 1, 2, 3, 4, 5 };
// int[] answers = { 1,3,2,4,2 };
int[] answers = { 3, 1, 1 };
// int[] answers = { 4, 4 };
for (int val : solution(numbers)) {
System.out.print(val + ",");
}
}
public static int[] solution(int[] answers) {
int persons[][] = { { 1, 2, 3, 4, 5 }, { 2, 1, 2, 3, 2, 4, 2, 5 }, { 3, 3, 1, 1, 2, 2, 4, 4, 5, 5 } };
int result[][] = new int[persons.length][2];
// 결과값 구조 초기화
for (int i = 0, len = result.length; i < len; i++) {
result[i][0] = i + 1;
result[i][1] = 0;
}
// 패턴대로 순환하며 일치 개수 체크
for (int i = 0, len = answers.length; i < len; i++) {
for (int j = 0; j < persons.length; j++) {
if (persons[j][i % persons[j].length] == answers[i])
result[j][1]++;
}
}
// 일치개수 기반하여 정렬
Arrays.sort(result, new Comparator<int[]>() {
@Override
public int compare(int[] back, int[] front) {
return front[1] - back[1];
}
});
// 출력할 길이 지정하여 반환값 설정
int length = result[0][1] == 0 ? result.length : 1;
int[] answer = new int[length];
for (int i = 0; i < length; i++) {
answer[i] = result[i][0];
}
return answer;
}
}
Set<Integer> lhs = new LinkedHashSet<Integer>();
public int solution(String numbers) {
makeCombination("", numbers);
return getPrimeCount(new LinkedList<Integer>(lhs));
}
public int getPrimeCount(LinkedList<Integer> numbers) {
for (int prime : new int[] { 2, 3, 5, 7 }) {
for (int i = 0; i < numbers.size(); i++) {
int number = numbers.get(i);
if (number < 2 || (number % prime == 0 && number != prime)) {
numbers.remove(i--);
}
}
}
return numbers.size();
}
public void makeCombination(String s, String number) {
if (number.length() == 0) {
if (!s.equals("")) {
lhs.add(Integer.parseInt(s));
}
} else {
for (int i = 0; i < number.length(); i++) {
makeCombination(s + number.charAt(i), number.substring(0, i) + number.substring(i + 1, number.length()));
}
for (int i = 0; i < number.length(); i++) {
makeCombination(s, number.substring(0, i) + number.substring(i + 1, number.length()));
}
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
// int[] numbers = { 3, 0, 6, 1, 5 };
// int[] numbers = { 0, 0, 0 };
int[] numbers = { 22, 42 };
System.out.println(solution(numbers));
}
public static int[] solution(int[] citations) {
int answer = 0;
//정렬위해 List 변환
List<Integer> list = Arrays.stream(citations).boxed().collect(Collectors.toList());
//정렬
Collections.sort(list, Collections.reverseOrder());
//X의 값이 H를 넘지않는 범위에서 순회
for(Integer citation : list) {
if (answer < citation) {
answer++;
} else {
break;
}
}
return answer;
}
}