Skip to content

Commit 70a4ead

Browse files
authored
Merge pull request #858 from Jeehay28/main
[Jeehay28] WEEK 05
2 parents dcbbef5 + 4d19c46 commit 70a4ead

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @param {number[]} prices
3+
* @return {number}
4+
*/
5+
6+
// TC : O(n)
7+
// SC : O(1)
8+
9+
var maxProfit = function (prices) {
10+
if (prices.length === 1) {
11+
return 0;
12+
}
13+
14+
// Two variables (profitMax and priceMin) are used to store the maximum profit and minimum price seen, which require O(1) space.
15+
let profitMax = 0;
16+
let priceMin = prices[0];
17+
18+
for (const price of prices) {
19+
const profit = price - priceMin;
20+
profitMax = Math.max(profit, profitMax);
21+
priceMin = Math.min(price, priceMin);
22+
}
23+
24+
return profitMax;
25+
};
26+
27+
// Why Constants Are Ignored in Big-O
28+
// In Big-O notation, O(2) is simplified to O(1) because constants are irrelevant in asymptotic analysis.
29+
// Big-O focuses on how resource usage scales with input size, not fixed values.
30+
31+
// Using 2 variables: O(1)
32+
// Using 10 variables: O(1)
33+
// Using 100 variables: O(1)
34+
35+
// What Space Complexity Looks Like for Larger Growth
36+
// O(n): Memory grows linearly with the input size (e.g., storing an array of n elements).
37+
// O(n^2): Memory grows quadratically (e.g., a 2D matrix with n*n elements).
38+
// 𝑂(log 𝑛): Memory grows logarithmically (e.g., recursive calls in binary search).
39+
// O(1): Fixed memory usage, regardless of input size (e.g., using a fixed number of variables).
40+
41+

group-anagrams/Jeehay28.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Guided approach
2+
// TC : O(n*k), where n is the number of strings, and k is the average length of each string.
3+
// SC : O(n*k)
4+
// overal time complexity improved : from O(n * klogk) to O(n * k)
5+
6+
/**
7+
* Time Complexity Breakdown:
8+
*
9+
* Step | Time Complexity | Explanation
10+
* --------------------------------------- | ------------------- | ----------------------------------------
11+
* Outer loop over strings (`for` loop) | O(n) | Iterate over each string in the input array `strs`.
12+
* Create key (`createKey`) | O(k) per string | For each string, count character frequencies, with k being the length of the string.
13+
* Map operations (`set` and `get`) | O(1) per string | Inserting and retrieving values from a Map.
14+
* Result array | O(n * k) | Storing grouped anagrams in the result array.
15+
*
16+
* Overall Time Complexity: | O(n * k) | Total time complexity considering all steps.
17+
*
18+
* Space Complexity Breakdown:
19+
*
20+
* Step | Space Complexity | Explanation
21+
* --------------------------------------- | ------------------- | -----------------------------------------
22+
* Map to store grouped anagrams | O(n * k) | Map stores n groups with each group having at most k characters.
23+
* Auxiliary space for `createKey` | O(1) | The frequency array used to count characters (constant size of 26).
24+
* Space for the result array | O(n * k) | Result array storing n groups of up to k elements.
25+
*
26+
* Overall Space Complexity: | O(n * k) | Total space complexity considering all storage.
27+
*/
28+
29+
/**
30+
* @param {string[]} strs
31+
* @return {string[][]}
32+
*/
33+
34+
var groupAnagrams = function (strs) {
35+
const createKey = (str) => {
36+
const arr = new Array(26).fill(0);
37+
38+
for (const ch of str) {
39+
const idx = ch.charCodeAt() - "a".charCodeAt();
40+
arr[idx] += 1;
41+
}
42+
43+
return arr.join("#");
44+
};
45+
46+
let map = new Map();
47+
48+
for (const str of strs) {
49+
const key = createKey(str);
50+
map.set(key, [...(map.get(key) || []), str]);
51+
}
52+
53+
return Array.from(map.values(map));
54+
};
55+
56+
// *My own approach
57+
58+
// Time Complexity
59+
// 1. Sorting Each String:
60+
// Sorting a string takes O(k*logk), where k is the length of the string.
61+
// Since we sort each string in the input array of size n, the total cost for sorting is O(n*klogk).
62+
63+
// 2. Hash Map Operations:
64+
// Inserting into the hash map is O(1) on average. Over n strings, the cost remains O(n).
65+
66+
// Overall Time Complexity:
67+
// O(n*klogk), where n is the number of strings and k is the average length of a string.
68+
69+
// /**
70+
// * @param {string[]} strs
71+
// * @return {string[][]}
72+
// */
73+
74+
// var groupAnagrams = function (strs) {
75+
// // helper function
76+
// const sorted = (str) => {
77+
// return str.split("").sort().join("");
78+
// };
79+
80+
// let obj = {};
81+
82+
// for (const str of strs) {
83+
// const key = sorted(str);
84+
// obj[key] = [...(obj[key] || []), str];
85+
// }
86+
87+
// return Object.values(obj);
88+
// };
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Space complexity: O(n * m), where n is the number of words and m is the average length of the words stored in the trie.
2+
var Trie = function () {
3+
this.root = {}; // Initialize the trie with a root node
4+
};
5+
6+
/**
7+
* @param {string} word
8+
* @return {void}
9+
*/
10+
11+
// Time Complexity: O(m), where m is the length of the word being inserted
12+
Trie.prototype.insert = function (word) {
13+
let currentNode = this.root;
14+
for (any of word) {
15+
// If the character doesn't exist, create a new node
16+
if (!currentNode[any]) {
17+
currentNode[any] = {};
18+
}
19+
currentNode = currentNode[any]; // Move to the next node
20+
}
21+
currentNode.end = true; // Mark the end of the word
22+
};
23+
24+
/**
25+
* @param {string} word
26+
* @return {boolean}
27+
*/
28+
// Time Complexity: O(m), where m is the length of the word being searched
29+
Trie.prototype.search = function (word) {
30+
let currentNode = this.root;
31+
for (any of word) {
32+
// If the character doesn't exist in the trie, return false
33+
if (!currentNode[any]) {
34+
return false;
35+
}
36+
currentNode = currentNode[any]; // Move to the next node
37+
}
38+
39+
return currentNode.end === true;
40+
};
41+
42+
/**
43+
* @param {string} prefix
44+
* @return {boolean}
45+
*/
46+
// Time Complexity: O(m), where m is the length of the prefix
47+
Trie.prototype.startsWith = function (prefix) {
48+
let currentNode = this.root;
49+
50+
for (any of prefix) {
51+
// If the character doesn't exist, return false
52+
if (!currentNode[any]) {
53+
return false;
54+
}
55+
currentNode = currentNode[any]; // Move to the next node
56+
}
57+
58+
return true; // Return true if the prefix exists
59+
};
60+
61+
/**
62+
* Your Trie object will be instantiated and called as such:
63+
* var obj = new Trie()
64+
* obj.insert(word)
65+
* var param_2 = obj.search(word)
66+
* var param_3 = obj.startsWith(prefix)
67+
*/
68+
69+

word-break/Jeehay28.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @param {string} s
3+
* @param {string[]} wordDict
4+
* @return {boolean}
5+
*/
6+
7+
// Time Complexity: O(n * w * m)
8+
// - n is the length of the string s.
9+
// - w is the number of words in the dictionary wordDict.
10+
// - m is the average length of words in wordDict.
11+
12+
// Space Complexity: O(n)
13+
// - The dp array of size n + 1 is the primary contributor to space usage, where n is the length of the string s.
14+
var wordBreak = function (s, wordDict) {
15+
dp = new Array(s.length + 1).fill(false);
16+
dp[0] = true;
17+
18+
// O(n)
19+
for (let i = 1; i <= s.length; i++) {
20+
// O(w)
21+
for (word of wordDict) {
22+
if (i >= word.length && s.slice(i - word.length, i) === word) {
23+
// s.slice(i - word.length, i), the slicing operation takes O(m), where m is the length of the word being checked
24+
dp[i] = dp[i - word.length];
25+
}
26+
27+
if (dp[i]) {
28+
break;
29+
}
30+
}
31+
}
32+
33+
return dp[s.length];
34+
};
35+
36+

0 commit comments

Comments
 (0)