cs.slides.com/colt_steele/problem-solving-patterns
Frequency Counter
This pattern uses objects or sets to collect values/frequencies of values
can often avoid nested loop or O(n^2) operations with arrays/strings
function same(arr1, arr2){
if(arr1.length !== arr2.length){
return false;
}
for(let i = 0; i < arr1.length; i++){
let correctIndex = arr2.indexOf(arr1[i] ** 2)
if(correctIndex === -1) {
return false;
}
console.log(arr2);
arr2.splice(correctIndex,1)
}
return true;
}
same([1,2,3,2], [9,1,4,4])
the idea behind the frequency counter usually use an object
and you use that object to construct a profile sort of a way of breaking down the contents of an array or a string.
function same(arr1, arr2){
if(arr1.length !== arr2.length){
return false;
}
let frequencyCounter1 = {}
let frequencyCounter2 = {}
for(let val of arr1){
frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1
}
for(let val of arr2){
frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1
}
console.log(frequencyCounter1);
console.log(frequencyCounter2);
for(let key in frequencyCounter1){
if(!(key ** 2 in frequencyCounter2)){
return false
}
if(frequencyCounter2[key ** 2] !== frequencyCounter1[key]){
return false
}
}
return true
}
same([1,2,3,2,5], [9,1,4,4,11])
Anagrams
is a word, phrase or name formed by rearrangeing the letters of another.
not only if the letters are in there but also the correct number of times the frequencies are correct.
| vaildAnagram('cinema', 'iceman') //true |
Using Frequency Counter Solution
function validAnagram(str1, str2){
// add whatever parameters you deem necessary - good luck!
let str1Arr = str1.split('');
let str2Arr = str2.split('');
if(str1Arr.length !== str2Arr.length) return false;
let char1 = {};
let char2 = {};
for(let val of str1Arr) {
char1[val] = (char1[val] || 0) +1;
}
for(let val of str2Arr) {
char2[val] = (char2[val] || 0) +1;
}
for( let val of Object.keys(char1) ) {
if(char1[val] !== char2[val]) {
return false;
}
}
return true;
}
another solution without nested loop, only two loops
function validAnagram(first, second) {
if (first.length !== second.length) {
return false;
}
const lookup = {};
for (let i = 0; i < first.length; i++) {
let letter = first[i];
// if letter exists, increment, otherwise set to 1
lookup[letter] ? lookup[letter] += 1 : lookup[letter] = 1;
}
console.log(lookup)
for (let i = 0; i < second.length; i++) {
let letter = second[i];
// can't find letter or letter is zero then it's not an anagram
if (!lookup[letter]) {
return false;
} else {
lookup[letter] -= 1;
}
}
return true;
}
// {a: 0, n: 0, g: 0, r: 0, m: 0,s:1}
validAnagram('anagrams', 'nagaramm')
Multiple Pointers
- Creating pointers or values that correspond to an index or position and
move towards the biginning, end or middle based on a certain condition
- very efficient for solving problems with minimal space complexity
ex1 )
Write a function called sumSero which accepts a sorted array of integers.
the function should find the first pair whrer the sum is 0.
looking for something to sums to zero
function sumZero(arr){
for(let i = 0; i < arr.length; i++){
for(let j = i+1; j < arr.length; j++){
if(arr[i] + arr[j] === 0){
return [arr[i], arr[j]];
}
}
}
}
sumZero([-4,-3,-2,-1,0,1,2,5])
ex2) countUniqueValues
counts the unique values in the array. could accepts a sorted array.
function countUniqueValues(arr){
// add whatever parameters you deem necessary - good luck!
let i = 0;
if(!arr.length) return i;
for(let j = 0; j<arr.length; j++) {
if(arr[i] !== arr[j]) {
i++
arr[i+1] = arr[j];
}
}
return i+1;
}
console.log(countUniqueValues([]));
Sliding Window
- involves creating a window which can either be an array or number from one position to another
- very useful for keeping track of a subset of data in an array/string etc.
ex)
Write a function called maxSubarraySum which accepts an array of integers and a number called n.
// do not recalculate all again. just subtract the first one and add the next one.
// sliding window
function maxSubarraySum(arr, num){
let maxSum = 0;
let tempSum = 0;
if (arr.length < num) return null;
for (let i = 0; i < num; i++) {
maxSum += arr[i];
}
tempSum = maxSum;
for (let i = num; i < arr.length; i++) {
tempSum = tempSum - arr[i - num] + arr[i];
maxSum = Math.max(maxSum, tempSum);
}
return maxSum;
}
maxSubarraySum([2,6,9,2,1,8,5,6,3],3)
Divide and Conquer
- This pattern involves dividing a data set into smaller chunks and then repeating a process with a subset of data.
- tremendously decrease time complexity
quick sort and merge sort , binary search are examples of divide and conquer algorithms
ex)
writhe a function called search that accepts a value and it returns the index where that value is found.
pick a middle element and compare whether the value is greater or not.
Time Complexity - Log(N) - Binary Search
it is commonly useed pattern
function search(array, val) {
let min = 0;
let max = array.length - 1;
while (min <= max) {
let middle = Math.floor((min + max) / 2);
let currentElement = array[middle];
if (array[middle] < val) {
min = middle + 1;
}
else if (array[middle] > val) {
max = middle - 1;
}
else {
return middle;
}
}
return -1;
}'Javascript > Algorithms' 카테고리의 다른 글
| Searching Algorithms (0) | 2020.12.23 |
|---|---|
| Recursion (0) | 2020.12.20 |
| Problem Solving Approach (0) | 2020.12.08 |
| The Big O of Objects and Array (0) | 2020.12.06 |
| Introducing Big O (0) | 2020.12.03 |