From 308b022b03a2bcdaba99ff38667b95ccd7b686f8 Mon Sep 17 00:00:00 2001 From: Aditya Parmar <58773630+Aditya1942@users.noreply.github.com> Date: Wed, 3 Nov 2021 09:33:20 +0530 Subject: [PATCH] merge: Sliding window (#833) * new algorithm 'Sliding-Window' added with example 'Longest Substring Without Repeating Characters' * new example of sliding window 'Permutation in String' added * chore: add `ignore_words_list` * sliding-window moved into Dynamic-programming directory Co-authored-by: Rak Laptudirm --- .github/workflows/Codespell.yml | 2 +- ...gestSubstringWithoutRepeatingCharacters.js | 49 +++++++++++++++ .../Sliding-Window/PermutationinString.js | 59 +++++++++++++++++++ ...ubstringWithoutRepeatingCharacters.test.js | 11 ++++ .../test/PermutationinString.test.js | 10 ++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 Dynamic-Programming/Sliding-Window/LongestSubstringWithoutRepeatingCharacters.js create mode 100644 Dynamic-Programming/Sliding-Window/PermutationinString.js create mode 100644 Dynamic-Programming/Sliding-Window/test/LongestSubstringWithoutRepeatingCharacters.test.js create mode 100644 Dynamic-Programming/Sliding-Window/test/PermutationinString.test.js diff --git a/.github/workflows/Codespell.yml b/.github/workflows/Codespell.yml index 0c421e95b..487167115 100644 --- a/.github/workflows/Codespell.yml +++ b/.github/workflows/Codespell.yml @@ -10,4 +10,4 @@ jobs: with: # file types to ignore skip: "*.json,*.yml,DIRECTORY.md,PermutateString.test.js,SubsequenceRecursive.js" - + ignore_words_list: "ba" diff --git a/Dynamic-Programming/Sliding-Window/LongestSubstringWithoutRepeatingCharacters.js b/Dynamic-Programming/Sliding-Window/LongestSubstringWithoutRepeatingCharacters.js new file mode 100644 index 000000000..9b3822eec --- /dev/null +++ b/Dynamic-Programming/Sliding-Window/LongestSubstringWithoutRepeatingCharacters.js @@ -0,0 +1,49 @@ +/** + * @name The-Sliding-Window Algorithm is primarily used for the problems dealing with linear data structures like Arrays, Lists, Strings etc. + * These problems can easily be solved using Brute Force techniques which result in quadratic or exponential time complexity. + * Sliding window technique reduces the required time to linear O(n). + * @see [The-Sliding-Window](https://www.geeksforgeeks.org/window-sliding-technique/) + */ + +/** + * @function LongestSubstringWithoutRepeatingCharacters + * @description Get the length of the longest substring without repeating characters + * @param {String} s - The input string + */ +export function LongestSubstringWithoutRepeatingCharacters (s) { + let maxLength = 0 + let start = 0 + let end = 0 + const map = {} + while (end < s.length) { + if (map[s[end]] === undefined) { + map[s[end]] = 1 + maxLength = Math.max(maxLength, end - start + 1) + end++ + } else { + while (s[start] !== s[end]) { + delete map[s[start]] + start++ + } + delete map[s[start]] + start++ + } + } + return maxLength +} + +// Example 1: +// Input: s = "abcabcbb" +// Output: 3 +// Explanation: The answer is "abc", with the length of 3. + +// Example 2: +// Input: s = "bbbbb" +// Output: 1 +// Explanation: The answer is "b", with the length of 1. + +// Example 3: +// Input: s = "pwwkew" +// Output: 3 +// Explanation: The answer is "wke", with the length of 3. +// Notice that the answer must be a substring, "pwke" is a subsequence and not a substring. diff --git a/Dynamic-Programming/Sliding-Window/PermutationinString.js b/Dynamic-Programming/Sliding-Window/PermutationinString.js new file mode 100644 index 000000000..ddbb766af --- /dev/null +++ b/Dynamic-Programming/Sliding-Window/PermutationinString.js @@ -0,0 +1,59 @@ +/** + * @name The-Sliding-Window Algorithm is primarily used for the problems dealing with linear data structures like Arrays, Lists, Strings etc. + * These problems can easily be solved using Brute Force techniques which result in quadratic or exponential time complexity. + * Sliding window technique reduces the required time to linear O(n). + * @see [The-Sliding-Window](https://www.geeksforgeeks.org/window-sliding-technique/) + */ +/** + * @function PermutationinString + * @description Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise. + * @param {String} s1 - The input string + * @param {String} s2 - The input string + * @return {boolean} - Returns true if s2 contains a permutation of s1, or false otherwise. + */ + +export function PermutationinString (s1, s2) { + if (s1.length > s2.length) return false + let start = 0 + let end = s1.length - 1 + const s1Set = SetHash() + const s2Set = SetHash() + for (let i = 0; i < s1.length; i++) { + s1Set[s1[i]]++ + s2Set[s2[i]]++ + } + if (equals(s1Set, s2Set)) return true + while (end < s2.length - 1) { + if (equals(s1Set, s2Set)) return true + end++ + console.log(s2[start], s2[end], equals(s1Set, s2Set)) + const c1 = s2[start] + const c2 = s2[end] + if (s2Set[c1] > 0) s2Set[c1]-- + s2Set[c2]++ + start++ + if (equals(s1Set, s2Set)) return true + } + return false +} +function equals (a, b) { + return JSON.stringify(a) === JSON.stringify(b) +} + +function SetHash () { + const set = new Set() + const alphabets = 'abcdefghijklmnopqrstuvwxyz' + for (let i = 0; i < alphabets.length; i++) { + set[alphabets[i]] = 0 + } + return set +} + +// Example 1: +// Input: s1 = "ab", s2 = "eidbaooo" +// Output: true +// Explanation: s2 contains one permutation of s1 ("ba"). + +// Example 2: +// Input: s1 = "ab", s2 = "eidboaoo" +// Output: false diff --git a/Dynamic-Programming/Sliding-Window/test/LongestSubstringWithoutRepeatingCharacters.test.js b/Dynamic-Programming/Sliding-Window/test/LongestSubstringWithoutRepeatingCharacters.test.js new file mode 100644 index 000000000..3a77a9208 --- /dev/null +++ b/Dynamic-Programming/Sliding-Window/test/LongestSubstringWithoutRepeatingCharacters.test.js @@ -0,0 +1,11 @@ +import { LongestSubstringWithoutRepeatingCharacters } from '../LongestSubstringWithoutRepeatingCharacters.js' + +describe('LongestSubstringWithoutRepeatingCharacters', () => { + it('should return longest substring without repeating characters', () => { + expect(LongestSubstringWithoutRepeatingCharacters('abcabcbb')).toEqual(3) + expect(LongestSubstringWithoutRepeatingCharacters('bbbbb')).toEqual(1) + expect(LongestSubstringWithoutRepeatingCharacters('pwwkew')).toEqual(3) + expect(LongestSubstringWithoutRepeatingCharacters('a')).toEqual(1) + expect(LongestSubstringWithoutRepeatingCharacters('')).toEqual(0) + }) +}) diff --git a/Dynamic-Programming/Sliding-Window/test/PermutationinString.test.js b/Dynamic-Programming/Sliding-Window/test/PermutationinString.test.js new file mode 100644 index 000000000..8ffe9accc --- /dev/null +++ b/Dynamic-Programming/Sliding-Window/test/PermutationinString.test.js @@ -0,0 +1,10 @@ +import { PermutationinString } from '../PermutationinString.js' + +describe('PermutationinString', () => { + it("should return true if one of s1's permutations is the substring of s2", () => { + expect(PermutationinString('ab', 'eidbaooo')).toEqual(true) + expect(PermutationinString('abc', 'bcab')).toEqual(true) + expect(PermutationinString('ab', 'eidboaoo')).toEqual(false) + expect(PermutationinString('abc', '')).toEqual(false) + }) +})