10 common algorithms we would likely encounter in real life. Lets improve our logic and programming skills. showing a clear and concise explanations of how these different algorithms work.
Return the number of total permutations of the provided string that don't have repeated consecutive letters. Assume that all characters in the provided string are each unique.
To solve this problem, we need to generate all permutations of the given string. A permutation is an arrangement of the characters in a string. For example, the permutations of "abc" are: 'abc', 'bac', 'bca', 'acb', 'cab', 'cba'.
This means 1 x 2 x 3 = 6 permutations
"c" has only 1 slot
"b" has choice of 2 slot
"a" has choice of 3 slot
"c" | "b" | "a"
____________________________________________
| |
"c" | "bc" | "abc"
| | "bac"
| | "bca"
| "cb" | "acb"
| | "cab"
| | "cba"
permutation([""], "c") // ["c"]
permutation(["c"], "b") // ["bc", "cb"]
permutation(["bc", "cb"], "a") //[ 'abc', 'bac', 'bca', 'acb', 'cab', 'cba' ]
- We will generate all possible permutations of the input string.
- We will filter out permutations that have consecutive repeated letters.
The key to our solution is the getPermutation
function. It generates all permutations recursively by taking the first character and inserting it at different positions in the permutations of the rest of the string.
function getPermutation(str) {
if (str.length == 0) return [""];
let new_char = str[0];
let current_permutation = getPermutation(str.slice(1));
let new_permutation = []
for (let perm of current_permutation){
for (let i=0; i<=perm.length; i++){
let new_perm = perm.slice(0, i) + new_char + perm.slice(i)
new_permutation.push(new_perm);
}
}
return new_permutation;
}
We use the hasConsecutiveLetters
function to check if a permutation has consecutive repeated letters.
function hasConsecutiveLetters(str) {
for (let i=0; i<str.length-1; i++){
if (str[i] == str[i+1]) return true;
}
return false
}
Here are some example calls to the permAlone function with different input strings:
permAlone("aab") // Returns 2
permAlone("aaa") // Returns 0
permAlone("aabb") // Returns 8
permAlone("abcdefa") // Returns 3600
permAlone("abfdefa") // Returns 2640
permAlone("zzzzzzzz") // Returns 0
permAlone("a") // Returns 1
permAlone("aaab") // Returns 0
permAlone("aaabb") // Returns 12
Given an array arr
, find element pairs whose sum equals the second argument arg
and return the sum of their indices. You may use multiple pairs that have the same numeric elements but different indices. Once an element has been used, it cannot be reused to pair with another element. Each pair should use the lowest possible available indices.
Following the question, we have four major tasks:
- Find a pair (a, b)
- Validate the pair
- Utilize the pair
- Eliminate the pair
We loop through each item in the array, taking it as one of the pairs (a
). Then, we loop through each item in the array again to find the other item of the pair (b
). We check if the pair is valid and eliminate it by marking a
& b
as null in the array.
A valid pair passes this test:
a
has not been paired with anotherb
has not been paired with anothera
has a different index fromb
a + b = arg
-
Initialization:
- Initialize a variable
sum
to keep track of the total sum of indices:
let sum = 0;
- Initialize a variable
-
Pair Search - First Loop:
- Loop through the array to find the first element of a pair, which we'll call
a
.
for (let aIndex = 0; aIndex < arr.length; aIndex++) { ... }
- Loop through the array to find the first element of a pair, which we'll call
-
Pair Validation - a:
- Ensure that
a
is not already part of a pair (a != null
).
let a = arr[aIndex]; if (a === null) continue;
- Ensure that
-
Pair Search - Second Loop:
- Start a nested loop to find the second element of a pair, which we'll call
b
.
for (let bIndex = 0; bIndex < arr.length; bIndex++) { ... }
- Start a nested loop to find the second element of a pair, which we'll call
-
Pair Validation - b:
- Validate the pair (a, b) by checking:
- a and b are not the same value (aIndex !== bIndex).
- b is not already in a pair (arr[bIndex] != null).
- The sum of a and b equals the target value arg.
let b = arr[bIndex]; if (aIndex !== bIndex && b !== null && a + b === arg) { ... }
- Validate the pair (a, b) by checking:
-
Utilize Valid Pair:
- If a valid pair is found, add the indices of
a
andb
to thesum
variable.
sum += aIndex + bIndex;
- If a valid pair is found, add the indices of
-
Pair Elimination:
- Eliminate the valid pair by setting their corresponding elements in the array to null.
arr[aIndex] = null; arr[bIndex] = null;
-
Next Pair:
- After a valid pair is found, utilized & eliminated, we no longer continue the second loop.
break;
-
Return the Accumulated Sum:
- Return the
sum
.
return sum;
- Return the
-
Selecting Pairs:
- We take an element from the
arr
, let's call ita
. - We find its complement, let's call it
b
, such thatb = arg - a
. - We now have a pair
(a, b)
.
- We take an element from the
-
Validating Pairs:
- To determine if the pair is valid, we check if
b
is inarr
. - It's crucial to ensure that
b
is within the arrayarr
. - There might be duplicate instances of
b
in the array with the same numeric value but different indices. - Our goal is to select the smallest
b
based on its position in the array. - Additionally, we need to confirm that the chosen
b
has not been previously paired with another element. - Keep in mind that the search for
b
considers thata
is effectively removed from the array. Ifa
andb
have the same numeric value, a valid pair should have distinct indices.
- To determine if the pair is valid, we check if
-
Optimizing Pair Search with a New Data Structure:
- To optimize the search for the complement
b
and achieve O(1) complexity, we create a new data structurearrNew
fromarr
. arrNew
is an object where keys represent unique values in the array, and each key has associated information.- Example:
arr = [0, 0, 0, 0, 1, 1] arrNew = { '0': { indices: [0, 1, 2, 3], pointer: 0 }, '1': { indices: [4, 5], pointer: 0 } }
- In this example, '0' and '1' are keys representing unique values in the array.
indices: [0, 1, 2, 3]
indicates the indices of occurrences for each value ('0' or '1').pointer: 0
is a pointer to the index that is free to use. If the pointer increases to 1, that means the index 0 has been used in a pair, and the next available version is at index 1.
- To optimize the search for the complement
-
Initialization:
- Initialize a variable
sum
to 0:
let sum = 0;
- Initialize a variable
-
Object a New Datastructure:
- Create
arrNew
fromarr
to efficiently track indices.
let arrNew = {}; arr.forEach((item, index)=>{ if (arrNew[item]) arrNew[item].indices.push(index); else arrNew[item] = {indices: [index], pointer: 0]}; })
- Create
-
Inspect each element in the Initial Data Structure:
- Iterate through each element
a
in the arrayarr
.
for (let a of arr){ ... }
- Iterate through each element
-
Compute the Complement b:
- Compute
b = arg - a
.
- Compute
-
Retrieve
b
Information & Retrievea
Information:- If
b
is a key inarrNew
, get the indices ofb
and its pointer & get the indices ofa
and its pointer.
if (arrNew[b]){ const bIndices = arrNew[b].indices; let bPointer = arrNew[b].pointer; const aIndices = arrNew[a].indices; let aPointer = arrNew[a].pointer; ... }
- If
-
Handle Edge Case:
- If
b
anda
have the same numeric value, adjust the pointer forb
to avoid using the same index.
if (b === a) bPointer = bPointer + 1;
- If
-
Check Availability:
- Ensure there are available indices for both
a
andb
.
if (aPointer < aIndices.length && bPointer < bIndices.length){ ... }
- Ensure there are available indices for both
-
Pairing and Update:
- If available, add both indices to the global
sum
variable and update pointers for botha
andb
.
sum += aIndices[aPointer] + bIndices[bPointer]; arrNew[a].pointer += 1; arrNew[b].pointer += 1;
- If available, add both indices to the global
Here are some example calls to the pairwise function with different input arrays:
pairwise([1, 1, 2], 3); // Returns 1
pairwise([1, 3, 2, 4], 4); // Returns 1