Skip to content

Commit bc4bc43

Browse files
authored
Merge pull request #2101 from hongseoupyun/main
[hongseoupyun] WEEK 03 Solutions
2 parents efa218f + 2dff60a commit bc4bc43

File tree

5 files changed

+296
-1
lines changed

5 files changed

+296
-1
lines changed

climbing-stairs/hongseoupyun.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def climbStairs(self, n: int) -> int:
2020

2121
prev1 = 1
2222
prev2 = 2
23-
for i in range(n,n+1):
23+
for i in range(3,n+1):
2424
current = prev2 + prev1
2525
prev1 = prev2
2626
prev2 = current

combination-sum/hongseoupyun.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# // Input: candidates = [2,3,5], target = 8
2+
# // Output: [[2,2,2,2],[2,3,3],[3,5]]
3+
4+
# // DFS/backtracking should be used - Find possilbe combinations till the end and backtrack to previous step to find other combinations
5+
# // For example, if we have candidates [2,3,5] and target 8
6+
# // Start with empty combination [], target 8
7+
# // Add 2 -> [2], remaining 6
8+
# // Add 2 -> [2,2], remaining 4
9+
# // Add 2 -> [2,2,2], remaining 2
10+
# // Add 2 -> [2,2,2,2], remaining 0 (found a valid combination)
11+
# // Backtrack to [2,2,2,3], remaining -1 (remaining is negative, backtrack)
12+
# // Backtrack to [2,2,2,5], remaining -3 (remaining is negative, backtrack)
13+
# // Backtrack to [2,2,3], remaining 1 (dead end, backtrack)
14+
# // Backtrack to [2,2,5], remaining -3 (remaining is negative, backtrack)
15+
# // Backtrack to [2,3], remaining 3
16+
# // Add 3 -> [2,3,3], remaining 0 (found a valid combination)
17+
# // so on ..
18+
19+
# // When you dfs, always start from current index and allow reusing the same element or next index only to avoid duplicates / to get unique combination
20+
# // Hence, if we starts from 2, next dfs calls can start from index of 2 or index of 3, but not index of 5 directly
21+
# // Moreover, if we start from 3, next dfs calls can start from index of 3 or index of 5, but not index of 2 directly
22+
23+
# backtrack(8, [], 0)
24+
# │
25+
# ├─ i = 0 pick 2 → backtrack(6, [2], 0)
26+
# │ │
27+
# │ ├─ i = 0 pick 2 → backtrack(4, [2,2], 0)
28+
# │ │ │
29+
# │ │ ├─ i = 0 pick 2 → backtrack(2, [2,2,2], 0)
30+
# │ │ │ │
31+
# │ │ │ ├─ i = 0 pick 2 → backtrack(0, [2,2,2,2], 0) 🟢 success → return
32+
# │ │ │ │
33+
# │ │ │ ├─ i = 1 pick 3 → backtrack(-1, [2,2,2,3], 1) 🔴 → return
34+
# │ │ │ │
35+
# │ │ │ └─ i = 2 pick 5 → backtrack(-3, [2,2,2,5], 2) 🔴 → return
36+
# │ │ │
37+
# │ │ └─ loop end → pop → combination = [2,2]
38+
# │ │
39+
# │ ├─ i = 1 pick 3 → backtrack(1, [2,2,3], 1)
40+
# │ │ │
41+
# │ │ ├─ i = 1 pick 3 → backtrack(0, [2,2,3,3], 1) 🟢 success → return
42+
# │ │ │
43+
# │ │ └─ i = 2 pick 5 → backtrack(-4, [2,2,3,5], 2) 🔴 → return
44+
# │ │
45+
# │ ├─ loop end → pop → [2,2]
46+
# │ │
47+
# │ └─ i = 2 pick 5 → backtrack(-1, [2,2,5], 2) 🔴 → return
48+
# │
49+
# ├─ loop end → pop → [2]
50+
# │
51+
# ├─ i = 1 pick 3 → backtrack(3, [2,3], 1)
52+
# │ │
53+
# │ ├─ i = 1 pick 3 → backtrack(0, [2,3,3], 1) 🟢 success → return
54+
# │ │
55+
# │ └─ i = 2 pick 5 → backtrack(-2, [2,3,5], 2) 🔴 → return
56+
# │
57+
# ├─ loop end → pop → [2]
58+
# │
59+
# ├─ i = 2 pick 5 → backtrack(1, [2,5], 2)
60+
# │ │
61+
# │ └─ i = 2 pick 5 → backtrack(-4, [2,5,5], 2) 🔴 → return
62+
# │
63+
# └─ loop end → pop → []
64+
65+
66+
67+
68+
from typing import List
69+
70+
class Solution:
71+
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
72+
result: List[List[int]] = []
73+
74+
def backtrack(remaining: int, combination: List[int], start_index: int):
75+
# base cases
76+
if remaining == 0:
77+
# append a COPY of combination
78+
result.append(combination[:])
79+
return
80+
if remaining < 0:
81+
return
82+
83+
# try candidates from start_index onward
84+
for i in range(start_index, len(candidates)):
85+
current_number = candidates[i]
86+
# choose
87+
combination.append(current_number)
88+
# explore (i, not i+1, because we can reuse same element)
89+
backtrack(remaining - current_number, combination, i)
90+
# undo (backtrack)
91+
combination.pop()
92+
93+
# initial call
94+
backtrack(target, [], 0)
95+
return result

combination-sum/hongseoupyun.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Input: candidates = [2,3,5], target = 8
2+
// Output: [[2,2,2,2],[2,3,3],[3,5]]
3+
4+
// DFS/backtracking should be used - Find possilbe combinations till the end and backtrack to previous step to find other combinations
5+
// For example, if we have candidates [2,3,5] and target 8
6+
// Start with empty combination [], target 8
7+
// Add 2 -> [2], remaining 6
8+
// Add 2 -> [2,2], remaining 4
9+
// Add 2 -> [2,2,2], remaining 2
10+
// Add 2 -> [2,2,2,2], remaining 0 (found a valid combination)
11+
// Backtrack to [2,2,2,3], remaining -1 (remaining is negative, backtrack)
12+
// Backtrack to [2,2,2,5], remaining -3 (remaining is negative, backtrack)
13+
// Backtrack to [2,2,3], remaining 1 (dead end, backtrack)
14+
// Backtrack to [2,2,5], remaining -3 (remaining is negative, backtrack)
15+
// Backtrack to [2,3], remaining 3
16+
// Add 3 -> [2,3,3], remaining 0 (found a valid combination)
17+
// so on ..
18+
19+
// When you dfs, always start from current index and allow reusing the same element or next index only to avoid duplicates / to get unique combination
20+
// Hence, if we starts from 2, next dfs calls can start from index of 2 or index of 3, but not index of 5 directly
21+
// Moreover, if we start from 3, next dfs calls can start from index of 3 or index of 5, but not index of 2 directly
22+
23+
/*
24+
backtrack(8, [], 0)
25+
26+
├─ i = 0 pick 2 → backtrack(6, [2], 0)
27+
│ │
28+
│ ├─ i = 0 pick 2 → backtrack(4, [2,2], 0)
29+
│ │ │
30+
│ │ ├─ i = 0 pick 2 → backtrack(2, [2,2,2], 0)
31+
│ │ │ │
32+
│ │ │ ├─ i = 0 pick 2 → backtrack(0, [2,2,2,2], 0) 🟢 success → return
33+
│ │ │ │
34+
│ │ │ ├─ i = 1 pick 3 → backtrack(-1, [2,2,2,3], 1) 🔴 → return
35+
│ │ │ │
36+
│ │ │ └─ i = 2 pick 5 → backtrack(-3, [2,2,2,5], 2) 🔴 → return
37+
│ │ │
38+
│ │ └─ loop end → pop → combination = [2,2]
39+
│ │
40+
│ ├─ i = 1 pick 3 → backtrack(1, [2,2,3], 1)
41+
│ │ │
42+
│ │ ├─ i = 1 pick 3 → backtrack(0, [2,2,3,3], 1) 🟢 success → return
43+
│ │ │
44+
│ │ └─ i = 2 pick 5 → backtrack(-4, [2,2,3,5], 2) 🔴 → return
45+
│ │
46+
│ ├─ loop end → pop → [2,2]
47+
│ │
48+
│ └─ i = 2 pick 5 → backtrack(-1, [2,2,5], 2) 🔴 → return
49+
50+
├─ loop end → pop → [2]
51+
52+
├─ i = 1 pick 3 → backtrack(3, [2,3], 1)
53+
│ │
54+
│ ├─ i = 1 pick 3 → backtrack(0, [2,3,3], 1) 🟢 success → return
55+
│ │
56+
│ └─ i = 2 pick 5 → backtrack(-2, [2,3,5], 2) 🔴 → return
57+
58+
├─ loop end → pop → [2]
59+
60+
├─ i = 2 pick 5 → backtrack(1, [2,5], 2)
61+
│ │
62+
│ └─ i = 2 pick 5 → backtrack(-4, [2,5,5], 2) 🔴 → return
63+
64+
└─ loop end → pop → []
65+
*/
66+
67+
68+
function combinationSum(candidates: number[], target: number): number[][] {
69+
const result: number[][] = []
70+
71+
function backtrack(remaining: number, combination: number[], startindex: number) {
72+
// Remaining is target - sum of combination
73+
// Base Case1: If remaining is 0, we found a valid combination -> add that combinations to result
74+
if (remaining === 0) {
75+
result.push([...combination]);
76+
return;
77+
}
78+
79+
// Base Case2: If remaining is negative, no valid combination -> backtrack
80+
if (remaining < 0) {
81+
return;
82+
}
83+
84+
// Explore further by trying each candidate starting from startindex
85+
// candidates = [2,3,5], target = 8
86+
for (let i = startindex; i < candidates.length; i++) {
87+
// Choose the current number
88+
const currentNumber = candidates[i];
89+
// Add the current number to the combination
90+
combination.push(currentNumber);
91+
92+
// Explore further with updated remaining and current combination
93+
backtrack(remaining - currentNumber, combination, i);
94+
// Backtrack: remove the last added candidate to try next candidate
95+
combination.pop();
96+
}
97+
}
98+
backtrack(target, [], 0);
99+
return result;
100+
};

valid-palindrome/hongseoupyun.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
import re
3+
4+
class Solution:
5+
# Palindrome is a word, phrase, number, or other sequences of characters that reads the same forward and backward (ignoring non-alphanumeric characters - letters and number).
6+
# the solution should first filter out non-alphanumeric characters and convert the string to lowercase.
7+
# Then, it should check if the cleaned string is equal to its reverse.
8+
9+
# Time complexity = O(n), as it checks, replaces, converts to lowercase, and reverses all characters in the string
10+
# Space complexity = O(n), as it creates a new string with a maximum length equal to the original string
11+
def isPalindrome(self, s: str) -> bool:
12+
filtered_string = re.sub(r'[^a-zA-Z0-9]','',s).lower()
13+
reversed_string = filtered_string[::-1]
14+
return reversed_string == filtered_string
15+
16+
17+
# Using Two-pointer; It searches from given string directly so the Space complexity is O(n) - better method
18+
# By using two index, searchs and compares from start and end of the string like this -><-
19+
# Do this while start index is less than end index
20+
# Skip non-alphanumeric characters
21+
# If both pointer are in characters, then convert to lowercase and compare
22+
# If not equal, return false
23+
# If all characters are equal, return true
24+
25+
# Time complexity = O(n), as it checks and converts to lowercase all characters in the string
26+
# Space complexity = O(1), as it uses only a constant amount of extra space
27+
def isPalindromeTwoPointer(self, s: str) -> bool:
28+
left = 0
29+
right = len(s) - 1
30+
31+
while left < right:
32+
if not s[left].isalnum():
33+
left+=1
34+
continue
35+
if not s[right].isalnum():
36+
right-=1
37+
continue
38+
if s[left].lower() != s[right].lower():
39+
return False
40+
41+
left+=1
42+
right-=1
43+
44+
return True

valid-palindrome/hongseoupyun.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// # Palindrome is a word, phrase, number, or other sequences of characters that reads the same forward and backward (ignoring non-alphanumeric characters - letters and number).
2+
// # the solution should first filter out non-alphanumeric characters and convert the string to lowercase.
3+
// # Then, it should check if the cleaned string is equal to its reverse.
4+
5+
6+
// Time complexity = O(n), as it checks, replaces, converts to lowercase, and reverses all characters in the string
7+
// Space complexity = O(n), as it creates a new string with a maximum length equal to the original string
8+
function isPalindrome(s: string): boolean {
9+
let filteredString: string = s.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
10+
let reversed: string = filteredString.split("").reverse().join("")
11+
12+
if (filteredString === reversed) {
13+
return true
14+
} else {
15+
return false
16+
}
17+
};
18+
19+
//Palindrom example: "A man, a plan, a canal: Panama"
20+
21+
// Using Two-pointer; It searches from given string directly so the Space complexity is O(n) - better method
22+
// By using two index, searchs and compares from start and end of the string like this-><-
23+
// Do this while start index is less than end index
24+
// Skip non-alphanumeric characters
25+
// If both pointer are in characters, then convert to lowercase and compare
26+
// If not equal, return false
27+
// If all characters are equal, return true
28+
29+
// Time complexity = O(n), as it checks and converts to lowercase all characters in the string
30+
// Space complexity = O(1), as it uses only a constant amount of extra space
31+
function isPalindrome2(s: string): boolean {
32+
33+
let left: number = 0;
34+
let right: number = s.length - 1;
35+
36+
let isAlphaNum = (str: string): boolean => {
37+
return /^[a-zA-Z0-9]$/.test(str)
38+
}
39+
40+
while (left < right) {
41+
if (!isAlphaNum(s[left])) {
42+
left++
43+
continue
44+
}
45+
if (!isAlphaNum(s[right])) {
46+
right--
47+
continue
48+
}
49+
if (s[left].toLowerCase() !== s[right].toLowerCase()) {
50+
return false
51+
}
52+
left++
53+
right--
54+
}
55+
return true
56+
};

0 commit comments

Comments
 (0)