Javascript | Dynamic array of Characters based on consecutive letters conditions - javascript

I was doing a codewar challange, and couldn't find a solution, but I really want to know how we can solve this problem.
So we getting two integers, let's say N and D and we should return a string containing exactly N letters 'n' and exactlly D letters d with no three consecutive letters being same.
For example if we get N=5 and D=3 we should return "nndnndnd" or "nbnnbbnn" or any other correct answer
another example like if we get N=1 D=4 the only accepted answer should be "ddndd"
What I did was making a helper function like this :
function generateArray (char,q){
let arr= []
for(let i=0; i<q; i++){
arr.push(char)
}
return arr
}
and inside the main function :
function solution(N, D) {
let arrayOfchar = generateArray('n',N)
arrayOfchar.reduce((prev,current,index) => {
for(let i=0; i<D; i++) {
if(prev===current) {
arrayOfchar.splice(index, 0, "d")
}
}
})
}
But I don't know hoe should I put the "d" only after two or less consecutive "n"
Anyone clue?

Rather than creating an entire array of the same character at the very start, I think it would make more sense to create the array piece-by-piece, until N and D come out to 0.
Here's one possible implementation. The general idea is to try to push whichever character count is larger, or if that's not possible due to 3-in-a-row, push the other character, and subtract the appropriate character count by one. Repeat until both counts are 0:
function solution(n, d) {
const arr = [];
function canPush(char) {
const { length } = arr;
return (arr[length - 1] !== char || arr[length - 2] !== char);
}
function push(char) {
arr.push(char);
if (char === 'n') n--;
else if (char === 'd') d--;
}
while (n > 0 || d > 0) {
if (n > d) {
if (canPush('n')) push('n');
else if (d === 0) return console.log('Impossible');
else push('d');
} else if (d >= n) {
if (canPush('d')) push('d');
else if (n === 0) return console.log('Impossible');
else push('n');
}
}
console.log(JSON.stringify(arr));
// return arr;
}
solution(5, 3);
solution(1, 4);
solution(1, 5);
solution(5, 1);
solution(2, 5);
solution(2, 6);
solution(2, 7);

Here is another solution to this interesting problem. The idea is not to go one by one but to figure which one is the larger number and then do an array of pairs of that letter while doing a simple array of the smaller and then just concat them one with another ... so you have 5 and 3 ... nn + d + nn + d + n. 2 pairs of the bigger plus one of the smaller etc.
const fillArray = (length, letter, bigNumber) => {
var arr = []
for(var index=0; index < length; index++) {
arr.push([letter, bigNumber%2 && index+1 === length ? null : letter])
}
return arr;
}
const getString = (n, d) => {
var swtch = d > n, arr = [],
bigger = {number: swtch ? d : n, letter: swtch ? 'd' : 'n', ceil: Math.ceil((swtch ? d : n)/2)},
smaller = {number: swtch ? n : d, letter: swtch ? 'n' : 'd', ceil: Math.ceil((swtch ? n : d)/2)}
if(Math.abs((bigger.number/2) - smaller.number >= 1.5)) {
return 'Not possible with given parameters!'
}
var bigWorkArray = fillArray(bigger.ceil, bigger.letter, bigger.number)
var smallWorkArray = n === d ? fillArray(smaller.ceil, smaller.letter, smaller.number) : Array(smaller.number).fill(smaller.letter)
for(var i=0; i < bigWorkArray.length; i++) {
arr.push(...bigWorkArray[i],...smallWorkArray[i] || '')
}
return arr.join('');
}
console.log(getString(5,3))
console.log(getString(1,4))
console.log(getString(1,5))
console.log(getString(5,1))
console.log(getString(2,5))
console.log(getString(2,6))
console.log(getString(2,7))

Related

Valid Times on a Digital Clock

This question has been bugging me ever since I got it in a Interview and couldn't figure it out and I've not been able to find a solution anywhere, especially in Javascript:
Given 4 Digits, count how many valid Times can be displayed ib a Digital Clock (in 24hr format) using those digits. Earliest Time is 00:00 and latest is 23:59.
Write a Function:
function solution(A,B,C,D);
That, given 4 intergers A,B,C,D, returns the number of valid times that can be displayed on a digital clock
Start by writing a validating function that tells you whether 4 digits make up a legit time:
function validate(A,B,C,D){
let hours = +("" + A + B),
mins = +("" + C + D);
return hours <= 23
&& hours >= 0
&& mins >= 0
&& mins < 60
}
Then given 4 digits, before you can use the above, you need to generate random orders of those 4 digits. So take any permutation function:
const permutations = arr => {
if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr;
return arr.reduce(
(acc, item, i) =>
acc.concat(
permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [
item,
...val,
])
),
[]
);
};
This will take an array of numbers like permutations([1,2,4,5]). The issue is this function will generate 24 element array even if you give it [1,1,1,1]. So you need to filter the unique ones:
const unique = arr => {
return arr.reduce((ac,d) => {
if(!ac.some(perm => d.join("") === perm.join(""))){
ac.push(d);
}
return ac;
},[])
}
Now you can write your solution combining above 3 functions:
function solution (A,B,C,D){
return unique(permutations([A,B,C,D])).reduce((ac,d) => ac += validate(...d),0)
}
For example:
solution(1,1,6,1) //2
I am absolutely sure it can written tidier and more concise, I might have forgotten something as well, so take everything with a pinch of salt
You're pretty new here. A reminder if you haven't done it, please take the tour, visit the help center and read up on asking good questions. After doing some research and searching for related topics on SO, try it yourself. If you're stuck, post a minimal, reproducible example of your attempt and note exactly where you're stuck.
I wouldn't answer without your demonstrated effort if there was not already a working answer posted.
Because there are only 24 permutations of the four digits, it might be easiest just to include them directly in the code. One solution would use a simple predicate (isValidTime) on four digits to see if they constitute a valid time, and then use a string representation of each possible permutation, convert them to four-digit strings, use the [... new Set (xs)] trick to find an array of the unique ones, collect the ones that match our validity predicate, and finally return the length of that array. It might look like this:
const isValidTime = (A, B, C, D, h = 10 * A + B, m = 10 * C + D) =>
0 <= h && h <= 23 && 0 <= m && m <= 59 // ? `${A}${B}${C}${D}` : false
const countValidTimes = (A, B, C, D, x = {A, B, C, D}) =>
[... new Set ([
"ABCD", "ABDC", "ACBD", "ACDB", "ADBC", "ADCB", "BACD", "BADC",
"BCAD", "BCDA", "BDAC", "BDCA", "CABD", "CADB", "CBAD", "CBDA",
"CDAB", "CDBA", "DABC", "DACB", "DBAC", "DBCA", "DCAB", "DCBA"
] .map (([...cs]) => cs .map (c => x [c]) .join (''))
)] .filter (s => isValidTime (... s .split ('') .map (d => Number(d)))) .length
console .log (countValidTimes (8, 6, 1, 5))
//=> 2 (18:56, 16:58)
console .log (countValidTimes (1, 2, 3, 4))
//=> 10 (12:34, 12:43, 13:24, 13:42, 14:23, 14:32, 21:34, 21:43, 23:14, 23:41)
console .log (countValidTimes (1, 4, 1, 4))
//=> 3 (14:14, 14:41, 11:44)
console .log (countValidTimes (1, 1, 1, 1))
//=> 1 (11:11)
console .log (countValidTimes (8, 6, 7, 5))
//=> 0
maybe not the best solution but i think it's ez to understand. I used backtracking to resolve this problem. Faced this question in an interview too :D.
public static void main(String[] args) {
//Driver
int result = solution(6, 2, 4, 7);
System.out.println(result);
}
public static int solution(int a, int b, int c, int d) {
int[] arr = {-1, -1, -1, -1};
Map<Integer, Integer> tracking = new HashMap<>();
tracking.put(a, 0);
tracking.put(b, 0);
tracking.put(c, 0);
tracking.put(d, 0);
int[] track = {a, b, c, d};
for (int i = 0; i < track.length; i++) {
tracking.put(track[i], tracking.get(track[i]) + 1);
}
Set<String> set = new HashSet<>();
possibleTime(a, b, c, d, arr, 0, tracking,set);
return set.size();
}
public static int[] possibleTime(int a, int b, int c, int d, int[] arr, int index, Map<Integer, Integer> tracking,Set<String> set) {
if (index == 4) {
set.add(Arrays.toString(arr));
return arr;
}
int[] pos = {a, b, c, d};
for (int i = 0; i < pos.length; i++) {
arr[index] = pos[i];
tracking.put(pos[i], tracking.get(pos[i]) - 1);
if (isValidTime(arr, tracking,set)) {
index++;
arr = possibleTime(a, b, c, d, arr, index, tracking,set);
index--;
}
tracking.put(pos[i], tracking.get(pos[i]) + 1);
arr[index] = -1;
}
return arr;
}
public static boolean isValidTime(int[] arr, Map<Integer, Integer> tracking,Set<String> set) {
//check existed
for (Integer in : tracking.keySet()) {
if (tracking.get(in) < 0) {
return false;
}
}
if(set.contains(Arrays.toString(arr)))
{
return false;
}
//validate hh
Map<Integer, Integer> hh = new HashMap<>();
hh.put(1, 9);
hh.put(2, 3);
if (arr[0] != -1) {
if (hh.containsKey(arr[0])) {
if (arr[1] != -1 && arr[1] > hh.get(arr[0])) {
return false;
}
} else {
return false;
}
}
//validate mmm
if (arr[2] != -1 && arr[2] > 5) {
return false;
}
if (arr[3] != -1 && arr[3] > 9) {
return false;
}
return true;
}
def solution(A, B, C, D):
times = 0
# check all possible hours
for hour_tens in range(2):
for hour_units in range(4):
if (hour_tens == 2 and hour_units > 3):
continue
# check all possible minutes
for min_tens in range(6):
for min_units in range(10):
if (str(hour_tens) + str(hour_units) + str(min_tens) + str(min_units)).count(str(A)) + (str(hour_tens) + str(hour_units) + str(min_tens) + str(min_units)).count(str(B)) + (str(hour_tens) + str(hour_units) + str(min_tens) + str(min_units)).count(str(C)) + (str(hour_tens) + str(hour_units) + str(min_tens) + str(min_units)).count(str(D)) == 4:
times += 1
return times

find all possible combinations of two integers

Each time I can climb 1 or 2 steps to reach the top (3 steps for example)
1 + 1 + 1, 1 + 2, 2 + 1. There are three cases (scenarios). Here's my voodoo code (the thing is some numbers (missing) don't appear for n = 5 it's 1211. the solution would be to do the reverse string and store two versions of such strings in the hash, so duplicates will disappear and after the cycle sums them.
function setCharAt(str, index, chr) {
if (index > str.length - 1) return str;
return str.substring(0, index) + chr + str.substring(index + 1);
}
let n = 9;
find(n);
function find(n) {
let origin = n; //every loop n decreases by one when it 0 while returns false,
let sum = 1;
n -= 1; //because n once once of 1's (n = 5) 1+1+1+1+1 then 1111, 1112 etc.
if (n <= 1) return sum;
while (origin <= n * 2) { //if n = 10; only"22222" can give 10, we don't go deeper
let str = "1".repeat(n); //from "1" of n(4) to "1111"
let copyStr = str;
while (str.length === copyStr.length) { //at the end we get 2222 then 22221,
// therefore the length will change, we exit the loop
let s = str.split('').reduce((a, b) => Number(a) + Number(b), 0); //countinng elems
console.log(str, "=", s);
if (s === origin) ++sum; //if elems equals the target we increase the amount by one
let one = str.lastIndexOf("1");
let two = str.lastIndexOf("2");
if (str[one] === "1" && str[one + 1] === "2") {
str = setCharAt(str, one, "2");
str = setCharAt(str, one + 1, "1");
} else {
str = setCharAt(str, one, "2");
}
}
--n;
}
console.log(sum)
}
If i understood your question, you wanna for let say n = 5 get all combinations of 1 and 2 (when you sum it) that give a sum of 5 (11111, 1112, etc)?
It is most likely that you wanna use recursion in these kind of situations, because its much easier. If you have just two values (1 and 2) you can achieve this pretty easily:
getAllCombinations = (n = 1) => {
const combinations = [];
const recursion = (n, sum = 0, str = "") => {
if (sum > n) return;
if (sum === n) {
combinations.push(str);
return;
}
// Add 1 to sum
recursion(n, sum + 1, str + "1");
// Add 2 to sum
recursion(n, sum + 2, str + "2");
};
recursion(n);
return combinations;
};

Rearranging a string to be a palindrome

I'm trying to solve the problem of: Given an array of strings with only lower case letters, make a function that returns an array of those same strings, but each string has its letters rearranged such that it becomes a palindrome (if not possible then return -1). I'm a bit stuck on how I should be rearranging the letters.
let arr = ["hello", "racecra"];
I created a function to first check if a word is a palindrome :
function isPalindrome(arr) {
let obj = {};
for (var x = 0; x < str.length; x++) {
if (obj[arr[x]]) {
obj[arr[x]] += 1;
} else {
obj[arr[x]] = 1;
}
}
let countOdd = 0;
let countEven = 0;
for (let x of Object.values(obj)) {
if (x % 2 == 0) {
countEven += 1;
} else {
countOdd += 1;
}
}
return countOdd == 1 ? true : false
}
then I plan to loop through the words
let emptyArr = [];
for (var x = 0; x < arr.length; x++) {
if (isPalindrome(arr[x]) {
// not sure what to do here. I know the word is a palindrome but not sure how to sort the order of the word in the palindrome form.
} else {
emptyArr.push(-1);
}
}
return emptyArr;
Look closely: you don't need your words to be palindromes, you need them to be rearrangeable as palindromes ("palindrome-candidates"). Now, a word is a palindrome-candidate if all of its letters but one can be counted by an even number (2, 4, 6 etc.)
For example, this...
hollo
... is NOT a palindrome, but can become one, as there's 2 'o', 2 'l' and just one 'h' in it. To rearrange, you just move 'h' in the middle, then just place 'o' and 'l' before and after it:
l -> o -> h <- o <- l
So start with splitting each of your words by characters, then either count those characters or just sort them (as #Barmar suggested). If they satisfy the condition, rearrange the letters following the approach given; if not, return null (or any other special value clearly distinguishable from the rest) immediately.
Here's one way to do it:
function rearrangeAsPalindrome(word) {
if (word.length === 1) return word; // easy win first
const charCounter = word.split('').reduce((counter, ch) => ({
...counter,
[ch]: (counter[ch] || 0) + 1
}), {});
const parts = ['', '', '']; // left, middle, right
const entries = Object.entries(charCounter);
for (let i = 0; i < entries.length; ++i) {
const [char, counter] = entries[i];
if (counter % 2) { // odd
if (parts[1] !== '') return null;
// one odd is already here, eject! eject!
parts[1] = char.repeat(counter);
}
else { // even
const half = counter / 2;
parts[0] = char.repeat(half) + parts[0];
parts[2] += char.repeat(half);
}
}
return parts.join('');
}
console.log(rearrangeAsPalindrome('racarrrac')); // crraaarrc
console.log(rearrangeAsPalindrome('aabbcc')); // cbaabc
console.log(rearrangeAsPalindrome('hollo')); // lohol
console.log(rearrangeAsPalindrome('hello')); // null
This function returns null (and does it early) when it realizes the word given cannot be rearranged as a palindrome - or an actual palindrome if it is possible.
This can help
"How to generate distinct palindromes from a string in JavaScript"
https://medium.com/#bibinjaimon/how-to-generate-distinct-palindromes-from-a-string-in-javascript-6763940f5138

Return the first non-repeating character of a string

In the first chunk of my code I have an ' if ' statement that is not working as it should, and I can't figure out why.
When using the argument 'hous', it should enter the first ' if ' statement and return 0. It returns -1 instead.
var firstUniqChar = function(s) {
for (let i = 0; i < s.length; i++){
let letter = s[i];
// console.log('s[i]: ' + letter);
// console.log(s.slice(1));
// console.log( 'i: ' + i);
if ((i = 0) && !(s.slice(1).includes(letter))) {
return 0;
}
if ((i = s.length - 1) && !(s.slice(0, i).includes(letter))) {
return 1;
}
if(!(s.slice(0, i).includes(letter)) && !(s.slice(i + 1).includes(letter))) {
return 2;
}
}
return -1;
};
console.log(firstUniqChar("hous"));
This is another way you can write your function:
const firstUniqChar = s => [...s].filter(c=>!(s.split(c).length-2))[0] || -1;
console.log(firstUniqChar("hous"));
console.log(firstUniqChar("hhoous"));
console.log(firstUniqChar("hhoouuss"));
Look up method for scattered repeated characters and functional find()-based approach
You may break your input string into array of characters (e.g. using spread syntax ...) and make use of Array.prototype.find() (to get character itserlf) or Array.prototype.findIndex() (to get non repeating character position) by finding the character that is different from its neighbors:
const src = 'hhoous',
getFirstNonRepeating = str =>
[...str].find((c,i,s) =>
(!i && c != s[i+1]) ||
(c != s[i-1] && (!s[i+1] || c != s[i+1])))
console.log(getFirstNonRepeating(src))
.as-console-wrapper{min-height:100%;}
Above will work perfectly when your repeating characters are groupped together, if not, I may recommend to do 2-passes over the array of characters - one, to count ocurrence of each character, and one more, to find out the first unique:
const src = 'hohuso',
getFirstUnique = str => {
const hashMap = [...str].reduce((r,c,i) =>
(r[c]=r[c]||{position:i, count:0}, r[c].count++, r), {})
return Object
.entries(hashMap)
.reduce((r,[char,{position,count}]) =>
((count == 1 && (!r.char || position < r.position)) &&
(r = {char, position}),
r), {})
}
console.log(getFirstUnique(src))
.as-console-wrapper{min-height:100%;}
function nonRepeat(str) {
return Array
.from(str)
.find((char) => str.match(newRegExp(char,'g')).length === 1);
}
console.log(nonRepeat('abacddbec')); // e
console.log(nonRepeat('1691992933')); // 6
console.log(nonRepeat('thhinkninw')); // t

How to find nth Fibonacci number using Javascript with O(n) complexity

Trying really hard to figure out how to solve this problem. The problem being finding nth number of Fibonacci with O(n) complexity using javascript.
I found a lot of great articles how to solve this using C++ or Python, but every time I try to implement the same logic I end up in a Maximum call stack size exceeded.
Example code in Python
MAX = 1000
# Create an array for memoization
f = [0] * MAX
# Returns n'th fuibonacci number using table f[]
def fib(n) :
# Base cases
if (n == 0) :
return 0
if (n == 1 or n == 2) :
f[n] = 1
return (f[n])
# If fib(n) is already computed
if (f[n]) :
return f[n]
if( n & 1) :
k = (n + 1) // 2
else :
k = n // 2
# Applyting above formula [Note value n&1 is 1
# if n is odd, else 0.
if((n & 1) ) :
f[n] = (fib(k) * fib(k) + fib(k-1) * fib(k-1))
else :
f[n] = (2*fib(k-1) + fib(k))*fib(k)
return f[n]
// # Driver code
// n = 9
// print(fib(n))
Then trying to port this to Javascript
const MAX = 1000;
let f = Array(MAX).fill(0);
let k;
const fib = (n) => {
if (n == 0) {
return 0;
}
if (n == 1 || n == 2) {
f[n] = 1;
return f[n]
}
if (f[n]) {
return f[n]
}
if (n & 1) {
k = Math.floor(((n + 1) / 2))
} else {
k = Math.floor(n / 2)
}
if ((n & 1)) {
f[n] = (fib(k) * fib(k) + fib(k-1) * fib(k-1))
} else {
f[n] = (2*fib(k-1) + fib(k))*fib(k)
}
return f[n]
}
console.log(fib(9))
That obviously doesn't work. In Javascript this ends up in an infinite loops. So how would you solve this using Javascript?
Thanks in advance
you can iterate from bottom to top (like tail recursion):
var fib_tail = function(n){
if(n == 0)
return 0;
if(n == 1 || n == 2)
return 1;
var prev_1 = 1, prev_2 = 1, current;
// O(n)
for(var i = 3; i <= n; i++)
{
current = prev_1 + prev_2;
prev_1 = prev_2;
prev_2 = current;
}
return current;
}
console.log(fib_tail(1000))
The problem is related to scope of the k variable. It must be inside of the function:
const fib = (n) => {
let k;
You can find far more good implementations here list
DEMO
fibonacci number in O(n) time and O(1) space complexity:
function fib(n) {
let prev = 0, next =1;
if(n < 0)
throw 'not a valid value';
if(n === prev || n === next)
return n;
while(n >= 2) {
[prev, next] = [next, prev+next];
n--;
}
return next;
}
Just use two variables and a loop that counts down the number provided.
function fib(n){
let [a, b] = [0, 1];
while (--n > 0) {
[a, b] = [b, a+b];
}
return b;
}
console.log(fib(10));
Here's a simpler way to go about it, using either iterative or recursive methods:
function FibSmartRecursive(n, a = 0, b = 1) {
return n > 1 ? FibSmartRecursive(n-1, b, a+b) : a;
}
function FibIterative(n) {
if (n < 2)
return n;
var a = 0, b = 1, c = 1;
while (--n > 1) {
a = b;
b = c;
c = a + b;
}
return c;
}
function FibMemoization(n, seenIt = {}) {//could use [] as well here
if (n < 2)
return n;
if (seenIt[n])
return seenIt[n];
return seenIt[n] = FibMemoization(n-1, seenIt) + FibMemoization(n-2, seenIt);
}
console.log(FibMemoization(25)); //75025
console.log(FibIterative(25)); //75025
console.log(FibSmartRecursive(25)); //75025
You can solve this problem without recursion using loops, runtime O(n):
function nthFibo(n) {
// Return the n-th number in the Fibonacci Sequence
const fibSeq = [0, 1]
if (n < 3) return seq[n - 1]
let i = 1
while (i < n - 1) {
seq.push(seq[i - 1] + seq[i])
i += 1
}
return seq.slice(-1)[0]
}
// Using Recursion
const fib = (n) => {
if (n <= 2) return 1;
return fib(n - 1) + fib(n - 2);
}
console.log(fib(4)) // 3
console.log(fib(10)) // 55
console.log(fib(28)) // 317811
console.log(fib(35)) // 9227465

Categories

Resources