So I am trying to solve N-Queens problem, and when I console.log(result) inside the solve function I am getting the correct output. but when I return the result array in the end, it seems like the result array has not been mutated at all, as I get [[-, -, -,-], [-,-,-,-]]
function solveNQueens(n) {
let result = [];
let buffer = Array(n).fill('-');
function solve(bufferIndexRow) {
if (bufferIndexRow === n) {
result.push(buffer);
return console.log('FOUND ONE SOLUTION'); // Finished last row, filled queens array
}
for (let column = 0; column < n; column++) {
buffer[bufferIndexRow] = column;
if (isValid(bufferIndexRow, column)) {
solve(bufferIndexRow + 1);
}
buffer[bufferIndexRow] = '-'
}
}
function isValid(row, col) {
for(let i = 0; i< row; i++) {
if(buffer[i] == col || Math.abs(i - row) == Math.abs(buffer[i]- col))
return false;
}
return true;
}
solve(0);
return result;
}
console.log(solveNQueens(4));
you need to pass in buffer to solve so that it can push the updated buffer to result
Related
I saw in some other articles that quicksort should be an in place algorithm, so is this implementation correct ?. Here the author is creating new arrays on each recursion step.
function quickSort(arr) {
if (arr.length < 2) {
return arr
} else {
let pivotIdx = getRandom(arr.length)
let pivot = arr[pivotIdx]
let [leftArr, rightArr] = partition(pivotIdx, arr)
return [...(quickSort(leftArr)) , ...[pivot] , ...(quickSort(rightArr))]
}
}
function getRandom(maxInt) {
return Math.floor(Math.random() * maxInt)
}
function partition(pivotIdx, arr) {
let leftArr = []
let rightArr = []
let pivot = arr[pivotIdx];
for (let i=0; i< arr.length; i++) {
if (i === pivotIdx) continue;
if (pivot > arr[i]) {
leftArr.push(arr[i])
} else {
rightArr.push(arr[i])
}
}
return [leftArr, rightArr]
}
quicksort([44,1,2,3])
Let's say, I have following template.
Hello, {I'm|he is} a {notable|famous} person.
Result should be
Hello, I'm a notable person.
Hello, I'm a famous person.
Hello, he is a notable person.
Hello, he is a famous person.
The only possible solution I have in mind - full search, but it is not effective.
May be there is a good algorithm for such kind of job but I do not know what task about. All permutations in array is very close to this but I have no idea how to use it here.
Here is working solution (it's part of object, so here is only relevant part).
generateText() parses string and converts 'Hello, {1|2}, here {3,4}' into ['Hello', ['1', '2'], 'here', ['3', '4']]]
extractText() takes this multidimensional array and creates all possible strings
STATE_TEXT: 'TEXT',
STATE_INSIDE_BRACKETS: 'INSIDE_BRACKETS',
generateText: function(text) {
var result = [];
var state = this.STATE_TEXT;
var length = text.length;
var simpleText = '';
var options = [];
var singleOption = '';
var i = 0;
while (i < length) {
var symbol = text[i];
switch(symbol) {
case '{':
if (state === this.STATE_TEXT) {
simpleText = simpleText.trim();
if (simpleText.length) {
result.push(simpleText);
simpleText = '';
}
state = this.STATE_INSIDE_BRACKETS;
}
break;
case '}':
if (state === this.STATE_INSIDE_BRACKETS) {
singleOption = singleOption.trim();
if (singleOption.length) {
options.push(singleOption);
singleOption = '';
}
if (options.length) {
result.push(options);
options = [];
}
state = this.STATE_TEXT;
}
break;
case '|':
if (state === this.STATE_INSIDE_BRACKETS) {
singleOption = singleOption.trim();
if (singleOption.length) {
options.push(singleOption);
singleOption = '';
}
}
break;
default:
if (state === this.STATE_TEXT) {
simpleText += symbol;
} else if (state === this.STATE_INSIDE_BRACKETS) {
singleOption += symbol;
}
break;
}
i++;
}
return result;
},
extractStrings(generated) {
var lengths = {};
var currents = {};
var permutations = 0;
var length = generated.length;
for (var i = 0; i < length; i++) {
if ($.isArray(generated[i])) {
lengths[i] = generated[i].length;
currents[i] = lengths[i];
permutations += lengths[i];
}
}
var strings = [];
for (var i = 0; i < permutations; i++) {
var string = [];
for (var k = 0; k < length; k++) {
if (typeof lengths[k] === 'undefined') {
string.push(generated[k]);
continue;
}
currents[k] -= 1;
if (currents[k] < 0) {
currents[k] = lengths[k] - 1;
}
string.push(generated[k][currents[k]]);
}
strings.push(string.join(' '));
}
return strings;
},
The only possible solution I have in mind - full search, but it is not effective.
If you must provide full results, you must run full search. There is simply no way around it. You don't need all permutations, though: the number of results is equal to the product of the number of alternatives in each template.
Although there are multiple ways to implement this, recursion is among the most popular approaches. Here is some pseudo-code to get you started:
string[][] templates = {{"I'm", "he is"}, {"notable", "famous", "boring"}}
int[] pos = new int[templates.Length]
string[] fills = new string[templates.Length]
recurse(templates, fills, 0)
...
void recurse(string[][] templates, string[] fills, int pos) {
if (pos == fills.Length) {
formatResult(fills);
} else {
foreach option in templates[pos] {
fills[pos] = option
recurse(templates, fills, pos+1);
}
}
}
It seems like the best solution here is going to be n*m where n=the first array and m= the second array . There are nm required lines of output, which means that as long as you are only doing nm you aren't doing any extra work
The generic running time for this is where there is more than 2 arrays with options, it would be
n1*n2...*nm where each of those is equal to the size of the respective list
A nested loop where you just print out the value for the current index of the outer loop along with the current value for the index of the inner loop should do this properly
I'm using jQuery DataTables, trying to sort data column with 2 different date types.
I have 2 different formats month/year and day/month/year but they are not sorting correctly.
Current code:
function dateSorter(a, b) {
var datea = a.split("/");
var dateb = b.split("/");
if (datea[1] > dateb[1]) return 1;
if (datea[1] < dateb[1]) return -1;
if (datea[0] > dateb[0]) return 1;
if (datea[0] < dateb[0]) return -1;
if( datea.length == 2 )
{
if (datea[2] > dateb[2]) return 1;
if (datea[2] < dateb[2]) return -1;
}
else
{
if( datea[1] > dateb[2] ) return 1;
if( datea[2] < dateb[1] ) return -1;
}
return 0;
}
Above is current code, it works for month/year format and sorts them fine , but not mixed with both formats.
This currently sorts day/month from day/month/year format but it does not sort year correctly.
Example (current):
03/04/2016
12/04/2017
12/05/2015
01/2015
02/2015
02/2016
01/2018
...
It should be:
01/2015
02/2015
12/05/2015
02/2016
03/04/2016
12/04/2017
01/2018
$.extend( jQuery.fn.dataTableExt.oSort, {
"date-time-odd-pre": function (a){
if(/\d{1,2}\/\d{1,2}\/\d{4}/.test(a)){
return parseInt(moment(a, "DD/MM/YYYY").format("X"), 10);
}else{
return parseInt(moment(a, "MM/YYYY").format("X"), 10);
}
},
"date-time-odd-asc": function (a, b) {
return a - b;
},
"date-time-odd-desc": function (a, b) {
return b - a;
}
});
Should work, though you'll need moment available.
Hope that helps.
I am sorting a grid with knockout.js. Following is my sort function
this.sortByName = function() {
var event = arguments[1];
var targeElement = event.originalTarget;
// console.info(targeElement);
console.log(targeElement.attributes[1].nodeValue);
order = 'sorting';
configuration.data.sort(function(a, b) {
if(a.name<b.name){
order = 'sorting_desc';
return a.name > b.name ? -1 : 1;
}
else if(a.name>b.name){
order = 'sorting_asc'
return a.name < b.name ? -1 : 1;
}
});
$(targeElement).removeClass('sorting_asc sorting_desc').addClass(order);
};
The by default grid view
The Sorted image 1
The sorted image 2
As you can see the order of sorting is not correct. I have been playing around for 3 days in this issue.
Well I found a solution to this problem
this.sortByName = function() {
currentOrder = arguments[0].sortClass();
var sortColumn = arguments[0].rowText;
if(currentOrder =='sorting' || currentOrder =='sorting_desc'){
currentOrder='sorting_asc';
configuration.data.sort(function(a, b) {
if (a[sortColumn] == b[sortColumn])
return 0;
else if (a[sortColumn] < b[sortColumn])
return -1;
else
return 1;
});
}else{
currentOrder='sorting_desc';
configuration.data.sort(function(a, b) {
if (a[sortColumn] == b[sortColumn])
return 0;
else if (a[sortColumn] > b[sortColumn])
return -1;
else
return 1;
});
}
self.resetSortColumns();
arguments[0].sortClass(currentOrder);
};
Consider a MxN bitmap where the cells are 0 or 1. '1' means filled and '0' means empty.
Find the number of 'holes' in the bitmap, where a hole is a contiguous region of empty cells.
For example, this has two holes:
11111
10101
10101
11111
... and this has only one:
11111
10001
10101
11111
What is the fastest way, when M and N are both between 1 and 8?
Clarification: diagonals are not considered contiguous, only side-adjacency matters.
Note: I am looking for something that takes advantage of the data format. I know how to transform this into a graph and [BD]FS it but that seems overkill.
You need to do connected component labeling on your image. You can use the Two-pass algorithm described in the Wikipedia article I linked above. Given the small size of your problem, the One-pass algorithm may suffice.
You could also use BFS/DFS but I'd recommend the above algorithms.
This seems like a nice use of the disjoint-set data structure.
Convert the bitmap to a 2d array
loop through each element
if the current element is a 0, merge it with the set of one its 'previous' empty neighbors (already visited)
if it has no empty neighbors, add it to its own set
then just count the number of sets
There may be advantages gained by using table lookups and bitwise operations.
For example whole line of 8 pixels may be looked up in 256 element table, so number of holes in a field 1xN is got by single lookup. Then there may be some lookup table of 256xK elements, where K is number of hole configurations in previous line, contatining number of complete holes and next hole configuration. That's just an idea.
I wrote an article describe the answer on Medium https://medium.com/#ahmed.wael888/bitmap-holes-count-using-typescript-javascript-387b51dd754a
but here is the code, the logic isn't complicated and you can understand it without reading the article.
export class CountBitMapHoles {
bitMapArr: number[][];
holesArr: Hole[] = [];
maxRows: number;
maxCols: number;
constructor(bitMapArr: string[] | number[][]) {
if (typeof bitMapArr[0] == 'string') {
this.bitMapArr = (bitMapArr as string[]).map(
(word: string): number[] => word.split('').map((bit: string): number => +bit))
} else {
this.bitMapArr = bitMapArr as number[][]
}
this.maxRows = this.bitMapArr.length;
this.maxCols = this.bitMapArr[0].length;
}
moveToDirection(direction: Direction, currentPosition: number[]) {
switch (direction) {
case Direction.up:
return [currentPosition[0] - 1, currentPosition[1]]
case Direction.down:
return [currentPosition[0] + 1, currentPosition[1]]
case Direction.right:
return [currentPosition[0], currentPosition[1] + 1]
case Direction.left:
return [currentPosition[0], currentPosition[1] - 1]
}
}
reverseDirection(direction: Direction) {
switch (direction) {
case Direction.up:
return Direction.down;
case Direction.down:
return Direction.up
case Direction.right:
return Direction.left
case Direction.left:
return Direction.right
}
}
findNeighbor(parentDir: Direction, currentPosition: number[]) {
let directions: Direction[] = []
if (parentDir === Direction.root) {
directions = this.returnAvailableDirections(currentPosition);
} else {
this.holesArr[this.holesArr.length - 1].positions.push(currentPosition)
directions = this.returnAvailableDirections(currentPosition).filter((direction) => direction != parentDir);
}
directions.forEach((direction) => {
const childPosition = this.moveToDirection(direction, currentPosition)
if (this.bitMapArr[childPosition[0]][childPosition[1]] === 0 && !this.checkIfCurrentPositionExist(childPosition)) {
this.findNeighbor(this.reverseDirection(direction), childPosition)
}
});
return
}
returnAvailableDirections(currentPosition: number[]): Direction[] {
if (currentPosition[0] == 0 && currentPosition[1] == 0) {
return [Direction.right, Direction.down]
} else if (currentPosition[0] == 0 && currentPosition[1] == this.maxCols - 1) {
return [Direction.down, Direction.left]
} else if (currentPosition[0] == this.maxRows - 1 && currentPosition[1] == this.maxCols - 1) {
return [Direction.left, Direction.up]
} else if (currentPosition[0] == this.maxRows - 1 && currentPosition[1] == 0) {
return [Direction.up, Direction.right]
} else if (currentPosition[1] == this.maxCols - 1) {
return [Direction.down, Direction.left, Direction.up]
} else if (currentPosition[0] == this.maxRows - 1) {
return [Direction.left, Direction.up, Direction.right]
} else if (currentPosition[1] == 0) {
return [Direction.up, Direction.right, Direction.down]
} else if (currentPosition[0] == 0) {
return [Direction.right, Direction.down, Direction.left]
} else {
return [Direction.right, Direction.down, Direction.left, Direction.up]
}
}
checkIfCurrentPositionExist(currentPosition: number[]): boolean {
let found = false;
return this.holesArr.some((hole) => {
const foundPosition = hole.positions.find(
(position) => (position[0] == currentPosition[0] && position[1] == currentPosition[1]));
if (foundPosition) {
found = true;
}
return found;
})
}
exec() {
this.bitMapArr.forEach((row, rowIndex) => {
row.forEach((bit, colIndex) => {
if (bit === 0) {
const currentPosition = [rowIndex, colIndex];
if (!this.checkIfCurrentPositionExist(currentPosition)) {
this.holesArr.push({
holeNumber: this.holesArr.length + 1,
positions: [currentPosition]
});
this.findNeighbor(Direction.root, currentPosition);
}
}
});
});
console.log(this.holesArr.length)
this.holesArr.forEach(hole => {
console.log(hole.positions)
});
return this.holesArr.length
}
}
enum Direction {
up = 'up',
down = 'down',
right = 'right',
left = 'left',
root = 'root'
}
interface Hole {
holeNumber: number;
positions: number[][]
}
main.ts file
import {CountBitMapHoles} from './bitmap-holes'
const line = ['1010111', '1001011', '0001101', '1111001', '0101011']
function main() {
const countBitMapHoles = new CountBitMapHoles(line)
countBitMapHoles.exec()
}
main()
function BitmapHoles(strArr) {
let returnArry = [];
let indexOfZ = [];
let subarr;
for(let i=0 ; i < strArr.length; i++){
subarr = strArr[i].split("");
let index = [];
for(let y=0 ; y < subarr.length; y++){
if(subarr[y] == 0)
index.push(y);
if(y == subarr.length-1)
indexOfZ.push(index);
}
}
for(let i=0 ; i < indexOfZ.length; i++){
for(let j=0; j<indexOfZ[i].length ; j++){
if(indexOfZ[i+1] && (indexOfZ[i][j]==indexOfZ[i+1][j] || indexOfZ[i+1].indexOf(indexOfZ[i][j])))
returnArry.indexOf(strArr[i]) < 0 ? returnArry.push(strArr[i]): false;
if(Math.abs(indexOfZ[i][j]-indexOfZ[i][j+1])==1)
returnArry.indexOf(strArr[i]) < 0 ? returnArry.push(strArr[i]): false;
}
}
return returnArry.length;
}
// keep this function call here
console.log(BitmapHoles(readline()));
function findHoles(map) {
let hole = 0;
const isHole = (i, j) => map[i] && map[i][j] === 0;
for (let i = 0; i < map.length; i++) {
for (let j = 0; j < map[i].length; j++) {
if (isHole(i, j)) {
markHole(i, j);
hole++;
}
}
}
function markHole(i, j) {
if (isHole(i, j)) {
map[i][j] = 2;
markHole(i, j - 1);
markHole(i, j + 1);
markHole(i + 1, j);
markHole(i - 1, j);
}
}
return hole;
}