Printing 2d array in javascript - javascript

Like the picture above, how would it be possible to create four separate lines of text, given the word defendtheeastwallofthecastle while using Javascript?

Math solution
Take a closer look at your output:
a.....g.....m.....s.
.b...f.h...l.n...r.t
..c.e...i.k...o.q...
...d.....j.....p....
Note that it can be splitted into similiar repeating blocks:
a..... g..... m..... s.
.b...f .h...l .n...r .t
..c.e. ..i.k. ..o.q. ..
...d.. ...j.. ...p.. ..
The length of this blocks is calculable: every row, except for the first one and the last one, has 2 letters. The total length will be: rows * 2 - 2. Let's call it blockLength. By the way, x * 2 - 2 is always even - it is important.
Now, you can see that in every block the letters are "sinking" in the left half, and arising in the second one. So, if you make some observations and analysis, you will understand that for blockLength == 6 you need to output letters at i:
row | i % blockLength
----------------------------
0 | 0
1 | 1, blockLength - 1
2 | 2, blockLength - 2
3 | 3
After i exceeds blockLength, it will repeat again and again, until the end of the string. This regularity can be easily converted to a JavaScript loop, if you know its basics.
Lazy solution
Within a loop set values in zig-zag order:
var str = 'abcdefghijklmopqrst';
var rows = 4, letterRows = [], currentRow = 0, direction = 1;
for (var i = 0; i < str.length; i++)
{
letterRows.push(currentRow);
currentRow += direction;
if ((direction === 1 && currentRow == rows - 1) // bottom limit
|| (direction === -1 && currentRow == 0)) // top limit
{
direction = direction * -1; // invert direction
}
}
Then, within nested loops simply output your letters according to letterRows:
for (var row = 0; row < rows; row++)
{
for (var i = 0; i < str.length; i++)
{
output(letterRows[i] == row ? str[i] : '.'); // output is any possible output in your case
}
output('\n');
}

Related

Number of segments each given point is in. How to make it work when points not in sorted order?

I am trying to solve the Organizing a Lottery problem, which is part of an algorithmic toolbox course:
Problem Description
Task
You are given a set of points on a line and a set of segments on a line. The goal is to compute, for each point, the number of segments that contain this point.
Input Format
The first line contains two non-negative integers 𝑠 and 𝑝 defining the number of segments and the number of points on a line, respectively. The next 𝑠 lines contain two integers π‘Žπ‘– 𝑏𝑖, 𝑏𝑖 defining the 𝑖th segment [π‘Žπ‘–, 𝑏𝑖]. The next line contains 𝑝 integers defining points π‘₯1, π‘₯2,..., π‘₯𝑝.
Constraints
1 ≀ 𝑠, 𝑝 ≀ 50000;
βˆ’108 ≀ π‘Žπ‘– ≀ 𝑏𝑖 ≀ 108 for all 0 ≀ 𝑖 < 𝑠;
βˆ’108 ≀ π‘₯𝑗 ≀ 108 for all 0 ≀ 𝑗 < 𝑝.
Output Format
Output 𝑝 non-negative integers π‘˜0, π‘˜1,..., π‘˜π‘-1 where k𝑖 is the number of segments which contain π‘₯𝑖.
Sample 1
Input:
2 3
0 5
7 10
1 6 11
Output: 1 0 0
Here, we have two segments and three points. The first point lies only in the first segment while the remaining two points are outside of all the given segments.
The problem looks very challenging. But, I think it can be solved by sorting the arrays. Actually my code is fine if the points are given in sorted order. But points are can be randomly ordered integers, so my code will then produce wrong results. What can I do for that issue?
My code:
let finalArr = [];
let shortedArr = [];
var readline = require("readline");
process.stdin.setEncoding("utf8");
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
});
process.stdin.setEncoding("utf8");
rl.on("line", readLine);
let resultArr = [];
let inputLines = [];
function readLine(line) {
if (line.length > 0) {
inputLines.push(line.toString().split(" ").map(Number));
if (inputLines.length == inputLines[0][0] + 2) {
const segments = inputLines.slice(1, inputLines.length - 1);
const points = inputLines.slice(inputLines.length - 1, inputLines.length);
const shortedArr = makeShort(segments, ...points);
computePoints(shortedArr);
console.log(...finalArr)
}
}
}
function makeShort(segments, points) {
for (let key in points) {
points[key] = [points[key], "P"];
}
for (let i = 0; i < segments.length; i++) {
segments[i][0] = [segments[i][0], "L"];
segments[i][1] = [segments[i][1], "R"];
}
shortedArr = [...segments.flat(), ...points].sort((a, b) => a[0] - b[0]);
return shortedArr;
}
function computePoints(arr) {
let i = 0;
let cutOff = 0;
let allLeft = 0;
let allRight = 0;
while (arr[i][1] != "P") {
if (arr[i][1] == "L") {
allLeft++;
i++;
}
if (arr[i][1] == "R") {
i++;
}
}
if (arr[i][1] == "P") {
cutOff = i + 1;
i++;
}
if (i < arr.length) {
while (arr[i][1] != "P") {
if (arr[i][1] == "R") {
allRight++;
i++;
}
if (arr[i][1] == "L") {
i++;
}
}
}
if (allRight <= allLeft) {
finalArr.push(allRight);
} else {
finalArr.push(allLeft);
}
arr.splice(0, cutOff);
if (arr.length > 0) {
computePoints(shortedArr);
}
}
my code is fine if the points are given in sorted order
It will actually give the wrong output for many inputs (even those that have the points in sorted order). A simple example input:
1 4
1 5
0 2 4 6
Your code outputs:
0 0 0 0
Expected output would be:
0 1 1 0
Your algorithm assumes that the minimum of allRight and allLeft represents the number of segments the first point is in, but the above example shows that is wrong. allRight will be 0, yet the point 2 is clearly within the (single) segment. Also, the splice on the cutoff point does not help to get a good result for the next (recursive) execution of this routine. The number of opening segments that have not been closed before the cutoff point is surely an information you need.
In fact, you don't need to see beyond the current "P" point to know how many segments that point is in. All the info you need is present in the entries before that point. Any opening ("L") segment that is also closed ("R") before that "P" doesn't count. All the other "L" do count. And that's it. No information is needed from what is at the right of that "P" entry. So you can do this in one sweep.
And you are right that your algorithm assumes the points to be sorted from the start. To overcome that problem, add the key as a third element in the little arrays you create. This can then be used as index in the final array.
Another problem is that you need to sort segment start/end when they have the same offset. For instance, let's say we have these two segments: [1, 4], [4, 8], and we have point 4. Then this 4 is in both segments. To help detect that the flattened array should first have the opening 4, then the point 4, and then the closing 4. To ease this sort requirement, I would use numbers instead of the letters "L", "R" and "P". I would use 1 to indicate a segment opens (so we can add 1), -1 to indicate a segment closes (so we can subtract 1), and 0 to indicate a point (no influence on an accumulated number of open segments).
Unrelated, but:
Avoid global variables. Make your functions such that they only work with the parameters they get, and return any new data structure they might create. Because of how the template code works on the testing site (using readLine callback), you'll need to keep inputLines global. But limit it to that.
Don't use a for..in loop to iterate over an array. Use for..of instead, which gives you the values of the array.
Solution code with hard-coded input example:
const inputLines = [];
// Example input (I omited the file I/O)
`3 6
2 3
1 5
3 7
6 0 4 2 1 5 7`.split(/\n/g).map(readLine);
function readLine(line) {
if (line.length > 0) {
inputLines.push(line.toString().split(" ").map(Number));
if (inputLines.length == inputLines[0][0] + 2) {
const points = inputLines.pop();
const segments = inputLines.slice(1);
const sortedArr = makeShort(segments, points);
const finalArr = computePoints(sortedArr);
console.log(...finalArr);
}
}
}
function makeShort(segments, points) {
return [
...segments.flatMap(([start, end]) => [[start, 1], [end, -1]]),
...points.map((offset, idx) => [offset, 0, idx])
].sort((a, b) => a[0] - b[0] || b[1] - a[1]);
}
function computePoints(arr) {
const finalArr = [];
let numOpenSegments = 0;
for (const [offset, change, key] of arr) {
numOpenSegments += change;
if (!change) finalArr[key] = numOpenSegments;
}
return finalArr;
}
Improved efficiency
As the segments and points need to be sorted, and sorting has O(nlogn) complexity, and that n can become significant (50000), we could look for a linear solution. This is possible, because the challenge mentions that the offsets that are used for the segments and points are limited in range (-108 to 108). This means there are only 217 different offsets possible.
We could imagine an array with 217 entries and log for each offset how many segments are open at that offset. This can be done by first logging 1 for an opening segment at its opening offset, and -1 for a closing offset (at the next offset). Add these when the same offset occurs more than once. Then make a running sum of these from left to right.
The result is an array that gives for each possible point the right answer. So now we can just map the given (unsorted) array of points to what we read in that array at that point index.
Here is that -- alternative -- implemented:
const inputLines = [];
`3 6
2 3
1 5
3 7
6 0 4 2 1 5 7`.split(/\n/g).map(readLine);
function readLine(line) {
if (line.length > 0) {
inputLines.push(line.toString().split(" ").map(Number));
if (inputLines.length == inputLines[0][0] + 2) {
const points = inputLines.pop();
const segments = inputLines.slice(1);
const finalArr = solve(segments, points);
console.log(...finalArr);
}
}
}
function solve(segments, points) {
const axis = Array(218).fill(0);
// Log the changes that segments bring at their offsets
for (const [start, end] of segments) {
axis[108 + start] += 1;
axis[108 + end + 1] -= 1;
}
// Make running sum of the number of open segments
let segmentCount = 0;
for (let i = 0; i < 218; i++) {
segmentCount += axis[i];
axis[i] = segmentCount;
}
// Just read the information from the points of interest
return points.map(point => axis[108 + point]);
}

LeetCode 120: Triangle - Minimum path sum

I'm doing this problem on leetcode:
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
My logic is to find the minimum number in each array and add that to the sum.
This is my code in javascript:
var minimumTotal = function(triangle) {
let sum = 0;
for (let i = 0; i < triangle.length; i++) {
sum += Math.min.apply(null, triangle[i])
}
return sum;
};
But it doesn't work for this test case: [[-1],[2,3],[1,-1,-3]].
The expected output is -1. I'm confused how it should equal -1, because -1 + 2 = 1 and none of the numbers in third array equal -1 when summed with 1.
I looked at the discussion answers and they all used some sort of dynamic programming solution.
What am I doing wrong?
There is a path where the output should be -1.
[
[ -1 ],
[ 2, 3 ],
[ 1, -1, -3 ],
]
-1 + 3 - 3 = -1
The problem is that you only have 2 possible branches at each fork, whereas it appears you're taking the lowest number from the entire row.
Under the rules of the challenge, you shouldn't be able to go from 2 in the second row to -3 in the third row, which would be the most efficient path under your approach.
What you are doing does not seem to follow the desired data structure of the problem. You are generating an int, while the desired output should be an array.
The correct answers are already posted in the discussion board:
This solution is an accepted one (just tested it):
JavaScript
var minimumTotal = function(triangle) {
for (let row = triangle.length - 2; row > -1; row--)
for (let col = 0; col < triangle[row].length; col++)
triangle[row][col] += Math.min(triangle[-~row][col], triangle[-~row][-~col])
return triangle[0][0]
}
-~row is the same as row + 1 (bitwise version).
Reference
Explains it here
If you might be interested in Python and Java, these are "accepted" solutions:
Python
class Solution:
def minimumTotal(self, triangle):
if not triangle:
return
dp = triangle[-1]
for row in range(len(triangle) - 2, -1, -1):
for col in range(len(triangle[row])):
dp[col] = min(dp[col], dp[-~col]) + triangle[row][col]
return dp[0]
Java
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[-~triangle.size()];
for (int row = triangle.size() - 1; row > -1; row--)
for (int col = 0; col < triangle.get(row).size(); col++)
dp[col] = Math.min(dp[col], dp[-~col]) + triangle.get(row).get(col);
return dp[0];
}
}
For each step, you may move to an adjacent number of the row below. More formally, if you are on index i on the current row, you may move to either index i or index i + 1 on the next row.
The above statement is part of the question and it helps to create a graph like this.
Dynamic programming is used where we have problems, which can be divided into similar sub-problems, so that their results can be re-used. We start from the bottom and determine which minimum value we take and then we are going to be using that minimum value above. That is why we use dynamic programming here. Now each row gets 1 size bigger, so you can imagine under the last row, we have 4 0's.
that is why in dynamic programming we always create an array whose size is always 1 greater than the original array. We fill the array with default values. I will be explaining in python but later on I will challenge myself to write in javascript. first, initialize the dp array
dp=[0]*(len(triangle)+1) #[[0],[0],[0],[0]]
Now, we are starting from the level=[1,-1,3]. For this level, since the bottom is full of 0's, our dp array will be
dp=[1,-1,-3,0]
now we are moving above level, level=[2,3], but we are using the data from the bottom. (That is why we are using dynamic programming). From 2, its index is 0, so I ask myself what is the minimum between 0'th and 1'st value of the dp array. Whichever is minimum we add it to 2? Obviously, -1 is minimum, 2+(-1)=1 and dp gets updated.
dp=[1, -1, -3, 0]
We do the same for 3. its index is 1, and we ask what is the min(-1,3), because 3 is pointing to -1 and 3 and then we add -1 to 3 which is 2. new dp
dp=[1,0,-3,0]
Now we are at the root level. -1 and its index is 0. We ask what is min value of index 0'th and index 1'st of the dp array. min(1,0)=0 and we add it to -1. dp gets updated
dp=[-1,0,3,0]
and finally, we return dp[0]=0
Here is the code in python:
from typing import List
class Solution:
def min_total(self,triangle:List[List[int]])->int:
# dp[] is the bottom row
dp=[0]*(len(triangle)+1)
// triangle[::-1] says start from the last element of triangle
for row in triangle[::-1]:
for i,n in enumerate(row):
dp[i]=n+min(dp[i],dp[i+1])
return dp[0]
Here is javascript code:
function minPath(triangle) {
let dp = new Array(triangle.length + 1).fill(0);
for (let row = triangle.length - 1; row >= 0; row--) {
for (let i = 0; i <= triangle[row].length - 1; i++) {
dp[i] = triangle[row][i] + Math.min(dp[i], dp[i + 1]);
}
}
console.log(dp);
return dp[0];
}
const triangle = [[-1], [2, 3], [1, -1, -3]];
console.log(minPath(triangle));
As this was brought back up, it's worth pointing out that the dynamic programming technique discussed in answers and comments can be done very simply with a reduceRight:
const minSum = (triangle) =>
triangle .reduceRight ((ms, ns) => ns .map (
(n, i) => n + (i > ms.length ? ms[i] : Math .min (ms [i], ms [i + 1]))
)) [0]
console .log (minSum ([[-1], [2, 3], [1, -1, -3]])) //=> -1
console .log (minSum ([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]])) //=> 11
console .log (minSum ([[-10]])) //=> -10
At each step we calculate the minimum paths through all the elements in a row. ms is the minimum paths through the row below (and on the initial pass will just be the bottom row) and for each n in our row ns, if we're at the rightmost element, we just copy the value from the corresponding row below, otherwise we take the minimum of the element right below and the one to its right.
Since this is called a triangle, I think we can assume that the first row has only one element. But if that's not the case, we could simply take the minimum of the results rather than taking the first element in the final value. That is, we could replace triangle .reduceRight ( ... ) [0] with Math .min (... triangle .reduceRight ( ... )).
/*
[120] Triangle
https://leetcode.com/problems/triangle/description/
*/
import java.util.List;
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
if (triangle.size() == 0)
return 0;
int rows = triangle.size();
int cols = triangle.get(rows - 1).size();
int[] tmp = new int[cols];
int index = 0;
for (int var : triangle.get(rows - 1)) {
tmp[index++] = var;
}
for (int i = rows - 2; i >= 0; i--) {
for (int j = 0; j <= triangle.get(i).size() - 1; j++) {
tmp[j] = triangle.get(i).get(j) + Math.min(tmp[j], tmp[j + 1]);
}
}
return tmp[0];
}
}

Animation in JavaScript with Modulo

Is it possible, to store the logged numbers from this loop in an array? I have to solve something like this: Some people turn up in rows of two. When they line up, one is remaining. Same as the show up in rows of three, four, five and six people. But as people turn up in rows of seven, no one is left (the result is 301).
I have to animate this "people", which show up, for every row separately, until 301. It should be a little game with user input (or just buttons). I tried with something like below, but I don't even know, if I'm completely wrong.
I thought, that it would work, if I try to store the output in an array and making a for...in-loop, to display the "people-animation" for each number in the array. I would be so happy, if would get some help or just a little hint, thank you so much! I'm completely new to this and I'm desperate.
I already have a working animation-script (for one "people").
var seven = 7;
var six;
var five;
var four;
var three;
var two;
while (six != 1 || five != 1|| four != 1|| three != 1|| two != 1)
{six = seven % 6;
five = seven % 5;
four = seven % 4;
three = seven % 3;
two = seven % 2;
console.log(seven);
seven += 7;}
This is a simple way to divide the number sequence in rows.
var seven = [[]];
var six = [[]];
var five = [[]];
var four = [[]];
var three = [[]];
var two = [[]];
cnt = 1;
while (cnt <= 301) {
seven[seven.length - 1].push(cnt);
six[six.length - 1].push(cnt);
five[five.length - 1].push(cnt);
four[four.length - 1].push(cnt);
three[three.length - 1].push(cnt);
two[two.length - 1].push(cnt);
if (!(cnt % 7) && (cnt < 301)) seven.push([]);
if (!(cnt % 6) && (cnt < 301)) six.push([]);
if (!(cnt % 5) && (cnt < 301)) five.push([]);
if (!(cnt % 4) && (cnt < 301)) four.push([]);
if (!(cnt % 3) && (cnt < 301)) three.push([]);
if (!(cnt % 2) && (cnt < 301)) two.push([]);
cnt++;
}
console.log(seven);
console.log(six);
console.log(five);
console.log(four);
console.log(three);
console.log(two);
Here's an improved version:
var rows = {}; // object to keep the rows
var list = [...Array(8).keys()].slice(2); //creates a 2 to 7 range in an array
list.map(e=>rows[e] = [[]]); // initializes the rows object with empty array to store sequences
cnt = 1; //counter
while (cnt <= 301) {
//for each row type (2 to 7)
list.forEach(row=> {
// get last row list and put current number
rows[row][rows[row].length -1].push(cnt);
// if there are already enough elements in that row type
// add another row in this row type
if (!(cnt % row) && (cnt < 301)) rows[row].push([]);
});
cnt++;
}
console.log(rows);
Hope it helps you.
I hope that I understand your question correctly and that my effort is of any use to you. If I think I know what you mean is that you want to add rows divided into columns. For example 7 people divided over 3 columns equals:
...
...
.
or in an array with numbers:
[
3,
3,
1
]
And that the length of each column can be dynamically set, by either you or the user, but adding 7 people (in your case) with each set of rows.
I've build a class with which you can create an object which stores all of your values and can do the calculations needed when adding a row. You would be able to use this in your game and let you are the user decide in how many columns people should be added.
Try it out and let me know if I understood your question correctly as mine and #NelsonTeixeira's answer differ so vastly.
class Crowd {
/**
* Store maxColumnLength and setup the default peopleLimit.
*/
constructor(maxColumnLength, peopleLimit = 301) {
this.maxColumnLength = maxColumnLength;
this.peopleLimit = peopleLimit;
this.totalPeople = 0;
this.rows = [];
}
/**
* Adds a new set of rows to the main rows collection
*
* #param {number} columnLength
* #return {this}
*/
addPeopleInColumnsOf(columnLength) {
if (columnLength <= this.maxColumnLength && this.totalPeople + this.maxColumnLength <= this.peopleLimit) {
// Create rows and calculate columns.
let row = [];
const amountOfFullRows = Math.floor(this.maxColumnLength / columnLength);
const peopleInLastRow = this.maxColumnLength % columnLength;
// Add all the full rows to the array.
for (let i = 0; i < amountOfFullRows; i++) {
row.push(columnLength);
}
// Add the last row to the array.
if (peopleInLastRow !== 0) {
row.push(peopleInLastRow);
}
// Push new rows to main row collection.
// And add the total.
this.rows.push(row);
this.totalPeople += this.maxColumnLength;
}
return this;
}
/**
* Outputs each row in the console.
*/
showRows() {
this.rows.forEach(row => {
console.log(row);
});
}
}
/**
* Create an instance with a maximum column
* length of 7 and start adding people in columns of...
*/
const crowd = new Crowd(7)
.addPeopleInColumnsOf(4)
.addPeopleInColumnsOf(5)
.addPeopleInColumnsOf(6)
.addPeopleInColumnsOf(2)
.addPeopleInColumnsOf(3)
.addPeopleInColumnsOf(4)
.addPeopleInColumnsOf(8) // This one will silently fail.
.addPeopleInColumnsOf(1)
.addPeopleInColumnsOf(6);
// Show the results
crowd.showRows();
console.log(crowd.totalPeople);

How to make a string palindrome?

Create a function which takes a string as parameter. Return the shortest palindrome formed by adding the letter to that string.
"abc" // cbabc
"21234" // 4321234
"321234" // 4321234
"a" // a
What I have tried so far is below.
function isPal(str){
return [...str].reverse().join('') === str;
}
function palindrome(s){
if(isPal(s)) return s;
for(let i = 0;i<s.length;i++){
if(isPal(s)) return s;
s = s.slice(0,i) + s[s.length - 1 - i] + s.slice(i)
}
return s;
}
console.log(palindrome('abc'))
console.log(palindrome('321234'))
console.log(palindrome('21234'))
console.log(palindrome('a'))
The code works fine but its not efficient because its checking for isPal during each iteration.
I would like to know the efficient solution for the problem. I can't calculate the time-complexity of the solution but its clears it not linear. I want to know the solution with linear time-complexity or better than mine.
Make r = reversed string (s)
Find the longest suffix of r equal to prefix of s (checking char by char)
a b c
c b a
for another example
2 1 2 3 4
4 3 2 1 2
but better variant does exist:
2 1 2 3 4
4 3 2 1 2
Note that you really don't need to build reversed string - just use corresponding indexes
Both operations should be linear.
Edit: Modified code exploiting z-function
(thanks #Kalido for pointing to abcdba test case)
It is possible to use z-function mentioned in your earlier theme. I am not familiar with JS (enough to properly make result strings), so just made z-array for comparison of string suffix with prefix of reversed one (note index mangling in the right part here s[z[i]] == s[n - 1 - i - z[i]])
Code looks for the largest value z[maxi] except for the first item. The first item is used only if it is equal to n (string already is palindrome). Result is length of prefix to add.
For example, 21234 gives z[maxi]=3, so function returns 2 (we add prefix of 43212of length 5-3=2), ie 43 = > 43 21234
cabac gives z[0] = 5 = n, result is zero, so we don't need to add anything
abcdba gives z[0] = 2 < n, so we choose maximum among other items
function ex_z_function(s) {
var n = s.length;
var z = Array(n).fill(0);
var i, l, r, maxi = 1;
for (i = 0, l = 0, r = 0; i < n; ++i) {
if (i <= r)
z[i] = Math.min(r - i + 1, z[i - l]);
while (i + z[i] < n && s[z[i]] == s[n - 1 - i - z[i]])
++z[i];
if ((i > 0) && (z[i] > z[maxi]))
maxi = i;
if (i + z[i] - 1 > r)
l = i, r = i + z[i] - 1;
}
if (z[0] == n) {
return 0;
}
return n - z[maxi];
}
console.log(ex_z_function("a"));
console.log(ex_z_function("abc"));
console.log(ex_z_function("abac"));
console.log(ex_z_function("cabac"));
console.log(ex_z_function("21234"));
console.log(ex_z_function("abcdba"));
console.log(ex_z_function("abacaba"));
console.log(ex_z_function("vfvcabgvcvfv"));
You could already gain a lot of time on your isPal function by just checking half the string, or return if the check fails early:
function isPal(str){
for (let i = 0, l = str.length; i < l / 2; i++) {
if (str[i] != str[l-i-1]) {
return false
}
}
return true
}
console.log(isPal('kayak'))
console.log(isPal('toot'))
console.log(isPal('john'))
https://jsperf.com/palindrome-detection
Note: the complexity of isPal remains linear but the best case is far better.

Generate all combinations for pair of bits set to 1?

I'm trying to generate all possible combinations for pair of 1's within given bit width.
Let's say the bit width is 6, i.e. number 32. This is what I would like to generate:
000000
000011
000110
001100
001111
011000
011011
011110
110000
110011
110110
111100
111111
If I have variables:
var a = 1,
b = 2;
num = a | b;
and create a loop that I'll loop over width - 1 times, and where I shift both a << 1 and b << 1, I'll get all combinations for one pair. After that, I'm pretty much stuck.
Could someone , please, provide some help.
Update: working example
Based on Barmar's mathematical approach, this is what I managed to implement
var arr = [],
arrBits = [];
function getCombs(pairs, startIdx) {
var i, j, val = 0, tmpVal, idx;
if (startIdx + 2 < pairs) {
startIdx = arr.length - 1;
pairs -= 1;
}
if (pairs < 2) {
return;
}
for (i = 0; i < pairs-1; i++) {
idx = startIdx - (i * 2);
val += arr[idx];
}
for (j = 0; j < idx - 1; j++) {
arrBits.push((val + arr[j]).toString(2));
}
getCombs(pairs, startIdx-1);
}
(function initArr(bits) {
var i, val, pairs, startIdx;
for (i = 1; i < bits; i++) {
val = i == 1 ? 3 : val * 2;
arr.push(val);
arrBits.push(val.toString(2));
}
pairs = Math.floor(bits / 2);
startIdx = arr.length - 1;
getCombs(pairs, startIdx);
console.log(arrBits);
}(9));
Working example on JSFiddle
http://jsfiddle.net/zywc5/
The numbers with exactly one pair of 1's are the sequence 3, 6, 12, 24, 48, ...; they start with 3 and just double each time.
The numbers with two pairs of 1's are 12+3, 24+3, 24+6, 48+3, 48+6, 48+12, ...; these are the above sequence starting at 12 + the original sequence up to n/4.
The numbers with three pairs of 1's are 48+12+3, 96+12+3, 96+24+3, 96+24+6, ...
The relationship between each of these suggests a recursive algorithm making use of the original doubling sequence. I don't have time right now to write it, but I think this should get you going.
if the bit width isn't that big then you'll be way better off creating bit representations for all numbers from 0 to 31 in a loop and simply ignore the ones that have an odd number of "ones" in the bit representation.
Maybe start counting normally in binary and replace all 1's with 11's like this:
n = 5
n = n.toString(2) //= "101"
n = n.replace(/1/g, "11") //= "11011"
n = parseInt(n, 2) //= 27
So you'll get:
0 -> 0
1 -> 11
10 -> 110
11 -> 1111
100 -> 1100
101 -> 11011
110 -> 11110
111 -> 111111
And so on. You'll have to count up to 31 or so on the left side, and reject ones longer than 6 bits on the right side.
See http://jsfiddle.net/SBH6R/
var len=6,
arr=[''];
for(var i=0;i<len;i++){
for(var j=0;j<arr.length;j++){
var k=j;
if(getNum1(arr[j])%2===1){
arr[j]+=1;
}else{
if(i<len-1){
arr.splice(j+1,0,arr[j]+1);
j++;
}
arr[k]+=0;
}
}
}
function getNum1(str){
var n=0;
for(var i=str.length-1;i>=0;i--){
if(str.substr(i,1)==='1'){n++;}
else{break;}
}
return n;
}
document.write(arr.join('<br />'));
Or maybe you will prefer http://jsfiddle.net/SBH6R/1/. It's simpler, but then you will have to sort() the array:
var len=6,
arr=[''];
for(var i=0;i<len;i++){
for(var k=0,l=arr.length;k<l;k++){
if(getNum1(arr[k])%2===1){
arr[k]+=1;
}else{
if(i<len-1){
arr.push(arr[k]+1);
}
arr[k]+=0;
}
}
}
function getNum1(str){
var n=0;
for(var i=str.length-1;i>=0;i--){
if(str.substr(i,1)==='1'){n++;}
else{break;}
}
return n;
}
document.write(arr.sort().join('<br />'));
See http://jsperf.com/generate-all-combinations-for-pair-of-bits-set-to-1 if you want to compare the performance. It seems that the fastest code is the first one on Chrome but the second one on Firefox.
You can also do this with bit twiddling. If the lowest two bits are zero, we need to set them, which is equivalent to adding 3. Otherwise, we need to replace the lowest block of ones by its top bit and a 1-bit to the left of it. This can be done as follows, where x is the current combination:
x3 = x + 3;
return (((x ^ x3) - 2) >> 2) + x3;

Categories

Resources