1
\$\begingroup\$

The task

is taken from leetcode

You're given strings J representing the types of stones that are jewels, and S representing the stones you have. Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels.

The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive, so "a" is considered a different type of stone from "A".

Example 1:

Input: J = "aA", S = "aAAbbbb"

Output: 3

Example 2:

Input: J = "z", S = "ZZ"

Output: 0

Note:

S and J will consist of letters and have length at most 50. The characters in J are distinct.

My functional solution

/**
 * @param {string} J
 * @param {string} S
 * @return {number}
 */
var numJewelsInStones = function(J, S) {
  const set = new Set(J);
  return [...S].reduce((ac, s) => set.has(s) + ac, 0);
};

My imperative solution:

/**
 * @param {string} J
 * @param {string} S
 * @return {number}
 */
var numJewelsInStones = function(J, S) {
  let num = 0;
  const set = {};
  for (let j = 0; j < J.length; j++) {
    set[J[j]] = 1;
  }
  for (let s = 0; s < S.length; s++) {
    num += set[S[s]] || 0;
  }
  return num;
};
\$\endgroup\$

3 Answers 3

2
\$\begingroup\$

Your code is concise and readable... I didn't have any feedback... it really shows how the functional solution is nicer.

I was curious if it could be done with regular expressions and no iteration, so I played around and got:

const numJewelsInStones = (j,s) => { 
  const m = s.match(new RegExp(`[${j}]`,'g'))
  return m ? m.length : 0 
}

or even

numJewelsInStones = (j,s) => s.replace(new RegExp(`[^${j}]`,'g'),'').length
\$\endgroup\$
1
  • \$\begingroup\$ Very clever indeed \$\endgroup\$ Commented Jun 1, 2019 at 18:51
1
\$\begingroup\$

Instead of populating a Set and using .has(), you can use String includes() directly. After that, it's just a matter of filtering the array and taking its length. I'd avoid using regexes unless they actually simplify things.

const countJewels = (J, S) => [...S].filter(n => J.includes(n)).length

console.log(countJewels("aA", "aAaabb"))

Your functions should be const unless you intend to change them. I wouldn't use parameter names like J and S, but I guess those were given by leetcode.

\$\endgroup\$
2
  • \$\begingroup\$ Includes is slower I think \$\endgroup\$ Commented Jun 4, 2019 at 10:52
  • \$\begingroup\$ For length 50 it might actually not be. Anyway, the inputs are so short you don't need to care. \$\endgroup\$
    – JollyJoker
    Commented Jun 4, 2019 at 10:55
0
\$\begingroup\$

here is my proposal: there are fewer cycles, and uses a regex more "simple" for interpreters javascript (I think that the use of the Set consumes more resources)

function numJewelsInStones(J, S)
{
  return [...J].reduce((ac, j) => ac + (S.match(RegExp(j)) || []).length, 0)
}

console.log( "'aA', 'aAAbbbb' ==>", numJewelsInStones('aA', 'aAAbbbb') )
console.log( "'z', 'ZZ' ==>", numJewelsInStones('z', 'ZZ') )

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.