Skip to content

Commit b9660c2

Browse files
authoredJul 2, 2018
Merge branch 'master' into master
2 parents f97738c + e3b482c commit b9660c2

File tree

7 files changed

+474
-0
lines changed

7 files changed

+474
-0
lines changed
 

‎README.md

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ the data.
3838
* `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
3939
* `A` [Graph](src/data-structures/graph) (both directed and undirected)
4040
* `A` [Disjoint Set](src/data-structures/disjoint-set)
41+
* `A` [Bloom Filter](src/data-structures/bloom-filter)
4142

4243
## Algorithms
4344

@@ -70,6 +71,7 @@ a set of rules that precisely define a sequence of operations.
7071
* `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)
7172
* `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones
7273
* `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - "Brute Force" and "Dynamic Programming" (Kadane's) versions
74+
* `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum
7375
* **Strings**
7476
* `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
7577
* `B` [Hamming Distance](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
@@ -160,6 +162,7 @@ different path of finding a solution. Normally the DFS traversal of state-space
160162
* `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
161163
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
162164
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
165+
* `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum
163166
* **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking
164167
search, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of
165168
a least-cost solution to the problem, in order to discard partial solutions with costs larger than the
@@ -233,6 +236,7 @@ Below is the list of some of the most used Big O notations and their performance
233236
| **B-Tree** | log(n) | log(n) | log(n) | log(n) | |
234237
| **Red-Black Tree** | log(n) | log(n) | log(n) | log(n) | |
235238
| **AVL Tree** | log(n) | log(n) | log(n) | log(n) | |
239+
| **Bloom Filter** | - | 1 | 1 | - | False positives are possible while searching |
236240

237241
### Array Sorting Algorithms Complexity
238242

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Combination Sum Problem
2+
3+
Given a **set** of candidate numbers (`candidates`) **(without duplicates)** and
4+
a target number (`target`), find all unique combinations in `candidates` where
5+
the candidate numbers sums to `target`.
6+
7+
The **same** repeated number may be chosen from `candidates` unlimited number
8+
of times.
9+
10+
**Note:**
11+
12+
- All numbers (including `target`) will be positive integers.
13+
- The solution set must not contain duplicate combinations.
14+
15+
## Examples
16+
17+
```
18+
Input: candidates = [2,3,6,7], target = 7,
19+
20+
A solution set is:
21+
[
22+
[7],
23+
[2,2,3]
24+
]
25+
```
26+
27+
```
28+
Input: candidates = [2,3,5], target = 8,
29+
30+
A solution set is:
31+
[
32+
[2,2,2,2],
33+
[2,3,3],
34+
[3,5]
35+
]
36+
```
37+
38+
## Explanations
39+
40+
Since the problem is to get all the possible results, not the best or the
41+
number of result, thus we don’t need to consider DP (dynamic programming),
42+
backtracking approach using recursion is needed to handle it.
43+
44+
Here is an example of decision tree for the situation when `candidates = [2, 3]` and `target = 6`:
45+
46+
```
47+
0
48+
/ \
49+
+2 +3
50+
/ \ \
51+
+2 +3 +3
52+
/ \ / \ \
53+
+2 ✘ ✘ ✘ ✓
54+
/ \
55+
✓ ✘
56+
```
57+
58+
## References
59+
60+
- [LeetCode](https://leetcode.com/problems/combination-sum/description/)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import combinationSum from '../combinationSum';
2+
3+
describe('combinationSum', () => {
4+
it('should find all combinations with specific sum', () => {
5+
expect(combinationSum([1], 4)).toEqual([
6+
[1, 1, 1, 1],
7+
]);
8+
9+
expect(combinationSum([2, 3, 6, 7], 7)).toEqual([
10+
[2, 2, 3],
11+
[7],
12+
]);
13+
14+
expect(combinationSum([2, 3, 5], 8)).toEqual([
15+
[2, 2, 2, 2],
16+
[2, 3, 3],
17+
[3, 5],
18+
]);
19+
20+
expect(combinationSum([2, 5], 3)).toEqual([]);
21+
22+
expect(combinationSum([], 3)).toEqual([]);
23+
});
24+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @param {number[]} candidates - candidate numbers we're picking from.
3+
* @param {number} remainingSum - remaining sum after adding candidates to currentCombination.
4+
* @param {number[][]} finalCombinations - resulting list of combinations.
5+
* @param {number[]} currentCombination - currently explored candidates.
6+
* @param {number} startFrom - index of the candidate to start further exploration from.
7+
* @return {number[][]}
8+
*/
9+
function combinationSumRecursive(
10+
candidates,
11+
remainingSum,
12+
finalCombinations = [],
13+
currentCombination = [],
14+
startFrom = 0,
15+
) {
16+
if (remainingSum < 0) {
17+
// By adding another candidate we've gone below zero.
18+
// This would mean that last candidate was not acceptable.
19+
return finalCombinations;
20+
}
21+
22+
if (remainingSum === 0) {
23+
// In case if after adding the previous candidate out remaining sum
24+
// became zero we need to same current combination since it is one
25+
// of the answer we're looking for.
26+
finalCombinations.push(currentCombination.slice());
27+
28+
return finalCombinations;
29+
}
30+
31+
// In case if we haven't reached zero yet let's continue to add all
32+
// possible candidates that are left.
33+
for (let candidateIndex = startFrom; candidateIndex < candidates.length; candidateIndex += 1) {
34+
const currentCandidate = candidates[candidateIndex];
35+
36+
// Let's try to add another candidate.
37+
currentCombination.push(currentCandidate);
38+
39+
// Explore further option with current candidate being added.
40+
combinationSumRecursive(
41+
candidates,
42+
remainingSum - currentCandidate,
43+
finalCombinations,
44+
currentCombination,
45+
candidateIndex,
46+
);
47+
48+
// BACKTRACKING.
49+
// Let's get back, exclude current candidate and try another ones later.
50+
currentCombination.pop();
51+
}
52+
53+
return finalCombinations;
54+
}
55+
56+
/**
57+
* Backtracking algorithm of finding all possible combination for specific sum.
58+
*
59+
* @param {number[]} candidates
60+
* @param {number} target
61+
* @return {number[][]}
62+
*/
63+
export default function combinationSum(candidates, target) {
64+
return combinationSumRecursive(candidates, target);
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
export default class BloomFilter {
2+
/**
3+
* @param {number} size - the size of the storage.
4+
*/
5+
constructor(size = 100) {
6+
// Bloom filter size directly affects the likelihood of false positives.
7+
// The bigger the size the lower the likelihood of false positives.
8+
this.size = size;
9+
this.storage = this.createStore(size);
10+
}
11+
12+
/**
13+
* @param {string} item
14+
*/
15+
insert(item) {
16+
const hashValues = this.getHashValues(item);
17+
18+
// Set each hashValue index to true.
19+
hashValues.forEach(val => this.storage.setValue(val));
20+
}
21+
22+
/**
23+
* @param {string} item
24+
* @return {boolean}
25+
*/
26+
mayContain(item) {
27+
const hashValues = this.getHashValues(item);
28+
29+
for (let hashIndex = 0; hashIndex < hashValues.length; hashIndex += 1) {
30+
if (!this.storage.getValue(hashValues[hashIndex])) {
31+
// We know that the item was definitely not inserted.
32+
return false;
33+
}
34+
}
35+
36+
// The item may or may not have been inserted.
37+
return true;
38+
}
39+
40+
/**
41+
* Creates the data store for our filter.
42+
* We use this method to generate the store in order to
43+
* encapsulate the data itself and only provide access
44+
* to the necessary methods.
45+
*
46+
* @param {number} size
47+
* @return {Object}
48+
*/
49+
createStore(size) {
50+
const storage = [];
51+
52+
// Initialize all indexes to false
53+
for (let storageCellIndex = 0; storageCellIndex < size; storageCellIndex += 1) {
54+
storage.push(false);
55+
}
56+
57+
const storageInterface = {
58+
getValue(index) {
59+
return storage[index];
60+
},
61+
setValue(index) {
62+
storage[index] = true;
63+
},
64+
};
65+
66+
return storageInterface;
67+
}
68+
69+
/**
70+
* @param {string} item
71+
* @return {number}
72+
*/
73+
hash1(item) {
74+
let hash = 0;
75+
76+
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
77+
const char = item.charCodeAt(charIndex);
78+
hash = (hash << 5) + hash + char;
79+
hash &= hash; // Convert to 32bit integer
80+
hash = Math.abs(hash);
81+
}
82+
83+
return hash % this.size;
84+
}
85+
86+
/**
87+
* @param {string} item
88+
* @return {number}
89+
*/
90+
hash2(item) {
91+
let hash = 5381;
92+
93+
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
94+
const char = item.charCodeAt(charIndex);
95+
hash = (hash << 5) + hash + char; /* hash * 33 + c */
96+
}
97+
98+
return Math.abs(hash % this.size);
99+
}
100+
101+
/**
102+
* @param {string} item
103+
* @return {number}
104+
*/
105+
hash3(item) {
106+
let hash = 0;
107+
108+
for (let charIndex = 0; charIndex < item.length; charIndex += 1) {
109+
const char = item.charCodeAt(charIndex);
110+
hash = (hash << 5) - hash;
111+
hash += char;
112+
hash &= hash; // Convert to 32bit integer
113+
}
114+
115+
return Math.abs(hash % this.size);
116+
}
117+
118+
/**
119+
* Runs all 3 hash functions on the input and returns an array of results.
120+
*
121+
* @param {string} item
122+
* @return {number[]}
123+
*/
124+
getHashValues(item) {
125+
return [
126+
this.hash1(item),
127+
this.hash2(item),
128+
this.hash3(item),
129+
];
130+
}
131+
}

0 commit comments

Comments
 (0)
Please sign in to comment.