Skip to content

[shinsj4653] Week 02 Solutions #1228

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 7 commits into from
Apr 12, 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
115 changes: 115 additions & 0 deletions 3sum/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""
Inputs: 정수 배열 nums

Outputs: triplet 모음 배열 (중복 요소 X)

Constraints: 3 < = nums.length <= 3 * 10^3
-10^5 <= nums[i] <= 10^5

Time Complexity:

각 수들의 위치 다르면서, 합이 0이 되는 조합들의 모음 결과
n^3 은 안됨

하지만 가능한 모든 조합 구하기를 효율화 시키면 될듯?

x 0 1 2 3 4 5
0 [_,-1,0,1,-2,-5]
1 [_,_,1,2,-1,-4]
2 [_,_,_,
3
4
5

n^2



0 [1 2]
0 [1 3]
0 [1 4]
0 [1 5]

0 1 [2 3]
0 1 [2 4]
0 1 [2 5]

0 1 2[3 4]
0 1 2[3 5]

0 1 2 3 [4 5]

우선 대괄호 안 두 수 합 사전 만들고,
keys() 순회하며,
key = a, b -> a보다 작은 수 for문 돌며 합 구하기?
-> 그럼 시간복잡도 : O(n^3 보다 살짝 작은??)

하지만 이 풀이로는 중복 후보가 나옴..


Space Complexity: O(n^2)

대괄호 내 두 수 조합 만큼의 크기가 사전 크기

# 1차 제출 코드

from collections import defaultdict

class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
v = defaultdict(int)
ret = []
memo = set()

for i in range(1, n):
for j in range(i + 1, n):
v[(i, j)] = nums[i] + nums[j]

print(v)
for key in v.keys():
a, b = key
print('key: a, b', a, b)

for i in range(a):
if nums[i] + v[key] == 0 and \
not (nums[i] in memo and nums[a] in memo and nums[b] in memo):
print('sum zero!')
memo.add(nums[i])
memo.add(nums[a])
memo.add(nums[b])
ret.append([nums[i], nums[a], nums[b]])



return ret

테스트 케이스만 정답..
nums =
[-1,0,1,2,-1,-4,-2,-3,3,0,4] 인 경우는 오답

[회고]
완탐, dp로 해봐도 안 풀리면 투 포인터 생각해보기!
"""

class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
tuples = set()
nums.sort()

for i in range(len(nums) - 2):
left, right = i + 1, len(nums) - 1

while left < right:
three_sum = nums[i] + nums[left] + nums[right]
if three_sum < 0:
left += 1
elif three_sum > 0:
right -= 1
else :
tuples.add((nums[i], nums[left], nums[right]))
left += 1
right -= 1

return list(tuples)

104 changes: 104 additions & 0 deletions climbing-stairs/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""
계단 오르기
맨 꼭대기 가는데 n steps만큼 걸림

매번 올라가는데 1 or 2 계단 오르기 가능!

Inputs: n

Outputs: how many distinct ways to get to the top?

Constraints: 1 <= n <= 45

Time Complexity: O(2^n)

계단 오르는 방법 중, 중복되지 않는 모든 가지 수 구하기
우선 완탐으로 해보고, 그 다음 최적부분구조 할 수 있는지 체크

n = 2

1 1 -> dp[1]
2 0 -> dp

2 dp(n - 2) + dp(n - 1) + 1

n = 3
2 1
1 1 1 => dp[2] 값

1 2 => 여기선 dp[2] 로 가면 안됨!

1 2
1 1 1 => dp[2] 값

2 1 => 이건 dp[1] 값


n = 4
1 3 => dp[3]
2 2 => dp[2]

n = 5
2 2 1
2 1 2
1 2 2

n = 6

5 1
4 2

n = 7

6 1
5 4
4 3

특정 수를 구성하는 1과 2의 배열 가짓수들이 정해져있음!!

한 호출마다 뻗어지는 가짓수, 즉 호출수를 모르겠어서 시간복잡도 모르겠음

점화식을 어떻게 세우지?

3
1 2

기저조건또 헷갈... n 3 // 2 + 1

하지만, 도식화해보니
결국 dp(n) = dp(n - 1) + dp(n - 2)

1 2
1 1 1 => dp[2] 값

2 1 => 이건 dp[1] 값

Space Complexity: O(n)
dp 배열 n만큼의 크기 지님

"""


class Solution:
def climbStairs(self, n: int) -> int:

if n == 1:
return 1

dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1

def climb(n):

if dp[n]:
return dp[n]

else:
dp[n] += climb(n - 1) + climb(n - 2)
return dp[n]

return climb(n)

# sol = Solution()
# sol.climbStairs(3)
71 changes: 71 additions & 0 deletions product-of-array-except-self/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""
Inputs: 정수형 배열 nums

Outputs: 정수형 배열 answer

Constraints: 2 <= nums.length <= 10^5
-30 <= nums[i] <= 30
The input is generated such that answer[i] is guaranteed to fit in a 32-bit integer.

Time Complexity: 반드시 o(n)

answer의 각 원소는 본인을 제외한 나머지 원소들 곱한 결과

나눗셈 연산도 불가능
사전?
1 2 3 4
2 4 6 8
6 12 18 24
24 48 72 96

dict[0] :
dict[1] :
dict[2] :
dict[3] :

스택?? push, pop 하는데 o(1) 걸림

(1,0) (2,1) (3,2) (4,3)

스택에서 뺀 다음, 다시 넣으면 while st에 갇히지 않나?

# 풀이 본 이후

nums 1 2 3 4

1 1 1 1

1 1 2 6 : 기준 idx 전까지의 곱

24 12 4 1 : 기준 idx 후까지의 곱

=> 더 개선된 풀이: 누적곱을 덮어씌우는 방법

6
24 12 8 6

24


Space Complexity: O(1)
product 배열에 곱 결과를 덮어씌워도 무방

"""


class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:

products = [1 for _ in range(len(nums))]

before = 1
for i in range(len(nums) - 1):
before *= nums[i]
products[i + 1] *= before

after = 1
for i in range(len(nums) - 1, 0, -1):
after *= nums[i]
products[i - 1] *= after

return products
75 changes: 75 additions & 0 deletions valid-anagram/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""
Inputs: two strings : s, t

Outputs: t 가 s의 anagram인지에 대한 여부

Constraints:

1 <= s.length, t.length <= 5 * 10^4
s and t consist of lowercase English letters.

Time Complexity: O(n)

각 문자들의 등장 횟수만 같으면 되지 않나?

s의 Counter 생성
t의 Counter 생성

t Counter의 keys() 돌면서,
해당 값이 s Counter 배열 key에 있는지, 그리고 그 key의 value값이 서로 같은지 체크

Space Complexity: O(n)

"""

# 첫 코드

from collections import defaultdict


class Solution:
def isAnagram(self, s: str, t: str) -> bool:
s_dict, t_dict = defaultdict(int), defaultdict(int)

for ch in s:
s_dict[ch] += 1

for ch in t:
t_dict[ch] += 1

for key in t_dict.keys():
if key not in t_dict or t_dict[key] != s_dict[key]:
return False

return True

# 반례 발생

# s = "ab", t = "a"
# 어느 한 문자열을 기준으로 세면 안되는 것 같다
# 두 count 사전을 모두 돌아야할듯. t keys()를 기준으로만 돌면 true가 나와버림. 답은 false인데


from collections import defaultdict


class Solution:
def isAnagram(self, s: str, t: str) -> bool:
s_dict, t_dict = defaultdict(int), defaultdict(int)

for ch in s:
s_dict[ch] += 1

for ch in t:
t_dict[ch] += 1

for key in t_dict.keys():
if key not in s_dict or t_dict[key] != s_dict[key]:
return False

for key in s_dict.keys():
if key not in t_dict or t_dict[key] != s_dict[key]:
return False

return True

Loading