diff --git a/chapter01/1.1 - Is Unique/isUnique.js b/chapter01/1.1 - Is Unique/isUnique.js index 136496c..ec726b2 100644 --- a/chapter01/1.1 - Is Unique/isUnique.js +++ b/chapter01/1.1 - Is Unique/isUnique.js @@ -1,5 +1,7 @@ +'use strict'; + var allUniqueChars = function(string) { - + // O(n^2) approach, no additional data structures used // for each character, check remaining characters for duplicates for (var i = 0; i < string.length; i++) { @@ -12,5 +14,53 @@ var allUniqueChars = function(string) { return true; // if no match, return true }; + + +var allUniqueChars2 = function(string) { + // O(n) approach and Space complexity O(1) + // Assume to use ASCII character set (7 bit, 128 positions) + // If we assume to use exended ASCII (8 bit), then check 256 positions. + + // If the string length exceeds the number of unique characters in the alphabet, return false + if (string.length > 128) return false; + const charactersArray = new Array(128); + for (let i = 0; i < string.length; i++) { + const val = string.charCodeAt(i); + if (charactersArray[val]) { + return false; + } + charactersArray[val] = true; + } + return true; +} + + /* TESTS */ -// log some tests here \ No newline at end of file +console.log(allUniqueChars('abcd'), true); +console.log(allUniqueChars('abab'), false); +console.log(allUniqueChars2('abcd'), true); +console.log(allUniqueChars2('abab'), false); + + +/* TESTS - Performance check */ + +var buildReadableASCII = function(){ + //Creates a string with readable ASCII characters (from position 32, and to make the code more readable we leave also the last one, 'DEL') + + let temp = ''; + for (var i = 32; i < 128; ++i) { + temp += String.fromCharCode(i); + } + return temp; +} + +const testString = buildReadableASCII(); +console.log('Readable ASCII' + testString); + +console.time('basic'); +console.log(allUniqueChars(testString), true); +console.timeEnd('basic'); + +console.time('new'); +console.log(allUniqueChars2(testString), true); +console.timeEnd('new'); diff --git a/chapter01/1.2 - Check Perm/checkPermute.js b/chapter01/1.2 - Check Perm/checkPermute.js index 0cb0931..1c19bfb 100644 --- a/chapter01/1.2 - Check Perm/checkPermute.js +++ b/chapter01/1.2 - Check Perm/checkPermute.js @@ -1,9 +1,15 @@ +/** + * Check Permutation + * Given two strings, write a method to decide if one is a + * permutation of the other. We should understand if the permutation comparison + *is case sensitive. Additionally, we should ask if whitespace is significant + **/ var checkPermute = function(stringOne, stringTwo) { // if different lengths, return false if (stringOne.length !== stringTwo.length) { return false; - // else sort and compare - // (doesnt matter how it's sorted, as long as it's sorted the same way) + // else sort and compare + // (doesnt matter how it's sorted, as long as it's sorted the same way) } else { var sortedStringOne = stringOne.split('').sort().join(''); var sortedStringTwo = stringTwo.split('').sort().join(''); @@ -16,4 +22,4 @@ console.log(checkPermute('aba', 'aab'), true); console.log(checkPermute('aba', 'aaba'), false); -console.log(checkPermute('aba', 'aa'), false); \ No newline at end of file +console.log(checkPermute('aba', 'aa'), false); diff --git a/chapter01/1.4 - PalinPerm/palinPerm.js b/chapter01/1.4 - PalinPerm/palinPerm.js index ca46496..f7954cd 100644 --- a/chapter01/1.4 - PalinPerm/palinPerm.js +++ b/chapter01/1.4 - PalinPerm/palinPerm.js @@ -17,9 +17,10 @@ var palinPerm = function(string) { // check that all chars are even count, except for one exception Object.keys(chars).forEach((char) => { if (chars[char] % 2 > 0) { - // if more than one exception, return false + // if more than one exception, return false if (mulligan) { - isPerm = false; // return in a forEach statment doesn't flow out of function scope + isPerm = false; // return in a forEach statment doesn't flow out of + // function scope } else { mulligan = true; } @@ -31,4 +32,58 @@ var palinPerm = function(string) { // TESTS console.log(palinPerm('Tact Coa'), 'true'); -console.log(palinPerm('Tact boa'), 'false'); \ No newline at end of file +console.log(palinPerm('Tact boa'), 'false'); + + + +/** + * If you find more than one character odd, the string is not palindrome + * This algorithm takes O ( N) time, where N is the length of the string. + */ +var palinPerm2 = function(string) { + var table = buildTable(string); + return checkOneOdd(table); + + function checkOneOdd(table) { + isOneOdd = false; + + for (var i of table) { + if (i % 2 == 1) { + if (isOneOdd) return false; + isOneOdd = true + } + } + return true; + } + + function getCharacterCode(item) { + var a = (new String('a')).charCodeAt(0); + var z = (new String('z')).charCodeAt(0); + var currentValue = (new String(item)).charCodeAt(0); + + if ((a <= currentValue) && (currentValue <= z)) { + return currentValue - a; + } + return -1; + } + + function buildTable(string) { + var arr = []; + for (var i = 0; i < string.length; i++) { + var position = getCharacterCode(string[i]); + if (position !== -1) { + if (arr[position] === undefined) { + arr[position] = 1 + } else { + arr[position] += 1; + } + } + } + return arr; + } +}; + +console.log('----'); +console.log(palinPerm2('abc'), false); +console.log(palinPerm2('abcab'), true); +console.log(palinPerm2('abcdabc'), true); diff --git a/chapter01/1.5 - OneAway/oneAway.js b/chapter01/1.5 - OneAway/oneAway.js index 1e66a89..3123fbf 100644 --- a/chapter01/1.5 - OneAway/oneAway.js +++ b/chapter01/1.5 - OneAway/oneAway.js @@ -5,15 +5,15 @@ var oneAway = function(string1, string2) { return false; } else { var mulligan = false; - var fP = 0; // first Pointer - var sP = 0; // second Pointer + var fP = 0; // first Pointer + var sP = 0; // second Pointer while (fP < first.length) { if (first[fP] !== second[sP]) { if (mulligan) { return false; } else { mulligan = true; - sP++; // second length is longer + sP++; // second length is longer } } else { fP++; @@ -29,14 +29,14 @@ var oneAway = function(string1, string2) { return false; } else { var mulligan = false; - var fP = 0; // first Pointer - var sP = 0; // second Pointer + var fP = 0; // first Pointer + var sP = 0; // second Pointer while (fP < first.length) { if (first[fP] !== second[sP]) { if (mulligan) { - return false; // more than one mismatch + return false; // more than one mismatch } else { - mulligan = true; // use up mulligan + mulligan = true; // use up mulligan } } fP++; @@ -48,12 +48,8 @@ var oneAway = function(string1, string2) { // insert a char for str1 -> remove a char for str2 // check one diff - // console log checks - // console.log(string1, string2, 'checkMiss', checkOneMissing(string1, string2)); - // console.log(string2, string1, 'checkMiss', checkOneMissing(string2, string1)); - // console.log(string1, string2, 'checkDiff', checkOneDiff(string1, string2)); - - return checkOneMissing(string1, string2) || checkOneMissing(string2, string1) || checkOneDiff(string1, string2); + return checkOneMissing(string1, string2) || + checkOneMissing(string2, string1) || checkOneDiff(string1, string2); }; @@ -61,4 +57,66 @@ var oneAway = function(string1, string2) { console.log(oneAway('pale', 'ple'), true); console.log(oneAway('pales', 'pale'), true); console.log(oneAway('pale', 'bale'), true); -console.log(oneAway('pale', 'bake'), false); \ No newline at end of file +console.log(oneAway('pale', 'bake'), false); + + + +console.log('----------------'); + +// There are three types of edits that can be performed on strings: insert a +// character, remove a character, or replace a character. Given two strings, +// write a function to check if they are one edit (or zero edits) away. EXAMPLE +// pale, ple -> true +// pales, pale -> true +// pale, bale -> true +// pale, bae -> false + +// This algorithm (and almost any reasonable algorithm) takes O ( n) time, where +// n is the length of the shorter string. + +function oneEditWay(string1, string2) { + if (string1.length === string2.length) { + return oneEditReplace(string1, string2); + } else if (string1.length + 1 === string2.length) { + return oneEditInsert(string1, string2); + } else if (string1.length == string2.length + 1) { + return oneEditInsert(string2, string1); + } +} + +function oneEditReplace(string1, string2) { + foundDifference = false; + + for (let i = 0; i < string1.length; i++) { + if (string1[i] !== string2[i]) { + if (foundDifference) return false; + foundDifference = true; + } + } + return foundDifference; +} + +/* Check if you can insert a character into sl to make s2. */ +function oneEditInsert(string1, string2) { + var indexS1, indexS2 = 0; + + while (indexS1 < string1.length && indexS2 < string2.length) { + if (string1[indexS1] !== string2[indexS2]) { + if (indexS1 != indexS2) { + return false; + } + indexS2++ + } else { + indexS1++; + indexS2++; + } + } + return true; +} + + +// Test +console.log(oneEditWay('pale', 'ple'), true); +console.log(oneEditWay('pales', 'pale'), true); +console.log(oneEditWay('pale', 'bale'), true); +console.log(oneEditWay('pale', 'bake'), false); diff --git a/chapter01/1.6 - String Compression/strComp.js b/chapter01/1.6 - String Compression/strComp.js index 2d0e776..c507246 100644 --- a/chapter01/1.6 - String Compression/strComp.js +++ b/chapter01/1.6 - String Compression/strComp.js @@ -5,7 +5,7 @@ var strComp = function(string) { var maxCount = 1; for (var i = 0; i < string.length; i++) { if (currChar !== string[i]) { - console.log(currChar, string[i], i); + // console.log(currChar, string[i], i); compressed = compressed + currChar + currCount; maxCount = Math.max(maxCount, currCount); currChar = string[i]; @@ -22,4 +22,46 @@ var strComp = function(string) { // Test console.log('aaaaaa', strComp('aaaaaa'), 'a6'); -console.log('aabcccccaaa', strComp('aabcccccaaa'), 'a2b1c5a3'); \ No newline at end of file +console.log('aabcccccaaa', strComp('aabcccccaaa'), 'a2b1c5a3'); + +// variant + +function compress(inputString) { + if (inputString.length <= checkCompressionLength(inputString)) + return inputString; + + function doCompression(inputString) { + countConsecutive = 0; + compressString = ''; + for (var i = 0; i < inputString.length; i++) { + countConsecutive++; + if (inputString[i] !== inputString[i + 1]) { + compressString += inputString[i]; + compressString += countConsecutive; + countConsecutive = 0; + } + } + return compressString; + } + + + function checkCompressionLength(inputString) { + countCompressedLength = 0; + countConsecutive = 0; + + for (var i = 0; i < inputString.length; i++) { + countConsecutive++; + if (inputString[i] !== inputString[i + 1]) { + countConsecutive = 0; + countCompressedLength += (1 + countConsecutive.toString().length); + } + } + return countCompressedLength; + } + return doCompression(inputString); +} + + +console.log('aaaaaa', compress('aaaaaa'), 'a6'); +console.log('abc', compress('abc'), 'abc'); +console.log('aabcccccaaa', compress('aabcccccaaa'), 'a2b1c5a3'); diff --git a/chapter01/1.7 - Rotate Matrix/rotateMatrix.js b/chapter01/1.7 - Rotate Matrix/rotateMatrix.js index b0e3e28..0d9631f 100644 --- a/chapter01/1.7 - Rotate Matrix/rotateMatrix.js +++ b/chapter01/1.7 - Rotate Matrix/rotateMatrix.js @@ -9,8 +9,8 @@ var rotateMatrix = function(matrix) { var fromPixel; // first transformation - var toRow = row; // 0 - var toCol = col; // 1 + var toRow = row; // 0 + var toCol = col; // 1 var toPixel = matrix[row][col]; // Do rotational transformation 4 times @@ -36,12 +36,7 @@ var rotateMatrix = function(matrix) { /* TEST */ -var testMatrix = [ -[1, 2, 3, 4], -[0, 1, 2, 3], -[0, 0, 1, 2], -[1, 0, 0, 1] -]; +var testMatrix = [[1, 2, 3, 4], [0, 1, 2, 3], [0, 0, 1, 2], [1, 0, 0, 1]]; console.log('before:'); console.log(testMatrix[0]); @@ -57,6 +52,8 @@ console.log(testMatrix[1]); console.log(testMatrix[2]); console.log(testMatrix[3]); +console.log('\n\n\n'); + /* var edge = n - 1; @@ -101,8 +98,57 @@ position of 1 -> m[0][1] flow of iteration: i) start from top left corner and move diagonally down -ii) for each row, iterate pixels until edge - 1 +ii) for each row, iterate pixels until edge - 1 (pixel at edge would have been transformed by the first pixel) iii) at each pixel iteration, iterate through 4 sides iv) do iteration in place, i.e. store a temp pixel for moving things around -*/ \ No newline at end of file +*/ + + +// Variant + +var testMatrix = + [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; + + +function rotateMatrix2(matrix) { + var n = matrix[0].length; + if (n <= 0) return false; + + printMatrix(matrix); + + // layers + for (var x = 0; x < n / 2; x++) { + var first = x; + var last = n - 1 - x; + + for (var y = first; y < last; y++) { + var top = matrix[x][y]; + + // top = left + matrix[x][y] = matrix[n - 1 - y][x]; + + // left = bottom + matrix[n - 1 - y][x] = matrix[n - 1 - x][n - 1 - y]; + + // bottom = right + matrix[n - 1 - x][n - 1 - y] = matrix[y][n - 1 - x]; + + // right = top + matrix[y][n - 1 - x] = top; + } + } + printMatrix(matrix); +}; + + + +function printMatrix(matrix) { + length = matrix[0].length; + + for (var x = 0; x < length; x++) { + console.log(testMatrix[x]); + } +}; + +rotateMatrix2(testMatrix); diff --git a/chapter01/1.8 - Zero Matrix/zeroMatrix.js b/chapter01/1.8 - Zero Matrix/zeroMatrix.js index b03dd5d..0e738b8 100644 --- a/chapter01/1.8 - Zero Matrix/zeroMatrix.js +++ b/chapter01/1.8 - Zero Matrix/zeroMatrix.js @@ -2,21 +2,21 @@ var checkZeros = function(matrix) { var matrixHeight = matrix.length; var matrixWidth = matrix[0].length; - var rowsToZeroify = {}; // use hashtables to remove duplicates + var rowsToZeroify = {}; // use hashtables to remove duplicates var colsToZeroify = {}; + counter = 0; for (var i = 0; i < matrixHeight; i++) { for (var j = 0; j < matrixWidth; j++) { + counter++; if (matrix[i][j] === 0) { rowsToZeroify[i] = true; colsToZeroify[j] = true; } } } - return { - rowsToZeroify: rowsToZeroify, - colsToZeroify: colsToZeroify - }; + console.log(counter); + return {rowsToZeroify: rowsToZeroify, colsToZeroify: colsToZeroify}; }; var printMatrix = function(matrix) { @@ -33,7 +33,7 @@ var zeroifyCol = function(matrix, col) { var zeroifyCols = function(matrix, zeroScan) { for (var col in zeroScan.colsToZeroify) { - zeroifyCol(matrix, Number(col)); + zeroifyCol(matrix, Number(col)); } }; @@ -45,29 +45,25 @@ var zeroifyRow = function(matrix, row) { var zeroifyRows = function(matrix, zeroScan) { for (var row in zeroScan.rowsToZeroify) { - zeroifyRow(matrix, Number(row)); + zeroifyRow(matrix, Number(row)); } }; /* Main Function */ var zeroMatrix = function(matrix) { - - if(matrix.length === 0) { return; } + if (matrix.length === 0) { + return; + } var zeroScan = checkZeros(matrix); zeroifyCols(matrix, zeroScan); zeroifyRows(matrix, zeroScan); - }; // Testing var testMatrix = [ - [1, 1, 1, 1], - [1, 1, 1, 1], - [1, 0, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1], + [1, 1, 1, 1], [1, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]; @@ -87,4 +83,4 @@ printMatrix(testMatrix); // [1, 0, 1, 1], // [1, 0, 1, 1], // [1, 0, 1, 1] -// ] \ No newline at end of file +// ]