trying to create sudoko matrix help (JS) - javascript

I'm trying to create a random board for my project but it finishes without filling the whole board(leaves 0)
I converted the original code from this site:
www.101computing.net/sudoku-generator-algorithm/
from python to javascript manually and checked all the functions that I created but some things were wrong.
would love to get some help here thnks!
the code:
let grid = Array(9).fill().map(()=>Array(9).fill(0))
let numberList = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(grid);
fillGrid(grid)
console.log(grid)
function fillGrid(grid){
//var counter;
// Find next empty cell
for (i in range(0,81)){
row = ~~(i / 9);
col = i % 9;
if (grid[row][col]== 0){
shuffle(numberList);
for (g in numberList){
value = numberList[g]
// Check that this value has not already be used on this row and col
if (!checkForNumebrInRaw(grid,row,value) && !checkForNumebrInColomn(grid,col,value)){
// Identify which of the 9 squares we are working on
square = []
if (row<3){
if (col<3){
square = getSquare(grid,0,3,0,3);
}else if (col<6){
square = getSquare(grid,3,6,0,3);
}else{
square = getSquare(grid,6,9,0,3);
}
}
else if (row<6){
if (col<3){
square = getSquare(grid,0,3,3,6);
}else if (col<6){
square = getSquare(grid,3,6,3,6);
}else{
square = getSquare(grid,6,9,3,6);
}
}
else{
if (col<3){
square = getSquare(grid,0,3,6,9);
}else if (col<6){
square = getSquare(grid,3,6,6,9);
}else{
square = getSquare(grid,6,9,6,9);
}
}
// Check that this value has not already be used on this 3x3 square
if (!checkForNumInSquare(square,value)){
grid[row][col] = value;
if (checkGrid(grid)){
return true;
}else
{
if (fillGrid(grid)){
return true;
}
}
}
}
break
}
grid[row][col] = 0;
}
}
}
function range(start, end) {
let res=[];
for (i=start;i<end;i++){
res.push(i)
}
return res
};
function getSquare(mat,a,b,c,d) {
var _pj_a = []
_pj_b = range(c, d);
for (var _pj_c = 0, _pj_d = _pj_b.length; _pj_c < _pj_d; _pj_c += 1) {
var i = _pj_b[_pj_c];
_pj_a.push(mat[i].slice(a, b));
}
return _pj_a;
};
function checkForNumebrInRaw(grid,raw,num){
for (let i = 0; i<grid.length;i++){
if (grid[raw][i] == num){return true;}
}
return false;
}
function checkForNumebrInColomn(grid,colomn,num){
for (let i = 0; i<grid.length;i++){
if (grid[i][colomn] == num){return true;}
}
return false;
}
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle...
while (currentIndex != 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
function checkForNumInSquare(grid,num){
for (let i=0;i<grid.length;i++){
for(let j=0;j<grid[i].length;j++){
if (grid[i][j]== num){return true;}
}
}
return false
}
// A function to check if the grid is full
function checkGrid(grid){
for (let i=0;i<grid.length;i++){
for(let j=0;j<grid[i].length;j++){
if (grid[i][j]== 0){return false;}
}
}
return true
}
output:
[
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
],
[
0, 0, 0, 0, 0,
0, 0, 0, 0
]
]
[
[
3, 8, 7, 4, 1,
2, 5, 6, 9
],
[
5, 9, 6, 3, 7,
8, 1, 4, 0
],
[
1, 2, 4, 5, 6,
9, 7, 3, 8
],
[
9, 4, 3, 1, 5,
7, 0, 8, 2
],
[
2, 1, 8, 0, 9,
4, 3, 7, 6
],
[
7, 0, 5, 6, 8,
3, 9, 1, 4
],
[
4, 7, 2, 8, 0,
1, 6, 9, 5
],
[
0, 6, 9, 2, 3,
5, 8, 0, 7
],
[
8, 3, 1, 7, 0,
6, 4, 2, 0
]
]

Ok so after a million tries i made it!
// true - row and colomn without the number
function rowAndColomnCheck(grid,row,col,num){
function checkForNumebrInRaw(grid,row,num){
for (let i = 0; i<grid.length;i++){
if (grid[row][i] == num){return true;}
}
return false;
}
function checkForNumebrInColomn(grid,colomn,num){
for (let i = 0; i<grid.length;i++){
if (grid[i][colomn] == num){return true;}
}
return false;
}
if (!checkForNumebrInColomn(grid,col,num) && !checkForNumebrInRaw(grid,row,num)){
return true;
}else{
return false;
}
};
function range(start, end) {
let res=[];
for (i=start;i<end;i++){
res.push(i)
}
return res
};
function getSquare(mat,a,b,c,d) {
var _pj_a = []
_pj_b = range(c, d);
for (var _pj_c = 0, _pj_d = _pj_b.length; _pj_c < _pj_d; _pj_c += 1) {
var i = _pj_b[_pj_c];
_pj_a.push(mat[i].slice(a, b));
}
return _pj_a;
};
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle...
while (currentIndex != 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
};
// check if number is in sqare given
function checkForNumInSquare(grid,num){
for (let i=0;i<grid.length;i++){
for(let j=0;j<grid[i].length;j++){
if (grid[i][j]== num){return true;}
}
}
return false
};
// A function to check if the grid is full
function checkGrid(grid){
for (let i=0;i<grid.length;i++){
for(let j=0;j<grid[i].length;j++){
if (grid[i][j]== 0){return false;}
}
}
// complete
return true
};
function fillSudoku(mat){
for(let i in range(0,81)){
var mainRow = ~~(i / 9);
var mainCol = i % 9;
if (mat[mainRow][mainCol] == 0){
shuffle(numberList);
for (let value of numberList){
if(rowAndColomnCheck(mat,mainRow,mainCol,value)){
var mySquare = [[]];
if(mainRow<3){
if (mainCol<3){
mySquare = getSquare(mat,0,3,0,3);
}
else if (mainCol<6){
mySquare = getSquare(mat,3,6,0,3);
}
else{
mySquare = getSquare(mat,6,9,0,3);
}
}
else if(mainRow<6){
if (mainCol<3){
mySquare = getSquare(mat,0,3,3,6);
}
else if (mainCol<6){
mySquare = getSquare(mat,3,6,3,6);
}
else{
mySquare = getSquare(mat,6,9,3,6);
}
}
else{
if (mainCol<3){
mySquare = getSquare(mat,0,3,6,9);
}
else if (mainCol<6){
mySquare = getSquare(mat,3,6,6,9);
}
else{
mySquare = getSquare(mat,6,9,6,9);
}
}
bol_t = checkForNumInSquare(mySquare,value);
if (bol_t == false){
mat[mainRow][mainCol] = value;
if (checkGrid(mat)){
return true;
}
else{
if (fillSudoku(mat)){
return true;
}
}
}
}
}
break
}
}
mat[mainRow][mainCol] = 0;
};
var numberList = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var grid = Array(9).fill().map(()=>Array(9).fill(0));
fillSudoku(grid);
console.log(grid);

Related

My 2d array is not updating even after assignment

After debugging for more than an hour, I found the problem in my code. I do not understand why it updates board[y][x] but not board itself.
Here is the code:
puzzle = [
[0, 0, 7, 0, 0, 6, 2, 0, 0],
[1, 0, 0, 8, 9, 0, 7, 6, 0],
[8, 0, 2, 0, 7, 3, 0, 5, 0],
[0, 0, 0, 1, 0, 9, 5, 0, 6],
[0, 1, 0, 0, 0, 0, 0, 8, 0],
[7, 0, 3, 6, 0, 8, 0, 0, 0],
[0, 7, 0, 2, 4, 0, 6, 0, 3],
[0, 4, 1, 0, 6, 7, 0, 0, 5],
[0, 0, 9, 3, 0, 0, 1, 0, 0]
];
function find_empty(board) {
for (let y = 0; y < 9; ++y) {
for (let x = 0; x < 9; ++x) {
if (board[y][x] === 0) {
return [y, x];
}
}
}
return null;
}
function is_valid(board, num, pos) {
let y = pos[0];
let x = pos[1];
// Horizontal checking...
for (let i = 0; i < 9; ++i) {
if (board[y][i] === num && x !== i) {
return false;
}
}
// Vertical checking
for (let i = 0; i < 9; ++i) {
if (board[i][x] === num && y !== i) {
return false;
}
}
// 3*3 box checking
box_start_y = (Math.floor(y / 3)) * 3;
box_start_x = (Math.floor(x / 3)) * 3;
for (let i = box_start_y; i < box_start_y + 3; ++i) {
for (let j = box_start_x; j < box_start_x + 3; ++j) {
if (board[i][j] === num && y !== i && x !== j) {
return false;
}
}
}
return true;
}
function solve_board(board) {
console.log("start", board);
empty_pos = find_empty(board);
console.log("empty_pos", empty_pos)
if (empty_pos === null) {
return board;
}
let y = empty_pos[0];
let x = empty_pos[1];
for (let num = 1; num < 10; ++num) {
console.log(board)
if (is_valid(board, num, empty_pos)) {
console.log(true, num)
console.log("Before assignment", board[y][x]);
board[y][x] = num;
console.log("y", y, ", x", x);
console.log("After true", board[y][x])
console.log("After true", board);
let solved_board = solve_board(board)
console.log("solved", solved_board);
if (solved_board !== false) {
return solved_board;
}
console.log(num, "did not work!!")
board[y][x] = 0;
}
console.log(false, num)
}
return false;
}
console.log("result", solve_board(puzzle))
The problem is on line 72 in solve_board function.
It updates board[y][x] as seen in the console.logs, but does not affect board. Is it some reference issue or pass by value problem?
If anyone can help me solve this issue, I would be really grateful.
you are assigning the new value correctly. Arrays are passed to the function by reference, so there should be no problem. You can verify it with this code snippet:
const arr = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
function foo(x) {
x[0][0] = 2
}
foo(arr)
console.log(arr[0][0]) // 2
There probably is some issue with the game logic itself, the conditions in the is_valid don't look right. Consider taking a look on this article explaining how to solve sudoku programmatically with logic and without brute force.
Alternatively, I suggest you look at the backtracking algorithm, which tries all possible options, which should be straightforward to implement.

Uncaught RangeError: Maximum call stack size exceeded with sudoku solver

// global variable
// accessible to all functions
var sol =
[[0, 7, 0, 2, 3, 8, 0, 0, 0],
[0, 0, 0, 7, 4, 0, 8, 0, 9],
[0, 6, 8, 1, 0, 9, 0, 0, 2],
[0, 3, 5, 4, 0, 0, 0, 0, 8],
[6, 0, 7, 8, 0, 2, 5, 0, 1],
[8, 0, 0, 0, 0, 5, 7, 6, 0],
[2, 0, 0, 6, 0, 3, 1, 9, 0],
[7, 0, 9, 0, 2, 1, 0, 0, 0],
[0, 0, 0, 9, 7, 4, 0, 8, 0]];
//this function prints the board
var printBoard = function () {
for (let row = 0; row < sol.length; row += 1) {
for (let col = 0; col < sol[row].length; col += 1) {
let id = 'r' + (row + 1) + (col + 1);
let elem = document.getElementById(id);
elem.innerHTML = sol[row][col];
}
}
};
function isValid(sol, row, col, k) {
for (let i = 0; i < 9; i++) {
const m = 3 * Math.floor(row / 3) + Math.floor(i / 3);
const n = 3 * Math.floor(col / 3) + i % 3;
if (sol[row][i] == k || sol[i][col] == k || sol[m][n] == k) {
return false;
}
}
return true;
}
var solve = function() {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (sol[row][col] == 0) {
for (let k = 1; k <= 9; k++) {
if (isValid(sol, row, col, k) == true) {
sol[row][col] == '${k}';
if(solve() == true) {
return true;
} else {
sol[row][col] == 0;
}
}
}
return false;
}
}
}
return true;
}
printBoard();
I am having trouble debugging this. I keep getting an error message when I click on my solve button, which will take the grid and complete a sudoku puzzle: "Uncaught RangeError: Maximum call stack size exceeded". Looking at the file, it seems that my isValid() function, is causing the issues here. I think I am stuck in a continuous loop somewhere? Any help would be appreciated. It also says the error lies on lines 40 and 24, which are:
function isValid(sol, row, col, k) {
and
if (isValid(sol, row, col, k) == true) {
Please help, as I am not even a CS major and this is for a class requirement, and I am not exactly experience with this type of stuff. I tried to search for help thorugh other resources but it is just confusing me even more.
EDIT:
//global variable
//accesible to all functions
var sol =
[[0, 7, 0, 2, 3, 8, 0, 0, 0],
[0, 0, 0, 7, 4, 0, 8, 0, 9],
[0, 6, 8, 1, 0, 9, 0, 0, 2],
[0, 3, 5, 4, 0, 0, 0, 0, 8],
[6, 0, 7, 8, 0, 2, 5, 0, 1],
[8, 0, 0, 0, 0, 5, 7, 6, 0],
[2, 0, 0, 6, 0, 3, 1, 9, 0],
[7, 0, 9, 0, 2, 1, 0, 0, 0],
[0, 0, 0, 9, 7, 4, 0, 8, 0]];
//this function prints the board
var printBoard = function () {
for (let row = 0; row < sol.length; row += 1) {
for (let col = 0; col < sol[row].length; col += 1) {
let id = 'r' + (row + 1) + (col + 1);
let elem = document.getElementById(id);
elem.innerHTML = sol[row][col];
}
}
};
function isValid(sol, row, col, k) {
for (let i = 0; i < 9; i++) {
const m = 3 * Math.floor(row / 3) + Math.floor(i / 3);
const n = 3 * Math.floor(col / 3) + i % 3;
if (sol[row][i] == k || sol[i][col] == k || sol[m][n] == k) {
return false;
}
}
return true;
}
var solve = function(sol) {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (sol[row][col] == 0) {
//set the check for the row and column
for (let k = 1; k <= 9; k++) {
if (isValid(sol, row, col, k) == true) {
sol[row][col] == k;
//check if its not true, then check the row and column again
if(solve() == true) {
return true;
} else {
sol[row][col] = 0;
}
}
}
return false;
}
}
}
return true;
};
printBoard();
You never change sol before recursively calling solve() again.
if (isValid(sol, row, col, k) == true) {
sol[row][col] == '${k}'; // <- does not update sol
if(solve() == true) {
return true;
} else {
sol[row][col] == 0; // <- does not update sol
}
}
When you find an option for k that is a valid you should update sol before calling solve() again. Otherwise you will create an endless recursive loop which will eventually exceed the maximum stack size and result in the error you receive.
Use the assignment operator (=) instead of the equality operator (==) to assign a new value. Furthermore '${k}' will result in the literal ${k} use backticks (`) if you want to use string interpolation. I don't see a reason to use a string here, simply assigning k would be sufficient.
if (isValid(sol, row, col, k) == true) {
sol[row][col] = k; // <- assign k to a cell in the matrix
if(solve() == true) {
return true;
} else {
sol[row][col] = 0; // <- reset the cell back to 0 if it cannot be solved
}
}
I would also suggest using guard clauses. Instead of nesting the whole body of the for-loop inside an if-statement, use a guard and skip to the next iteration with continue:
for (...) {
if (check) {
// code
}
}
Can be changed to:
for (...) {
if (!check) continue;
// code
}
This generally improves the code indention and readability.

What does element.count & element.value means in array?

I found a great solution to get maximum Bi-valued slice of an array. And I want to apply it in Swift. However, I'm not familiar with JavaScript, I search it via Google, but no result yet.
Well, I simply want to know what does last.count & last.value means in below code. What they do with element last?
function getLongestSlice(array) {
var count = 0,
max = 0,
temp = [];
array.forEach(function (a) {
var last = temp[temp.length - 1];
if (temp.length < 2 || temp[0].value === a || temp[1].value === a) {
++count;
} else {
count = last.count + 1;
}
if (last && last.value === a) {
last.count++;
} else {
temp.push({ value: a, count: 1 });
temp = temp.slice(-2);
}
if (count > max) {
max = count;
}
});
return max;
}
console.log(getLongestSlice([58, 800, 0, 0, 0, 356, 8988, 1, 1])); // 4
console.log(getLongestSlice([58, 800, 0, 0, 0, 356, 356, 8988, 1, 1])); // 5
console.log(getLongestSlice([1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8])); // 10
Update:
Thanks. Now it is working in Swift.
import Foundation
struct Tmp {
var value: Int
var count: Int
}
func getLongestSlice(A: [Int]) -> Int {
var count = 0,
max = 0,
temp: [Tmp] = []
var last: Tmp = Tmp(value: 0, count: 0)
for a in A {
if temp.count != 0 {
last = temp[temp.count - 1]
}
print("last: \(last)")
if temp.count < 2 || temp[0].value == a || temp[1].value == a {
count += 1
} else {
count = last.count + 1
}
if last.value == a {
last.count += 1
// assign last.count to last element's count of temp array
temp[temp.count - 1].count = last.count
} else {
temp.append(Tmp(value: a, count: 1))
temp = Array(temp.suffix(2))
}
if count > max {
max = count
}
}
return max
}
getLongestSlice(A: [58, 800, 0, 0, 0, 356, 8988, 1, 1]) // return 4
getLongestSlice(A: [58, 800, 0, 0, 0, 356, 356, 8988, 1, 1]) // return 5
getLongestSlice(A: [1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8]) // return 10
getLongestSlice(A: [777]) // return 1
getLongestSlice(A: []) // return 0
From thread: Find Max Slice Of Array | Javascript
The temp array holds objects of the following shape:
{ count: ..., value: ... }
So the last refers to the last element of that array, while count and value are the properties of that element.
This is not related to JavaScript.

Flood-fill algorithm in Javascript not filling the entire grid when using for loops

I've been working at this all day, and I can't work out why this algorithm doesn't cover the entire grid when starting at position grid[1][1].
I start by setting up the grid and calculating the number of rows and columns in the grid to give me a limit on the edges of the array.
I then call the function, setting position grid[1][1] = 1, calculating the offset and making sure it is not outside the array and making sure the new position has not already been called before calling the function recursively.
I just can't figure out why this isn't working!
var grid = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
var cols = grid.length;
var rows = grid[0].length;
floodFill(1, 1)
function floodFill(col, row) {
grid[col][row] = 1;
for (c_off = -1; c_off < 2; c_off++) {
for (r_off = -1; r_off < 2; r_off++) {
var i = col + c_off;
var j = row + r_off;
if (i > -1 && i < cols && j > -1 && j < rows) {
if (grid[i][j] != 1) {
floodFill(i, j);
}
}
}
}
}
grid;
/*
output:
[ [ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 0 ],
[ 1, 1, 0, 0, 0 ] ]
expected output:
[ [ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ] ]
*/
That's because c_off and r_off are not defined as local variables (via the var or let keywords) so they are treated like a global variables which means that a recursive invocation of floodFill() overwrites the values for its calling invocation thereby interfering with the caller's iteration order.
The fix is simple: just add a var keyword in both for loops:
function floodFill(col, row) {
grid[col][row] = 1;
for (var c_off = -1; c_off < 2; c_off++) {
for (var r_off = -1; r_off < 2; r_off++) {
var i = col + c_off;
var j = row + r_off;
if (i > -1 && i < cols && j > -1 && j < rows) {
if (grid[i][j] != 1) {
floodFill(i, j);
}
}
}
}
}
Appendix
You can move the detection of out-of-grid condition, and the check whether the given point is already filled, to the beginning of the function (instead of doing it just before the recursive call). Some may argue that the resulting code is simpler to understand:
function floodFill(col, row) {
if (col < 0 || col >= cols || row < 0 || row >= rows) {
return;
}
if (grid[col][row] == 1) {
return;
}
grid[col][row] = 1;
for (var c_off = -1; c_off < 2; c_off++) {
for (var r_off = -1; r_off < 2; r_off++) {
floodFill(col + c_off, row + r_off);
}
}
}
I think Itay Maman answer is probably better. I solved it this way. by changing c_off < 5 and r_off < 5
var grid = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
var cols = grid.length;
var rows = grid[0].length;
floodFill(1, 1)
function floodFill(col, row) {
grid[col][row] = 1;
for (c_off = -1; c_off < 5; c_off++) {
for (r_off = -1; r_off < 5; r_off++) {
var i = col + c_off;
var j = row + r_off;
if (i > -1 && i < cols && j > -1 && j < rows) {
if (grid[i][j] != 1) {
floodFill(i, j);
}
}
}
}
}
console.log(grid);

Find Max Slice Of Array | Javascript

I need to find the maximum slice of the array which contains no more than two different numbers.
Here is my array [1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8]
My thought process on this is to find the numbers that are not repeated and return their index within a new array.
Here is what I have so far:
function goThroughInteger(number) {
var array = [];
//iterate the array and check if number is not repeated
number.filter(function (element, index, number) {
if(element != number[index-1] && element != number[index+1]) {
array.push(index);
return element;
}
})
console.log(array);
}
goThroughInteger([1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8]);
I'm unsure where to go next, I'm struggling to understand the question that being - find the maximum slice which contains no more than two different numbers - that confuses me.
A solution with a single loop, which checks the last values and increments a counter.
function getLongestSlice(array) {
var count = 0,
max = 0,
temp = [];
array.forEach(function (a) {
var last = temp[temp.length - 1];
if (temp.length < 2 || temp[0].value === a || temp[1].value === a) {
++count;
} else {
count = last.count + 1;
}
if (last && last.value === a) {
last.count++;
} else {
temp.push({ value: a, count: 1 });
temp = temp.slice(-2);
}
if (count > max) {
max = count;
}
});
return max;
}
console.log(getLongestSlice([58, 800, 0, 0, 0, 356, 8988, 1, 1])); // 4
console.log(getLongestSlice([58, 800, 0, 0, 0, 356, 356, 8988, 1, 1])); // 5
console.log(getLongestSlice([1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8])); // 10
function goThroughInteger(array) {
var solutionArray = [];
var max = 0;
for (var i = 0; i <= array.length; i++) {
for (var j = i + 1; j <= array.length; j++) {
var currentSlice= array.slice(i,j);
var uniqSet = [...new Set(currentSlice)];
if(uniqSet.length <3) {
if(currentSlice.length>max) {
max= currentSlice.length;
}
}
}
}
console.log(max);
}
goThroughInteger([1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8]);
This solution checks every possible slice of the array, checks if it has not more than 2 different numbers and finally prints out the length of the longest slice.
This is a possible solution, with complexity O(n²) (as pointed out by #le_m in the comments)
goThroughInteger = (list) => {
let scores = list.reduce((slices, num, pos) => {
let valid = [num];
let count = 0;
for (let i = pos; i < list.length; i++) {
if (valid.indexOf(list[i]) == -1) {
if (valid.length < 2) {
valid.push(list[i]);
count++;
} else {
break;
}
} else {
count++;
}
}
slices[pos] = { pos, count };
return slices;
}, []);
scores.sort((a, b) => b.count - a.count);
let max = scores[0];
return list.slice(max.pos, max.pos + max.count);
};
console.log(goThroughInteger([1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8]));
console.log(goThroughInteger([58, 800, 0, 0, 0, 356, 8988, 1, 1]));
```
The solution calculates the 'score' at every position of the input list, counting the length of a sequence of no more than 2 different values, then takes the result with the highest score and extracts a slice from the original list based on that information.
It can definitely be cleaned and optimized but I think it's a good starting point.
Using the sliding window algorithm in O(n) time:
const arr = [1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8, 1, 1 ,1 ,1, 8, 1, 1, 8, 8];
const map = {
length: 0
};
let required = [];
for(start = 0, end = 0; end <= arr.length; ){
if(map.length > 2){
if(map[arr[start]] === 1){
delete map[arr[start]];
map.length --;
}else{
map[arr[start]]--;
};
start++;
}else{
if(end - start > required.length){
required = arr.slice(start, end);
};
if(map[arr[end]]){
map[arr[end]]++;
}else{
map[arr[end]] = 1;
map.length++;
}
end++;
}
}
console.log(required);

Categories

Resources