How can I compare two shuffled strings? - javascript

I have the following two strings:
var str1 = "hello";
var str2 = "ehlol";
How can I check whether both strings contain the same characters?

May not be very optimal, but you can simply do
str1.split("").sort().join() == str2.split("").sort().join(); //outputs true
Another suggested approach in one the comments (for optimization in case string length is quite big)
str1.length===str2.length && str1.split("").sort().join() == str2.split("").sort().join(); //first check the length to quickly rule out in case of obvious non-matches

One of the recommended ways to do it is using a hash table: count how many times each character appears. Note that this works best if your characters are ASCII.
The complexity of this algorithm is O(M+N+sigma) where M, N are the lengths of the strings and sigma is the number of distinct letters. The complexity of the accepted solution is higher because of the sorting, which is usually done in O(N*logN), but still a good one if your strings are short. If your strings have hundreds of thousands of characters, then this is the way to go. The drawback of using hash tables is that the memory usage is higher than the solution that uses sorting.
function sameLetters(str1, str2){
var hash = {};
var len1 = str1.length;
var len2 = str2.length;
// Strings with different lengths can't contain the same letters
if(len1 !== len2) return false;
// Count how many times each character appears in str1
for(var i = 0; i < len1; ++i) {
var c = str1[i];
if(typeof hash[c] !== 'undefined') hash[c]++;
else hash[c] = 1;
}
// Make sure each character appearing in str2 was found in str1
for(var i = 0; i < len2; ++i) {
var c = str2[i];
if(typeof hash[c] === 'undefined') return false;
if(hash[c] === 0) return false;
hash[c]--;
}
// Make sure no letters are left
for(var c in hash) {
if(hash[c]) return false;
}
return true;
}
You can then call the function like this (play with it in the browser console):
sameLetters("hello", "ehlol"); // true
sameLetters("hello", "ehllol"); // false

You can use a function for this purpose like sameChars function here-
function myFunction()
{
var input_1 = document.getElementById('input_1').value;
var input_2 = document.getElementById('input_2').value;
var result = sameChars(input_1,input_2);
document.getElementById("demo").innerHTML = result;
}
function sameChars(firstStr, secondStr)
{
var first = firstStr.split('').sort().join('');
var second = secondStr.split('').sort().join('');
return first.localeCompare(second)==0;
}
<input type="text" maxlength="512" id="input_1"/>
<input type="text" maxlength="512" id="input_2"/>
<button onclick="myFunction()">Check If Shuffled</button>
<p id="demo"></p>

Here's a modified version of Gurvinders answer.
var str1 = "hello",
str2 = "ehlol";
// Add sort on prototype of String object
String.prototype.sort = function () {
return this.split('').sort().join('');
};
// First check if length of both is same
var same = str1.length === str2.length && str1.sort() === str2.sort();
console.log('Strings are same?', same);

You could possibly say this:
(a.length === b.length) && (a.split('').every(function(val) { return b.indexOf(val) > -1}))
And, in ES6 you could make it look as follows:
(a.length === b.length) && a.split('').every(val => { return b.indexOf(val) > -1 })

Related

Word Break algorithm

I'm trying to implement the "Word Break" algorithm.
Problem:
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
Note:
The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.
Example:
Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".
My solution:
var wordBreak = function(s, wordDict) {
if(!wordDict || wordDict.length === 0)
return false;
while(wordDict.length > 0 || s.length > 0) {
const word = wordDict.shift();
const index = s.indexOf(word);
if(index === -1) {
return false;
}
s = s.substring(0, index) + s.substring(index+word.length, s.length);
}
return s.length === 0 && wordDict.length === 0 ? true : false;
};
It works for the example (input) above. However it fails for the input below.
Input: s = "applepenapple", wordDict = ["apple", "pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
Note that you are allowed to reuse a dictionary word.
How can I keep track of words that I already eliminate and check it at the end. This input above, the remaining s string contains "apple" which is in the word dictionary, so the output should be true.
Thanks
A simple Javascript solution.
This loops through the wordDict array and checks if each word exist in the str. If it doesn't that is when the indexOf the word return -1, the function returns false. However, if the words in the wordDict array are in the string, it returns true at the end of the for loop.
const wordBreak =(str, wordDict)=>{
if (!wordDict || wordDict.length === 0) return false
for(let i=0; I<wordDict.length; i++){
const dictIndex = str.indexOf(wordDict[i])
if(dictIndex === -1){
return false
}
}
return true
}
This is an interesting problem I met two years ago in a different context, i.e., query tokenization. In my case, the number of words in the dictionary was in the order of several million, therefore a recursive approach looking each time for a different word of the dictionary was not practicable. Furthermore, I needed to apply dynamic programming to solve the task for strict efficiency reasons.
First of all, I suggest you to use the AhoCorasick algorithm to find the words within your search string. The algorithm looks for an arbitrary number of patterns in a string in linear time in the length of the string regardless of the number of patterns to find (no more number of words times length of the string operation, indeed each find of a word in a string needs to scan the entire string..).
Luckily, I found a javascript implementation of the algorithm here.
Using the code linked above and dynamic programming to track the words appearing in your string, I wrote the following javascript solution:
function wordBreak(s, wordDict) {
const len = s.length;
const memoization_array_words = new Array(len).fill(null);
const memoization_array_scores = new Array(len).fill(0);
const wordScores = {};
wordDict.forEach(function(word) {
wordScores[word] = 1
});
automata = new AhoCorasick(wordDict);
results = automata.search(s);
results.forEach(function(result) {
// result[0] contains the end position
// result[1] contains the list of words ending in that position
const end_pos = result[0];
result[1].forEach(function(word) {
const prev_end_pos = end_pos - word.length;
const prev_score = (prev_end_pos == -1) ? 0 : memoization_array_scores[prev_end_pos];
const score = prev_score + wordScores[word];
if (score > memoization_array_scores[end_pos]) {
memoization_array_words[end_pos] = word;
memoization_array_scores[end_pos] = score;
}
});
});
if (memoization_array_words[len-1] == null) {
return false;
}
solution = []
var pos_to_keep = len - 1;
while (pos_to_keep >= 0) {
const word = memoization_array_words[pos_to_keep];
solution.push(word);
pos_to_keep -= word.length;
}
return solution.reverse()
}
where memoization_array_words and memoization_array_scores are filled left to right when we meet a word occurring after a previous one or at the beginning of the string s. The code should be autoesplicative, but if you need any explanation write me a comment, please.
As a plus, I associated a score to each word (here is 1 for simplicity) that allows you to distinguish between the different solutions. For instance, if you associate to each word an importance score, you will end up with the tokenization with the greatest score. In the code above, the tokenization with the highest number of words.
Extended version: I testing over the wordDict with some if there is one of the worde that beginns at the test-string (indexOf==0). If so I shorten the string about the length of the word and call the function recursivly with the shortened string. Otherwise the string is not splitable and I return false. I go this way on till an error occurs or the length of the string is 0 and I win because everything goes allright.
Remark: The error when the WordBreak is not clearly like with s= "cars" wordDict = ["car","ca","rs"] is now fixed. For this I calling in the some-methode the algorithm recursivly. So if one way stops before ending I go backwards and search for alternatives till I found one or there is no possibility left.
Remarks to; array.some
In an array.forEach there can't used a break without using some ugly tricks (like try...catch and throwing an error), so I could use the classic variant of the for-loop. But there exists the array.some method this loops like a forEach-loop but there had only one of the elements to be return true so the result is true.
Example:
const array = [1, 2, 3, 4, 5];
// checks whether an element is even
const even = (element) => element % 2 === 0;
console.log(array.some(even));
Here is the code of the working algorithm.
var wordBreak = function(s, wordDict) {
if (!wordDict || wordDict.length === 0) return false;
while (s.length > 0) {
let test = wordDict.some( (word,index) => {
if (s.indexOf(word)===0) {
s_new = s.substr(word.length);
return wordBreak(s_new, wordDict);
}
});
if (!test ) return false;
s=s_new;
}
if (s.length === 0) return true;
}
s = "leetcode"; wordDict = ["leet", "code"];
console.log(wordBreak(s, wordDict));
s = "applepenapple"; wordDict = ["apple", "pen"];
console.log(wordBreak(s, wordDict));
s= "cars"; wordDict = ["car","ca","rs"];
console.log(wordBreak(s, wordDict));
function wordBreak(dict, str){
if (!str){
return true;
}
for (const word of dict){
if (str.startsWith(word)){
return wordBreak(dict, str.substring(word.length, str.length))
}
}
return false;
}
You could also probably optimize the loop over dict by pre-sorting the array and using binary search, but hopefully this gets the point across.
If you'd be looking for a Dynamic Programming solution, we'd use an array for recording, and then we'd loop through and keep track of the word.
This'll pass through in JavaScript:
const wordBreak = function(s, wordDict) {
const len = s.length
const dp = new Array(len + 1).fill(false)
dp[0] = true
for (let i = 1; i < len + 1; i++) {
for (let j = 0; j < i; j++) {
if (dp[j] === true && wordDict.includes(s.slice(j, i))) {
dp[i] = true
break
}
}
}
return dp[s.length]
}
In Python, we would have used a list (which is similar to an array of JavaScript) with the same size as our string:
class Solution:
def wordBreak(self, s, words):
dp = [False] * len(s)
for i in range(len(s)):
for word in words:
k = i - len(word)
if word == s[k + 1:i + 1] and (dp[k] or k == -1):
dp[i] = True
return dp[-1]
Similarly in Java, we'd have used a boolean[]:
public final class Solution {
public static final boolean wordBreak(
String s,
List<String> words
) {
if (s == null || s.length() == 0) {
return false;
}
final int len = s.length();
boolean[] dp = new boolean[len];
for (int i = 0; i < len; i++) {
for (int j = 0; j <= i; j++) {
final String sub = s.substring(j, i + 1);
if (words.contains(sub) && (j == 0 || dp[j - 1])) {
dp[i] = true;
break;
}
}
}
return dp[len - 1];
}
}
Here is LeetCode's DP solution:
public class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> wordDictSet=new HashSet(wordDict);
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[s.length()];
}
}
References
For additional details, please see the Discussion Board which you can find plenty of well-explained accepted solutions in there, with a variety of languages including efficient algorithms and asymptotic time/space complexity analysis1, 2.

JavaScript Regex - test for sets of four non-duplicate characters

I am trying to use Regex to test if a certain string contains only sets of four non-duplicate characters.
For example I would like to test string
acbdbcaddacb
which would return true as it can return
acbd
bcad
dacb
i.e. sets of four characters which have no duplicates even though the entire string does.
I have tried the following regex which does not work for example and I am not sure why:
/^(?:(?:([a-d])(?!.{0,2}\1))(?:([a-d])(?!.{0,1}\1))(?:([a-d])(?!\1))[a-d])+$/
Any solutions?
Thank you
You're close. Your current regex is only checking if the 2nd - 4th letters in each group match the 1st. I believe /^(?:(?:([a-d])(?!.{0,2}\1))(?:([a-d])(?!.{0,1}\1|\2))(?:([a-d])(?!\1|\2|\3))[a-d])+$/ should work... or at least it's getting closer to correct I'm not sure if I left out some edge cases but it seems to be working for my test strings
Try this :
function check(str) {
var len = str.length; // check string length
if (len % 4 == 0) { // pass if divided by 4 == true
var arr = str.match(/.{4}/g); // make the in array
var res = [];
for (i = 0; i < arr.length; i++) {
if (arr[i].match(/^(?:([a-zA-Z])(?!.*\1))*$/)) {
res.push(arr[i]); // push if passed regex
}
}
if (arr.length === res.length) { // if they same that means true
console.log("true");
} else {
console.log("false");
}
} else {
console.log("false");
}
}
var str1 = "acbdbcaddacb";
check(str1); // true
var str2 = "aabbccdd";
check(str2); // false
var str3 = "abcde";
check(str3); // false
var str4 = "abcdabcdabcdabcd";
check(str4); // true
var str5 = "abcdabcdabcdabc4";
check(str5); // false

How to compare Palindromes

Not sure what i did wrong. I'm trying to compare 2 strings to see if they are Palindromes
function palindrome(str) {
var rem = str.replace(/\s/g, "");
var a = rem.split("");
var b = a.reverse();
for(var i = 0; i < rem.length; i++){
if (b[i] == a[i]){
return true;
}
return false;
}
}
palindrome("not a doctor"); //this should show false, but it's showing true
The reverse method transposes the elements of the calling array object in place, mutating the array, and returning a reference to the array.
Source
That's why you get true. Seems your a and b variables point to the same object.
By the way, your approach seems somewhat flawed as others have pointed out bellow. So, a better version of solution to your task could be (not properly tested):
function isPalindrome(input) {
var str = input.replace(/\s/g, "").toLowerCase();
var left = 0, right = str.length - 1;
while( left <= right) {
if(str[left] !== str[right]) return false;
left++; right--;
}
return true;
}
console.log(isPalindrome("your string")); // false
console.log(isPalindrome("Drawn onward")); //true
The idea is that you compare the corresponding symbols on both ends of your modified (without spaces and lowercased) string. If they don't match at some point, so this is not a palindrome.
There are a few problems with your code.
Problem 1: You are using reverse method which mutate the original array (See the docs on reverse). So variables a and b would have the same value, that is the reversed string of the original array. What you can do instead is create a fresh new array and assign it to the variable b like so:
var b = [].concat(a).reverse();
Problem 2: You forgot to check ALL of the letters in the string. You are returning your function way too early. For example, for the input string 'aada', which is not a palindrome it will return true. This is because, your function exits as soon as evaluates the similarity of the first string of both arrays. To fix this you could do something like this:
function palindrome(str) {
var rem = str.replace(/\s/g, "");
var a = rem.split("");
var b = [].concat(a).reverse();
for(var i = 0; i < rem.length; i++){
if (b[i] !== a[i]){
return false;
}
}
return true
}
You can even further optimise your function like this:
function palindrome(str) {
const len = str.length;
const halfLen = len/2;
for (let i = 0; i < halfLen; i++) {
if (str[i] !== str[len - 1 - i]) return false;
}
return true;
}
Palindrome strings read the same backwards and forwards, So you can make a comparison of the first and the last, second to second last etc until you reach the middle character.
Hope this helps.
As others have said, your a and b points to same object, so you need to clone it first.
Also you must not return true immediately, better way is to check for inequality and return true after the whole cycle ends.
function palindrome(str) {
var rem = str.replace(/\s/g, "");
var a = rem.split("");
var b = a.slice().reverse();
console.log(a, b);
for(var i = 0; i < rem.length; i++){
if (b[i] != a[i]){
return false;
}
}
return true;
}
console.log(palindrome("lol 1"));
Your code had two problems.
As noted by #curveball, your a and b variables are references to the same objects, as reverse modifies the original array.
Additionally, you are returning true as soon as the first element in the a array is equal to the first element of the b array. You must return false as soon as one element is different from another. But can only return true after comparing all the elements in the array.
function palindrome(str) {
var rem = str.replace(/\s/g, "");
var a = rem.split("");
var b = a.slice().reverse();
for(var i = 0; i < rem.length; i++){
if (b[i] !== a[i]){
return false;
}
}
return true;
}
palindrome("not a doctor");
Additionally, an alternative (and typical) algorithm for checking whether a string is a palindrome would be to compare (after removing blanks) first position to last one, second position to second from the end, etc. That way it is not necessary to clone (and reverse) the data.

Find smallest substring containing a given set of letters in a larger string

Say you have the following string:
FJKAUNOJDCUTCRHBYDLXKEODVBWTYPTSHASQQFCPRMLDXIJMYPVOHBDUGSMBLMVUMMZYHULSUIZIMZTICQORLNTOVKVAMQTKHVRIFMNTSLYGHEHFAHWWATLYAPEXTHEPKJUGDVWUDDPRQLUZMSZOJPSIKAIHLTONYXAULECXXKWFQOIKELWOHRVRUCXIAASKHMWTMAJEWGEESLWRTQKVHRRCDYXNT
LDSUPXMQTQDFAQAPYBGXPOLOCLFQNGNKPKOBHZWHRXAWAWJKMTJSLDLNHMUGVVOPSAMRUJEYUOBPFNEHPZZCLPNZKWMTCXERPZRFKSXVEZTYCXFRHRGEITWHRRYPWSVAYBUHCERJXDCYAVICPTNBGIODLYLMEYLISEYNXNMCDPJJRCTLYNFMJZQNCLAGHUDVLYIGASGXSZYPZKLAWQUDVNTWGFFY
FFSMQWUNUPZRJMTHACFELGHDZEJWFDWVPYOZEVEJKQWHQAHOCIYWGVLPSHFESCGEUCJGYLGDWPIWIDWZZXRUFXERABQJOXZALQOCSAYBRHXQQGUDADYSORTYZQPWGMBLNAQOFODSNXSZFURUNPMZGHTAJUJROIGMRKIZHSFUSKIZJJTLGOEEPBMIXISDHOAIFNFEKKSLEXSJLSGLCYYFEQBKIZZTQQ
XBQZAPXAAIFQEIXELQEZGFEPCKFPGXULLAHXTSRXDEMKFKABUTAABSLNQBNMXNEPODPGAORYJXCHCGKECLJVRBPRLHORREEIZOBSHDSCETTTNFTSMQPQIJBLKNZDMXOTRBNMTKHHCZQQMSLOAXJQKRHDGZVGITHYGVDXRTVBJEAHYBYRYKJAVXPOKHFFMEPHAGFOOPFNKQAUGYLVPWUJUPCUGGIXGR
AMELUTEPYILBIUOCKKUUBJROQFTXMZRLXBAMHSDTEKRRIKZUFNLGTQAEUINMBPYTWXULQNIIRXHHGQDPENXAJNWXULFBNKBRINUMTRBFWBYVNKNKDFR
I'm trying to find the smallest substring containing the letters ABCDA.
I tried a regex approach.
console.log(str.match(/[A].*?[B].*?[C].*?[D].*?[A]/gm).sort((a, b) => a.length - b.length)[0]);
This works, but it only find strings where ABCDA appear (in that order). Meaning it won't find substring where the letters appear in a order like this: BCDAA
I'm trying to change my regex to account for this. How would I do that without using | and type out all the different cases?
You can't.
Let's consider a special case: Assume the letters you are looking for are A, A, and B. At some point in your regexp there will certainly be a B. However, the parts to the left and to the right of the B are independent of each other, so you cannot refer from one to the other. How many As are matched in the subexpression to the right of the B depends on the number of As being already matched in the left part. This is not possible with regular expressions, so you will have to unfold all the different orders, which can be many!
Another popular example that illustrates the problem is to match opening brackets with closing brackets. It's not possible to write a regular expression asserting that in a given string a sequence of opening brackets is followed by a sequence of closing brackets of the same length. The reason for this is that to count the brackets you would need a stack machine in contrast to a finite state machine but regular expressions are limited to patterns that can be matched using FSMs.
This algorithm doesn't use a regex, but found both solutions as well.
var haystack = 'FJKAUNOJDCUTCRHBYDLXKEODVBWTYPTSHASQQFCPRMLDXIJMYPVOHBDUGSMBLMVUMMZYHULSUIZIMZTICQORLNTOVKVAMQTKHVRIFMNTSLYGHEHFAHWWATLYAPEXTHEPKJUGDVWUDDPRQLUZMSZOJPSIKAIHLTONYXAULECXXKWFQOIKELWOHRVRUCXIAASKHMWTMAJEWGEESLWRTQKVHRRCDYXNTLDSUPXMQTQDFAQAPYBGXPOLOCLFQNGNKPKOBHZWHRXAWAWJKMTJSLDLNHMUGVVOPSAMRUJEYUOBPFNEHPZZCLPNZKWMTCXERPZRFKSXVEZTYCXFRHRGEITWHRRYPWSVAYBUHCERJXDCYAVICPTNBGIODLYLMEYLISEYNXNMCDPJJRCTLYNFMJZQNCLAGHUDVLYIGASGXSZYPZKLAWQUDVNTWGFFYFFSMQWUNUPZRJMTHACFELGHDZEJWFDWVPYOZEVEJKQWHQAHOCIYWGVLPSHFESCGEUCJGYLGDWPIWIDWZZXRUFXERABQJOXZALQOCSAYBRHXQQGUDADYSORTYZQPWGMBLNAQOFODSNXSZFURUNPMZGHTAJUJROIGMRKIZHSFUSKIZJJTLGOEEPBMIXISDHOAIFNFEKKSLEXSJLSGLCYYFEQBKIZZTQQXBQZAPXAAIFQEIXELQEZGFEPCKFPGXULLAHXTSRXDEMKFKABUTAABSLNQBNMXNEPODPGAORYJXCHCGKECLJVRBPRLHORREEIZOBSHDSCETTTNFTSMQPQIJBLKNZDMXOTRBNMTKHHCZQQMSLOAXJQKRHDGZVGITHYGVDXRTVBJEAHYBYRYKJAVXPOKHFFMEPHAGFOOPFNKQAUGYLVPWUJUPCUGGIXGRAMELUTEPYILBIUOCKKUUBJROQFTXMZRLXBAMHSDTEKRRIKZUFNLGTQAEUINMBPYTWXULQNIIRXHHGQDPENXAJNWXULFBNKBRINUMTRBFWBYVNKNKDFR';
var needle = 'ABCDA'; // the order of letters doesn't matter
var letters = {};
needle.split('').forEach(function(ch) {
letters[ch] = letters[ch] || 0;
letters[ch]++;
});
var shortestSubstringLength = haystack.length;
var shortestSubstrings = []; // storage for found substrings
var startingPos = 0;
var length;
var currentPos;
var notFound;
var letterKeys = Object.keys(letters); // unique leters
do {
lettersLeft = JSON.parse(JSON.stringify(letters)); // copy letters count object
notFound = false;
posStart = haystack.length;
posEnd = 0;
letterKeys.forEach(function(ch) {
currentPos = startingPos;
while (!notFound && lettersLeft[ch] > 0) {
currentPos = haystack.indexOf(ch, currentPos);
if (currentPos >= 0) {
lettersLeft[ch]--;
posStart = Math.min(currentPos, posStart);
posEnd = Math.max(currentPos, posEnd);
currentPos++;
} else {
notFound = true;
}
}
});
if (!notFound) {
length = posEnd - posStart + 1;
startingPos = posStart + 1; // starting position for next iteration
}
if (!notFound && length === shortestSubstringLength) {
shortestSubstrings.push(haystack.substr(posStart, length));
}
if (!notFound && length < shortestSubstringLength) {
shortestSubstrings = [haystack.substr(posStart, length)];
shortestSubstringLength = length;
}
} while (!notFound);
console.log(shortestSubstrings);
Maybe not as clear as using regex could be (well, for me regex are never really clear :D ) you can use brute force (not so brute)
Create an index of "valid" points of your string (those with the letters you want) and iterate with a double loop over it getting substrings containing at least 5 of those points, checking that they are valid solutions. Maybe not the most efficient way, but easy to implement, to understand, and probably to optimize.
var haystack="UGDVWUDDPRQLUZMSZOJPSIKAIHLTONYXAULECXXKWFQOIKELWOHRVRUCXIAASKHMWTMAJEWGEESLWRTQKVHRRCDYXNTLDSUPXMQTQDFAQAPYBGXPOLOCLFQNGNKPKOBHZWHRXAWAWJKMTJSLDLNHMUGVVOPSAMRUJEYUOBPFNEHPZZCLPNZKWMTCXERPZRFKSXVEZTYCXFRHRGEITWHRRYPWSVAYBUHCERJXDCYAVICPTNBGIODLYLMEYLISEYNXNMCDPJJRCTLYNFMJZQNCLAGHUDVLYIGASGXSZYPZKLAWQUDVNTWGFFYFFSMQWUNUPZRJMTHACFELGHDZEJWFDWVPYOZEVEJKQWHQAHOCIYWGVLPSHFESCGEUCJGYLGDWPIWIDWZZXRUFXERABQJOXZALQOCSAYBRHXQQGUDADYSORTYZQPWGMBLNAQOFODSNXSZFURUNPMZGHTAJUJROIGMRKIZHSFUSKIZJJTLGOEEPBMIXISDHOAIFNFEKKSLEXSJLSGLCYYFEQBKIZZTQQXBQZAPXAAIFQEIXELQEZGFEPCKFPGXULLAHXTSRXDEMKFKABUTAABSLNQBNMXNEPODPGAORYJXCHCGKECLJVRBPRLHORREEIZOBSHDSCETTTNFTSMQPQIJBLKNZDMXOTRBNMTKHHCZQQMSLOAXJQKRHDGZVGITHYGVDXRTVBJEAHYBYRYKJAVXPOKHFFMEPHAGFOOPFNKQAUGYLVPWUJUPCUGGIXGR";
var needle="ABCD";
var size=haystack.length;
var candidate_substring="";
var minimal_length=size;
var solutions=new Array();
var points=Array();
for(var i=0;i<size;i++){
if(needle.indexOf(haystack[i])>-1) points.push(i);
}
var limit_i= points.length-4;
var limit_k= points.length;
for (var i=0;i<limit_i;i++){
for(var k=i;k<limit_k;k++){
if(points[k]-points[i]+1<=minimal_length){
candidate_substring=haystack.substr(points[i],points[k]-points[i]+1);
if(is_valid(candidate_substring)){
solutions.push(candidate_substring);
if(candidate_substring.length < minimal_length) minimal_length=candidate_substring.length;
}
}
}
}
document.write('<p>Solution length:'+minimal_length+'<p>');
for(var i=0;i<solutions.length;i++){
if(solutions[i].length<=minimal_length) document.write('<p>Solution:'+solutions[i]+'<p>');
}
function is_valid(candidate_substring){
//verify we've got all characters
for(var j=0;j<candidate_substring.length;j++){
if(candidate_substring.indexOf(needle.charAt(j))<0) return false;
}
//...and verify we have two "A"
if(candidate_substring.indexOf("A")==candidate_substring.lastIndexOf("A")) return false;
return true;
}
Just had this problem in an interview as a coding assignment and came up with another solution, (it's not as optimal as the one above but maybe it's easier to understand).
function MinWindowSubstring(strArr) {
const N = strArr[0];
const K = strArr[1];
const letters = {};
K.split('').forEach( (character) => {
letters[character] = letters[character] ? letters[character] + 1 : 1;
});
let possibleSequencesList = [];
const letterKeys = Object.keys(letters);
for(let i=0; i< N.length; i++) {
const char = N[i];
if (new String(letterKeys).indexOf(char) !== -1) {
// found a character in the string
// update all previus sequences
possibleSequencesList.forEach((seq) => {
if(!seq.sequenceComplete) {
seq[char] = seq[char]-1;
seq.lastIndex = i;
// check if sequence is complete
var sequenceComplete = true;
letterKeys.forEach( (letter) => {
if(seq[letter] > 0) {
sequenceComplete = false;
}
});
seq.sequenceComplete = sequenceComplete
}
})
// create a new sequence starting from it
const newSeq = {
startPoint: i,
lastIndex: i,
sequenceComplete: false,
...letters
}
newSeq[char] = newSeq[char]-1;
possibleSequencesList.push(newSeq);
}
}
// cleanup sequences
let sequencesList = possibleSequencesList.filter(sequence => sequence.sequenceComplete);
let output = [];
let minLength = N.length;
// find the smalles one
sequencesList.forEach( seq => {
if( (seq.lastIndex - seq.startPoint) < minLength) {
minLength = seq.lastIndex - seq.startPoint;
output = N.substring(seq.startPoint, seq.lastIndex + 1);
}
})
return output;
}

Javascript in list

What's the easiest way to check to see if a number is in a comma delimited list?
console.log(provider[cardType]);
//returns: Object { name="visa", validLength="16,13", prefixRegExp=}
if (ccLength == 0 || (cardType > 0 && ccLength < provider[cardType].validLength)) {
triggerNotification('x', 'Your credit card number isn\'t long enough');
return false;
} else {
if ($('.credit-card input[name="cc_cvv"]').val().length < 3) {
triggerNotification('x', 'You must provide a CCV');
return false;
}
Seems similar to this SO question.
Just .split() the CSV and use inArray.
Not sure how your sample code relates to checking to see if a number is in a comma delimited list...
Also not sure if this is the easiest way, but it's what springs to mind:
<script type="text/javascript">
var myNumbers = "1,2,3,4,5";
var myArray = myNumbers.split( ',' );
// looking for "4"
for ( var i=0; i<myArray.length; i++ ) {
if (myArray[i] == 4) {
alert('Found it!');
break;
}
}
I do not see where you have a significant comma delimited list in the script you posted.
The fastest way could be something like
var csvList ="a,b,c,d,e,f,g,h";
var testList = ","+csvList+",";
var needle = "f";
alert(testList.indexOf(","+needle+",")!=-1)
just to be different ;)
If it's just a list of comma separated numbers with nothing fancy, you can just use the split method:
var numbers = list.split(",");
This will give you an array of all of the numbers in the list. Checking whether a number is in an array is trivial.
Native JavaScript and therefore cross-browser compliant. Some frameworks provide functions that do this for you, but you don't get more basic than the following.
var numbers = list.split(",");
var count = numbers.length;
var exists = false;
for (var i = 0; i < count; ++i) {
if (numbers[i] == anumber) {
exists = true;
break;
}
}
From your sample, I assume your question was "How do I see if a number is within a range of two values specified by a single-comma-delimited string?":
function inRange( number, stringRange ){
var minmax = stringRange.split(',');
minmax[0] = minmax[0]*1; //convert to number
minmax[1] = minmax[1]*1; //convert to number
minmax.sort(); // Ensure [0] is the min
return number>=minmax[0] && number<=minmax[1];
}
Try this one...
console.log(provider[cardType]); //returns: Object { name="visa", validLength="16,13", prefixRegExp=}
var regExp = new RegExp(",?" + ccLength + ",?");
if (ccLength == 0 || (cardType > 0 && !regExp.test(provider[cardType].validLength)))
{
triggerNotification('x', 'Your credit card number isn\'t long enough');
return false;
}
else
{
if ($('.credit-card input[name="cc_cvv"]').val().length < 3)
{
triggerNotification('x', 'You must provide a CCV');
return false;
}
}

Categories