Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TONY] WEEK 01 solutions #299

Merged
merged 5 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions contains-duplicate/TonyKim9401.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Solution {
public boolean containsDuplicate(int[] nums) {
// HashSet O(n)
/*
Set<Integer> set = new HashSet();
for (int num : nums) set.add(num);
return set.size() != nums.length;
*/

// dupl value O(n log n)
Arrays.sort(nums);
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] == nums[i + 1]) return true;
}
return false;
DaleSeo marked this conversation as resolved.
Show resolved Hide resolved
}
}
18 changes: 18 additions & 0 deletions kth-smallest-element-in-a-bst/TonyKim9401.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Solution {
private List<Integer> nums = new ArrayList<>();
public int kthSmallest(TreeNode root, int k) {
visitTreeNode(root);
return nums.get(k-1);
}

public void visitTreeNode(TreeNode node) {
if (node == null) return;

// left < right
visitTreeNode(node.left);
nums.add(node.val);
visitTreeNode(node.right);
}
// time complexity: O(n), visit all nodes once
// space complexity: O(1), used an array list
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nums 리스트에 트리들의 값을 누적하면 최악의 경우에는 O(n)을 차지할 것 같습니다 ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다! 잘못 생각했네요ㅜ

}
21 changes: 21 additions & 0 deletions number-of-1-bits/TonyKim9401.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Solution {
public int hammingWeight(int n) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석으로 처리하신 while문으로 입력을 나누어 해결하는 방법의 시간복잡도는 O(log n)이 걸릴 것 같은데, Integer.bitCountO(1)이라고 봐야할까요??

  public static int bitCount(int i) {
      // HD, Figure 5-2
      i = i - ((i >>> 1) & 0x55555555);
      i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
      i = (i + (i >>> 4)) & 0x0f0f0f0f;
      i = i + (i >>> 8);
      i = i + (i >>> 16);
      return i & 0x3f;
  }

단순 연산으로 처리하고 있어서 O(log n)이라고 보기 힘들지 않을까 싶은데, 토니님은 어떻게 생각하시나요??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 주셔서 감사합니다!
확인해본 결과는 다음과 같습니다.

Integer.bitCount(n) : 시간 복잡도 O(1), 공간 복잡도 O(1)

  • Integer.bitCount의 경우 내부 함수가 O(1)의 시간 복잡도로 만들어져 있다고 합니다!

while 반복문: 시간 복잡도 O(log n), 공간 복잡도 O(1)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integer.bitCount의 경우 내부 함수가 O(1)의 시간 복잡도로 만들어져 있다고 합니다!

오 그렇군요 ㅎㅎ 확인해주셔서 감사합니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TonyKim9401 Integer.bitCount(n)의 시간 복잡도가 O(1)이라는 것에 대한 레퍼런스 좀 공유해주실 수 있으실까요? 내부적으로 도대체 어떤 알고리즘을 썼길래 입력 값에 무관하게 일정한 시간이 걸리는지 궁금합니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DaleSeo 위에 jdalma 님께서 올려주신 코드가 내부적으로 사용하는 코드이네요.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네네, 덕분에 저도 배웠네요! 이런 코드가 실제 코딩 테스트에서 유리할 지 불리할 지에 대해서 모임 때 같이 얘기해보면 좋을 것 같습니다.

/*
Time complexity: O(n)
Space complexity: O(1)
*/
return Integer.bitCount(n);

/*
Time complexity: O(n)
Space complexity: O(1)

int output = 0;
while (n > 0) {
if ((n & 1) == 1) output += 1;
n >>= 1;
}
return output;
*/
}
}
32 changes: 32 additions & 0 deletions top-k-frequent-elements/TonyKim9401.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Solution {
public int[] topKFrequent(int[] nums, int k) {

// declare hashmap
// key: each element, value: appered count
Map<Integer, Integer> map = new HashMap<>();

// if map contains the element, increase its value by one.
// else put the element and 1 for initializing
for (int num : nums) {
if (map.containsKey(num)) {
map.put(num, map.getOrDefault(num, 0) + 1);
} else {
map.put(num, 1);
}
}

// keyList only has key values of the hashmap
// using their value count sort keys by descending order
List<Integer> keyList = new ArrayList<>(map.keySet());
Collections.sort(keyList, (o1, o2) -> map.get(o2).compareTo(map.get(o1)));
Comment on lines +18 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분이 얼마나 시간이 걸릴지 분석을 한 번 해보시면 어떨까요? 그 분석을 바탕으로 좀 더 효율적인 알고리즘을 고민해보셔도 좋을 것 같습니다. 이미 문제를 다 푸셔서 시간이 좀 있으실 것 같아서 제안드립니다.

Copy link
Contributor Author

@TonyKim9401 TonyKim9401 Aug 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DaleSeo 이 부분은... GPT에 물어 본 결과였구요 ㅜ 답변 공유해드리는걸로 대체해도 괜찮을까요?

Integer.bitCount(n)의 시간 복잡도가 O(1)이라는 이유는 내부적으로 사용하는 알고리즘과 CPU의 하드웨어 명령어 덕분입니다. 이 함수는 주어진 정수 n의 이진 표현에서 1의 개수를 세는 작업을 수행합니다. 상세한 설명은 다음과 같습니다.

1. 내부 구현
Integer.bitCount(n) 메서드는 비트 연산을 기반으로 구현된 알고리즘을 사용하여 1의 개수를 셉니다. Java의 Integer 클래스는 하드웨어 수준에서 효율적인 비트 조작을 수행하는 메서드로 최적화되어 있습니다. 이는 비트 연산이 정수의 비트를 직접 다루기 때문에 매우 빠르게 실행됩니다.

Java에서 Integer.bitCount(n)는 하드웨어 명령어에 의존하거나, 하드웨어 명령어가 없는 경우 소프트웨어적으로 최적화된 알고리즘을 사용합니다. 이 알고리즘은 일정한 수의 연산 단계만을 수행하기 때문에 입력 크기에 관계없이 항상 일정한 시간 안에 결과를 도출할 수 있습니다.

2. 알고리즘
Integer.bitCount(n)는 일반적으로 "SWAR (SIMD Within A Register)" 알고리즘을 사용합니다. 이 알고리즘은 비트들을 그룹화하여 병렬 처리하고, 여러 비트의 개수를 동시에 세는 방식으로 동작합니다. 단계는 다음과 같습니다:

각 비트 쌍의 1의 개수를 셉니다.
각 4비트 그룹에서 1의 개수를 셉니다.
각 8비트 그룹에서 1의 개수를 셉니다.
이 과정을 계속해서 32비트 숫자 전체에서 1의 개수를 얻습니다.
이 과정은 고정된 수의 연산 단계(즉, 5~6단계)로 이루어져 있으며, 입력 정수 n의 크기에 관계없이 동일한 수의 연산이 수행됩니다. 따라서 시간 복잡도는 O(1)입니다.

3. 하드웨어 명령어
많은 현대 CPU는 비트 카운트를 위한 전용 명령어(예: x86 아키텍처의 POPCNT)를 가지고 있습니다. 이러한 명령어는 비트 카운트를 하드웨어 수준에서 처리하므로 매우 빠르게 실행됩니다. Java의 JIT(Just-In-Time) 컴파일러는 가능한 경우 이러한 하드웨어 명령어를 사용하도록 코드를 최적화할 수 있습니다.

이 명령어는 한 사이클 내에 연산을 완료하므로, 이 경우에도 O(1) 시간 복잡도를 유지할 수 있습니다.

4. 결론
Integer.bitCount(n)가 O(1) 시간 복잡도를 가지는 이유는 이 함수가 입력 크기와 무관하게 일정한 수의 연산만을 수행하는 고정된 알고리즘을 사용하기 때문입니다. 이 알고리즘은 비트 연산을 사용하여 빠르게 1의 개수를 셀 수 있도록 최적화되어 있으며, 현대 CPU의 하드웨어 명령어를 활용할 수 있어 더 효율적인 처리가 가능합니다.

Copy link
Contributor

@DaleSeo DaleSeo Aug 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 위 내용은 #299 (comment) 에 대한 답변이 아닐까요? 제가 여쭤본 내용에 대한 답변이 아닌 것 같습니다.



int[] output = new int[k];
int idx = 0;

// retreive keys k times and set output
while (idx < k) output[idx] = keyList.get(idx++);

return output;
}
}