Skip to content

Commit 0858fdb

Browse files
committed
Add comments to explain the solution
1 parent 72a94d0 commit 0858fdb

File tree

8 files changed

+149
-6
lines changed

8 files changed

+149
-6
lines changed

src/LRUCache/LRUCache.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
#include <map>
2323
using namespace std;
2424

25+
// The idea here is quite simple:
26+
// 1) A Map to index the key. O(1) key search time-complexity.
27+
// 2) A List to sort the cache data by accessed time.
28+
//
29+
// Considering there are too many insert/delete opreations for the List,
30+
// The ouble linked list is the good data structure to performance it.
2531

2632
class Node {
2733
public:
@@ -32,6 +38,7 @@ class Node {
3238
//Node(int k, int v, Node* n=NULL, Node* p=NULL): key(k), value(v), next(n), prev(p) {}
3339
};
3440

41+
// the following double linked list seems a bit commplicated.
3542
class DoubleLinkedList {
3643

3744
private:
@@ -151,8 +158,11 @@ class DoubleLinkedList {
151158
class LRUCache{
152159

153160
private:
161+
//cacheList - store the date
154162
DoubleLinkedList cacheList;
163+
//cacheMap - index the date for searching
155164
map<int, Node*> cacheMap;
165+
//the max capcity of cache
156166
int capacity;
157167

158168
public:
@@ -164,6 +174,7 @@ class LRUCache{
164174
}
165175

166176
int get(int key) {
177+
// The accessed node must be up-to-time -- take to the front
167178
if (cacheMap.find(key) != cacheMap.end() ){
168179
cacheList.TakeToBegin(cacheMap[key]);
169180
return cacheMap[key]->value;
@@ -173,12 +184,15 @@ class LRUCache{
173184
}
174185

175186
void set(int key, int value) {
187+
// key found, update the data, and take to the front
176188
if (cacheMap.find(key) != cacheMap.end() ){
177189
Node *p = cacheMap[key];
178190
p->value = value;
179191
cacheList.TakeToBegin(cacheMap[key]);
180192
}else{
193+
// key not found, new a node to store data
181194
cacheMap[key] = cacheList.NewAtBegin(key, value);
195+
// if the capacity exceed, remove the last one.
182196
if( cacheList.Size() > capacity) {
183197
int key = cacheList.GetTailNode()->key;
184198
cacheMap.erase(key);

src/binaryTreePostorderTraversal/binaryTreePostorderTraversal.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ struct TreeNode {
3838
vector<int> postorderTraversal1(TreeNode *root);
3939
vector<int> postorderTraversal2(TreeNode *root);
4040

41+
42+
// We have two methods here.
43+
// 1) the first one acutally is pre-order but reversed the access order.
44+
// 2) the second one is the traditional one
45+
4146
vector<int> postorderTraversal(TreeNode *root) {
4247
if (random()%2){
4348
cout << "---method one---" << endl;
@@ -47,6 +52,7 @@ vector<int> postorderTraversal(TreeNode *root) {
4752
return postorderTraversal2(root);
4853
}
4954

55+
5056
vector<int> postorderTraversal1(TreeNode *root) {
5157
vector<int> v;
5258
vector<TreeNode*> stack;
@@ -56,6 +62,7 @@ vector<int> postorderTraversal1(TreeNode *root) {
5662
while (stack.size()>0){
5763
TreeNode *n = stack.back();
5864
stack.pop_back();
65+
//the tricks: reverse the access order.
5966
v.insert(v.begin(), n->val);
6067
if (n->left){
6168
stack.push_back(n->left);
@@ -67,6 +74,8 @@ vector<int> postorderTraversal1(TreeNode *root) {
6774
return v;
6875
}
6976

77+
// traditional and standard way.
78+
// using the stack to simulate the recursive function stack.
7079
vector<int> postorderTraversal2(TreeNode *root) {
7180
vector<int> v;
7281
vector<TreeNode*> stack;
@@ -75,13 +84,16 @@ vector<int> postorderTraversal2(TreeNode *root) {
7584
while(stack.size()>0 || node!=NULL){
7685

7786
if (node != NULL){
87+
// keep going the left
7888
stack.push_back(node);
7989
node = node->left;
8090
}else{
8191
TreeNode *n = stack.back();
92+
// left way is finsised, keep going to the right way
8293
if (n->right != NULL && lastVisitNode != n->right){
8394
node = n->right;
8495
}else{
96+
// both left and right has been accessed.
8597
stack.pop_back();
8698
v.push_back(n->val);
8799
lastVisitNode = n;

src/findMinimumInRotatedSortedArray/findMinimumInRotatedSortedArray.II.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ int findMin(vector<int> &num) {
6565
}
6666
}
6767

68+
// checking the edge case
6869
if (high == low) return num[low];
6970
return num[low] < num[high] ? num[low] : num[high];
7071

src/findMinimumInRotatedSortedArray/findMinimumInRotatedSortedArray.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,40 @@
2121
#include <vector>
2222
using namespace std;
2323

24+
/*
25+
* Obveriously, to search any sorted array, the binary search is the common sense.
26+
*
27+
* To solve this problem, the idea is same as the search in rotated sorted array.
28+
*/
2429
int findMin(vector<int> &num) {
2530

2631
int low=0, high=num.size()-1;
2732

2833
while(high-low>1){
2934
int mid = low + (high-low)/2;
35+
// Chek the array if it is non-rotated, then just return the first element.
3036
if (num[low] < num[mid] && num[mid] < num[high]){
31-
return num[low] < num[mid] ? num[low] : num[mid];
37+
return num[low];
3238
}
39+
40+
// The array is rotated
41+
// Spli it into two part, the minimal value must be the rotated part
42+
43+
// if the left part is rotated, warch the left part
3344
if (num[low] > num [mid]){
3445
high = mid;
3546
continue;
3647
}
48+
// if the right part is rotated, search the right part.
3749
if (num[mid] > num[high]){
3850
low = mid;
3951
continue;
4052
}
4153
}
42-
54+
// the array only has 1 element
4355
if (high == low) return num[low];
56+
57+
// the array has 2 elements
4458
return num[low] < num[high] ? num[low] : num[high];
4559

4660
}

src/maxPointsOnALine/maxPointsOnALine.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct Point {
2222
Point(int a, int b) : x(a), y(b) {}
2323
};
2424

25-
// O^2 solution
25+
// O(n^2) time complexity solution
2626
int maxPoints(vector<Point> &points) {
2727

2828
#define INT_MAX 2147483647
@@ -32,25 +32,39 @@ int maxPoints(vector<Point> &points) {
3232
if (points.size()<=2) return points.size();
3333

3434
int maxnum = 0;
35+
//using a map to find the same slope line
3536
map<double, int> slopeMap;
37+
38+
//The algorithm here is quite straight forward.
39+
// take each point in array to caculate with others
40+
//
41+
//Actually the algorithm here can be optimized.
42+
// there are many duplicated calculation.
43+
// considering two points A and B, (A,B) is same with (B,A), here re-calculated.
3644
for(int i=0; i<points.size(); i++) {
45+
//reset teh slope map.
3746
slopeMap.clear();
3847
slopeMap[INT_MIN] = 0;
3948
int samePointCnt = 1;
4049
for (int j=0; j<points.size(); j++) {
41-
if (i==j) continue;
50+
if (i==j) continue; //skip the same point
51+
//Caculate the slope of two points
4252
int delta_x = points[i].x - points[j].x;
4353
int delta_y = points[i].y - points[j].y;
54+
//Special case: two points are exactly at same place
4455
if (delta_y == 0 && delta_x == 0){
4556
samePointCnt++;
4657
continue;
4758
}
59+
//Special case: delta_x == 0
4860
double slope = INT_MAX;
4961
if (delta_x!=0) {
5062
slope = 1.0*delta_y / delta_x;
5163
}
64+
//Count the points is same line.
5265
slopeMap[slope]++;
5366
}
67+
//find the max number of points located at same line with points[i]
5468
map<double, int>::iterator it;
5569
for (it = slopeMap.begin(); it != slopeMap.end(); it++) {
5670
if (maxnum < it->second + samePointCnt) {

src/maximumProductSubarray/maximumProductSubarray.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,47 @@
1010
* For example, given the array [2,3,-2,4],
1111
* the contiguous subarray [2,3] has the largest product = 6.
1212
*
13+
* More examples:
14+
*
15+
* Input: arr[] = {6, -3, -10, 0, 2}
16+
* Output: 180 // The subarray is {6, -3, -10}
17+
*
18+
* Input: arr[] = {-1, -3, -10, 0, 60}
19+
* Output: 60 // The subarray is {60}
20+
*
21+
* Input: arr[] = {-2, -3, 0, -2, -40}
22+
* Output: 80 // The subarray is {-2, -40}
1323
*
1424
**********************************************************************************/
1525

1626
#include <iostream>
1727
#include <algorithm>
1828
using namespace std;
1929

30+
// The idea is similar with "Find the subarray wich has the largest sum"
31+
// (See: http://en.wikipedia.org/wiki/Maximum_subarray_problem)
32+
//
33+
// The only thing to note here is, maximum product can also be obtained by minimum (negative) product
34+
// ending with the previous element multiplied by this element. For example, in array {12, 2, -3, -5, -6, -2},
35+
// when we are at element -2, the maximum product is multiplication of, minimum product ending with -6 and -2.
36+
//
2037
int maxProduct(int A[], int n) {
2138

39+
// To remember the max/min product for previous position
40+
int maxPrev = A[0], minPrev = A[0];
41+
// To remember the max/min product for current position
2242
int maxHere = A[0], minHere = A[0];
43+
// Overall maximum product
2344
int maxProd = A[0];
24-
int maxPrev = A[0], minPrev = A[0];
2545

2646
for (int i=1; i<n; i++){
47+
//max( maxPrev * A[i], minPrev * A[i], A[i] )
2748
maxHere = max( max( maxPrev * A[i], minPrev * A[i] ), A[i] );
49+
//min( maxPrev * A[i], minPrev * A[i], A[i] )
2850
minHere = min( min( maxPrev * A[i], minPrev * A[i] ), A[i] );
51+
//Keep tracking the overall maximum product
2952
maxProd = max(maxHere, maxProd);
53+
//Shift the current max/min product to previous variables
3054
maxPrev = maxHere;
3155
minPrev = minHere;
3256
}
@@ -45,4 +69,7 @@ int main()
4569

4670
int b[] = {-1, -1};
4771
TEST(b);
72+
73+
int c[] = {-1, 0, -2};
74+
TEST(c);
4875
}

src/wordBreak/wordBreak.II.cpp

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,34 @@
2929
#include <map>
3030
using namespace std;
3131

32+
// ---------------
33+
// Recursive Way
34+
// ---------------
35+
// The recursive method is quite straight forward.
36+
//
37+
// 1) if a substring from 0 to i is a word, then take the rest substring to evaluate.
38+
// 2) during the recursion, keep tracking the result
39+
//
40+
// For example:
41+
//
42+
// s = "catsanddog",
43+
// dict = ["cat", "cats", "and", "sand", "dog"].
44+
//
45+
//
46+
// +---> sand / dog ---> dog
47+
// |
48+
// +-------> cat / sanddog
49+
// |
50+
// catsanddog
51+
// |
52+
// +------> cats / anddog
53+
// |
54+
// +----> and / dog ---> dog
55+
//
56+
//
57+
// However, the recursive could produce a lot duplicated calculation, we need use a cache to avoid.
58+
//
59+
3260
//To avoid time limit error, need to add cache
3361
vector<string> wordBreak(string s, set<string> &dict, map<string, vector<string> >& cache) {
3462

@@ -66,24 +94,52 @@ void wordBreak(string s, set<string> &dict, string str, vector<string>& result)
6694
for(int i=0; i<s.size(); i++){
6795
string w = s.substr(0,i+1);
6896

97+
// if the current substring is a word
6998
if (dict.find(w)!=dict.end()) {
7099
str = org_str;
71100
if (str.size()>0){
72101
str +=" ";
73102
}
74103
str = str + w;
75104

105+
// foud the solution, add it into the result
76106
if (i==s.size()-1){
77107
result.push_back(str);
78108
return;
79109
}
80110

111+
//recursively to solve the rest subarray
81112
wordBreak(s.substr(i+1, s.size()-i-1), dict, str, result);
82113
}
83114
}
84115
}
116+
//---------------------
117+
// Dynamic Programming
118+
//---------------------
119+
//
120+
// Define substring[i, j] is the sub string from i to j.
121+
//
122+
// (substring[i,j] == word) : result[i] = substring[i,j] + {result[j]}
123+
//
124+
// So, it's better to evaluate it backword.
125+
//
126+
// For example:
127+
//
128+
// s = "catsanddog",
129+
// dict = ["cat", "cats", "and", "sand", "dog"].
130+
//
131+
// 0 c "cat" -- word[0,2] + {result[3]} ==> "cat sand dog"
132+
// "cats" -- word[0,3] + {result[4]} ==> "cats and dog"
133+
// 1 a ""
134+
// 2 t ""
135+
// 3 s "sand" -- word[3,6] + {result[7]} ==> "sand dog"
136+
// 4 a "and" -- word[4,6] + {result[7]} ==> "and dog"
137+
// 5 n ""
138+
// 6 d ""
139+
// 7 d "dog"
140+
// 8 o ""
141+
// 9 g ""
85142

86-
//Dynamic Programming
87143
vector<string> wordBreak_dp(string s, set<string> &dict) {
88144
vector< vector<string> > result(s.size());
89145

src/wordBreak/wordBreak.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@ using namespace std;
2323

2424
bool wordBreak(string s, set<string> &dict) {
2525

26+
//using an array to mark subarray from 0 to i can be broken or not
2627
vector<bool> v(s.size(),false);
2728

2829
for(int i=0; i<s.size(); i++){
30+
//check the substring from 0 to i is int dict or not
2931
string w = s.substr(0,i+1);
3032
v[i] = (dict.find(w)!=dict.end());
3133

34+
//if it is, then use greedy algorithm
3235
if (v[i]) continue;
3336

37+
//if it is not, then break it to check
3438
for(int j=0; j<i; j++){
39+
//if the substring from 0 to j can be borken, then check the substring from j to i
3540
if (v[j]==true){
3641
w = s.substr(j+1, i-j);
3742
v[i] = (dict.find(w)!=dict.end());

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy