Skip to content

[JustHm] Week 01 Solutions #1133

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

Merged
merged 8 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions contains-duplicate/JustHm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Solution {
func containsDuplicate(_ nums: [Int]) -> Bool {
nums.count != Set(nums).count
}
}
20 changes: 20 additions & 0 deletions house-robber/JustHm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Solution {
func rob(_ nums: [Int]) -> Int {
guard nums.count != 1 else { return nums[0] }
guard nums.count != 2 else { return max(nums[0], nums[1]) }

// var dp = [nums[0], max(nums[0], nums[1])]
var twoStepPrev = nums[0]
var oneStepPrev = max(nums[0], nums[1])
Copy link
Contributor

Choose a reason for hiding this comment

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

DP 문제를 O(n) space로 푸신 다음 O(1) space로 최적화하셨군요! 사용하신 변수명이 직관적이어서 코드 이해가 잘 되는 것 같습니다 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

정말 꼼꼼히 리뷰해주셔서 감사합니다!
DP 풀이는 피보나치만 해봐서 그런지 너무 생소해서 기초부터 열심히 공부해봐야겠습니다.. 초보풀이지만 좋은점 짚어주셔서 감사합니다!

for i in 2..<nums.count {
Copy link
Contributor

Choose a reason for hiding this comment

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

저는 경계값에서 조건을 빠짐없이 판단하거나 배열의 인덱스를 정확하게 다루는 데에 서툴러서 twoStepPrevoneStepPrev를 모두 0으로 초기화해서 풀었습니다. JustHm님처럼 꼼꼼히 케이스를 따져보면서도 풀어봐야겠다는 생각이 드네요!

var maxNum = max(oneStepPrev, twoStepPrev + nums[i])
twoStepPrev = oneStepPrev
oneStepPrev = maxNum
// var maxNum = max(dp[i-1], dp[i-2] + nums[i])
// dp.append(maxNum)
}
// print(dp)
// return dp.max() ?? 0
return oneStepPrev
}
}
52 changes: 52 additions & 0 deletions longest-consecutive-sequence/JustHm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class Solution {
func longestConsecutive(_ nums: [Int]) -> Int {
guard !nums.isEmpty else { return 0 }
/*
중복 제거 후 소팅 후 배열로 만드는것은 N + NlogN + N 으로 예상된다..
그래서 정렬만 하고 로직에서 중복 숫자는 그냥 무시하게 만드는 방식으로 속도를 개선
문제에서 O(N)으로 작성하자 라는 제약아닌 제약이 있었는데, O(N)은 도저히 떠오르지 않는다.
*/
let nums = nums.sorted()//Array(Set(nums).sorted())
var answer = 1
var count = 1
for index in 0..<nums.count-1 {
if nums[index] - nums[index + 1] == -1 {
count += 1
}
else if nums[index] == nums[index + 1] { continue }
else {
answer = max(answer, count)
count = 1
}
}
return max(answer, count)
}
}
// MARK: time: O(n) 풀이
/*
몰랐던점 Set의 contains는 O(n) 아님, O(1)임 (내부적으로 Hash table로 구현되어있음)
하지만 풀이 제출해보니까 속도가 sort 한거보다 덜나옴.. 왜?
Set은 contains를 확인할때, 들어온 값을 hash로 변경후 검색, 버킷찾기, 충돌 검사 등을 거치기 때문에... O(1)은 맞는데 시간이 조금 걸린다.
그렇기에 set방식으로 O(n)에 짠거보다 sorted 내장함수를 이용한 O(nlogn)의 실제 실행시간이 더 빠른것.
*/
class AnotherSolution {
func longestConsecutive(_ nums: [Int]) -> Int {
var numSet = Set(nums)
var answer = 0

for num in numSet {
// num-1이 없으면 시작지점이니까 여기부터 +1 하면서 길이 확인
// num-1이 있으면 그냥 무시
if !numSet.contains(num-1) { //Set의 contains는 O(1)임!! (내부적으로 Hash table로 구현되어있기 때문)
var count = 1
var temp = num + 1
while numSet.contains(temp) {
count += 1
temp += 1
}
answer = max(answer, count)
}
}
return answer
}
}
44 changes: 44 additions & 0 deletions top-k-frequent-elements/JustHm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// MARK: 리뷰를 받고 시도해본 다른 풀이 (time: O(n), space O(n)
class Solution {
func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] {
// 빈도수 별로 Dictionary에 저장
var dict = [Int: Int]()
for num in nums {
dict[num, default: 0] += 1
}
// Bucket sort 사용, 크기는 nums 만큼, 빈도수가 nums 공간보다 클수는 없으니까
var bucket = Array(repeating: [Int](), count: nums.count + 1)
for (key, value) in dict {
// 빈도수를 인덱스로 key == num 을 저장함
// 배열로 한 이유는 빈도수가 같은게 있을 수 있으니까!
bucket[value].append(key)
}

// 결과 출력
var answer = [Int]()
// bucket의 뒤에서부터 탐색
for index in stride(from: nums.count, to: 0, by: -1) {
// 없으면 무시
guard !bucket[index].isEmpty else { continue }
// 버켓의 현재 인덱스에 nil이 아니면 하나씩 결과에 추가해줌.
for item in bucket[index] {
answer.append(item)
// k개 만큼 가져왔다면 바로 리턴
if answer.count == k { return answer }
}
}

return answer
}
}
// MARK: time: O(nlogn), space: O(n)
// n+nlogn+n
class Solution {
func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] {
var dict = [Int: Int]()
for num in nums {
dict[num, default: 0] += 1
}
return [Int](dict.sorted{$0.value > $1.value}.map{$0.key}[..<k])
}
}
12 changes: 12 additions & 0 deletions two-sum/JustHm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var dict = [Int: Int]()
for index in 0..<nums.count {
if let item = dict[nums[index]] {
return [item, index]
}
else { dict[target - nums[index]] = index }
}
return []
}
}