well this is problem number 12 on projecteuler website:
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
and here's my code (I'm new to Javascript)
let num = 1;
let add= 1;
let divisors = [];
while (divisors.length < 500){
divisors = []
for(let i = 1; i <= num; i++){
if(num % i == 0){
divisors.push(i);
}
}
add ++;
num += add;
}
console.log(num - add)
this code run fine when I change the while loop condition to 300 or less.
and this code running on Intel i7 Q740 1.75GHz.
when I try it nothing shows up on console and my question is that's because of my CPU and lack of power or my code has issue? I wait about 20 mins and still nothing as result.
This code is not very efficient as #Vasil Dininski pointed out but you won't reach the max Integer you just have to wait a while for your program to calculate.
I would recommend to optimize your code e.g. by writing a simple function which returns your number of divisors for your current number.
This could look similar to this:
function numberOfDivisors(num) {
var numOfDivisors = 0;
var sqrtOfNum = Math.sqrt(num);
for(var i = 1; i <= sqrtOfNum; i++) {
if(num % i == 0) {
numOfDivisors += 2;
}
}
// if your number is a perfect square you have to reduce it by one
if(sqrtOfNum * sqrtOfNum == num) {
numOfDivisors--;
}
return numOfDivisors;
}
Then you could use this method in your while loop like this:
var maxNumOfDivisors = 500;
var num = 0;
var i = 1;
while(numberOfDivisors(num) < maxNumOfDivisors) {
num += i;
i++;
}
which would return you the correct triangular number.
Please also note that triangular numbers start at 0 which is why my num is 0.
As you might have noticed, this algorithm might be a bit brute-force. A better one would be combine a few things. Let's assume the number we're looking for is "n":
Find all prime numbers in the range [1, square root of n]. You will
be iterating over n, so the sieve of
eratosthenes
will help in terms of efficiency (you can memoize primes you've already found)
Given that any number can be expressed as a prime number to some power, multiplied by a prime number to some power, etc. you can find all the combinations of those primes to a power, which are divisors of n.
This would be a more efficient, albeit a more complicated way to find them. You can take a look at this quora answer for more details: https://www.quora.com/What-is-an-efficient-algorithm-to-find-divisors-of-any-number
If my calculation is not wrong, you add one more to each next divisor from previous divisor and you get final result.
let prev = 0;
for(let i=0; i < 500; i++) {
prev = prev + i;
}
console.log("AA ", prev);
Related
A friend of mine takes a sequence of numbers from 1 to n (where n > 0)
Within that sequence, he chooses two numbers, a and b
He says that the product of a and b should be equal to the sum of all numbers in the sequence, excluding a and b
Given a number n, could you tell me the numbers he excluded from the sequence?
Have found the solution to this Kata from Code Wars but it times out (After 12 seconds) in the editor when I run it; any ideas as too how I should further optimize the nested for loop and or remove it?
function removeNb(n) {
var nArray = [];
var sum = 0;
var answersArray = [];
for (let i = 1; i <= n; i++) {
nArray.push(n - (n - i));
sum += i;
}
var length = nArray.length;
for (let i = Math.round(n / 2); i < length; i++) {
for (let y = Math.round(n / 2); y < length; y++) {
if (i != y) {
if (i * y === sum - i - y) {
answersArray.push([i, y]);
break;
}
}
}
}
return answersArray;
}
console.log(removeNb(102));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think there is no reason for calculating the sum after you fill the array, you can do that while filling it.
function removeNb(n) {
let nArray = [];
let sum = 0;
for(let i = 1; i <= n; i++) {
nArray.push(i);
sum += i;
}
}
And since there could be only two numbers a and b as the inputs for the formula a * b = sum - a - b, there could be only one possible value for each of them. So, there's no need to continue the loop when you find them.
if(i*y === sum - i - y) {
answersArray.push([i,y]);
break;
}
I recommend looking at the problem in another way.
You are trying to find two numbers a and b using this formula a * b = sum - a - b.
Why not reduce the formula like this:
a * b + a = sum - b
a ( b + 1 ) = sum - b
a = (sum - b) / ( b + 1 )
Then you only need one for loop that produces the value of b, check if (sum - b) is divisible by ( b + 1 ) and if the division produces a number that is less than n.
for(let i = 1; i <= n; i++) {
let eq1 = sum - i;
let eq2 = i + 1;
if (eq1 % eq2 === 0) {
let a = eq1 / eq2;
if (a < n && a != i) {
return [[a, b], [b, a]];
}
}
}
You can solve this in linear time with two pointers method (page 77 in the book).
In order to gain intuition towards a solution, let's start thinking about this part of your code:
for(let i = Math.round(n/2); i < length; i++) {
for(let y = Math.round(n/2); y < length; y++) {
...
You already figured out this is the part of your code that is slow. You are trying every combination of i and y, but what if you didn't have to try every single combination?
Let's take a small example to illustrate why you don't have to try every combination.
Suppose n == 10 so we have 1 2 3 4 5 6 7 8 9 10 where sum = 55.
Suppose the first combination we tried was 1*10.
Does it make sense to try 1*9 next? Of course not, since we know that 1*10 < 55-10-1 we know we have to increase our product, not decrease it.
So let's try 2*10. Well, 20 < 55-10-2 so we still have to increase.
3*10==30 < 55-3-10==42
4*10==40 < 55-4-10==41
But then 5*10==50 > 55-5-10==40. Now we know we have to decrease our product. We could either decrease 5 or we could decrease 10, but we already know that there is no solution if we decrease 5 (since we tried that in the previous step). So the only choice is to decrease 10.
5*9==45 > 55-5-9==41. Same thing again: we have to decrease 9.
5*8==40 < 55-5-8==42. And now we have to increase again...
You can think about the above example as having 2 pointers which are initialized to the beginning and end of the sequence. At every step we either
move the left pointer towards right
or move the right pointer towards left
In the beginning the difference between pointers is n-1. At every step the difference between pointers decreases by one. We can stop when the pointers cross each other (and say that no solution can be obtained if one was not found so far). So clearly we can not do more than n computations before arriving at a solution. This is what it means to say that the solution is linear with respect to n; no matter how large n grows, we never do more than n computations. Contrast this to your original solution, where we actually end up doing n^2 computations as n grows large.
Hassan is correct, here is a full solution:
function removeNb (n) {
var a = 1;
var d = 1;
// Calculate the sum of the numbers 1-n without anything removed
var S = 0.5 * n * (2*a + (d *(n-1)));
// For each possible value of b, calculate a if it exists.
var results = [];
for (let numB = a; numB <= n; numB++) {
let eq1 = S - numB;
let eq2 = numB + 1;
if (eq1 % eq2 === 0) {
let numA = eq1 / eq2;
if (numA < n && numA != numB) {
results.push([numA, numB]);
results.push([numB, numA]);
}
}
}
return results;
}
In case it's of interest, CY Aries pointed this out:
ab + a + b = n(n + 1)/2
add 1 to both sides
ab + a + b + 1 = (n^2 + n + 2) / 2
(a + 1)(b + 1) = (n^2 + n + 2) / 2
so we're looking for factors of (n^2 + n + 2) / 2 and have some indication about the least size of the factor. This doesn't necessarily imply a great improvement in complexity for the actual search but still it's kind of cool.
This is part comment, part answer.
In engineering terms, the original function posted is using "brute force" to solve the problem, iterating every (or more than needed) possible combinations. The number of iterations is n is large - if you did all possible it would be
n * (n-1) = bazillio n
Less is More
So lets look at things that can be optimized, first some minor things, I'm a little confused about the first for loop and nArray:
// OP's code
for(let i = 1; i <= n; i++) {
nArray.push(n - (n - i));
sum += i;
}
??? You don't really use nArray for anything? Length is just n .. am I so sleep deprived I'm missing something? And while you can sum a consecutive sequence of integers 1-n by using a for loop, there is a direct and easy way that avoids a loop:
sum = ( n + 1 ) * n * 0.5 ;
THE LOOPS
// OP's loops, not optimized
for(let i = Math.round(n/2); i < length; i++) {
for(let y = Math.round(n/2); y < length; y++) {
if(i != y) {
if(i*y === sum - i - y) {
Optimization Considerations:
I see you're on the right track in a way, cutting the starting i, y values in half since the factors . But you're iterating both of them in the same direction : UP. And also, the lower numbers look like they can go a little below half of n (perhaps not because the sequence start at 1, I haven't confirmed that, but it seems the case).
Plus we want to avoid division every time we start an instantiation of the loop (i.e set the variable once, and also we're going to change it). And finally, with the IF statements, i and y will never be equal to each other the way we're going to create the loops, so that's a conditional that can vanish.
But the more important thing is the direction of transversing the loops. The smaller factor low is probably going to be close to the lowest loop value (about half of n) and the larger factor hi is probably going to be near the value of n. If we has some solid math theory that said something like "hi will never be less than 0.75n" then we could make a couple mods to take advantage of that knowledge.
The way the loops are show below, they break and iterate before the hi and low loops meet.
Moreover, it doesn't matter which loop picks the lower or higher number, so we can use this to shorten the inner loop as number pairs are tested, making the loop smaller each time. We don't want to waste time checking the same pair of numbers more than once! The lower factor's loop will start a little below half of n and go up, and the higher factor's loop will start at n and go down.
// Code Fragment, more optimized:
let nHi = n;
let low = Math.trunc( n * 0.49 );
let sum = ( n + 1 ) * n * 0.5 ;
// While Loop for the outside (incrementing) loop
while( low < nHi ) {
// FOR loop for the inside decrementing loop
for(let hi = nHi; hi > low; hi--) {
// If we're higher than the sum, we exit, decrement.
if( hi * low + hi + low > sum ) {
continue;
}
// If we're equal, then we're DONE and we write to array.
else if( hi * low + hi + low === sum) {
answersArray.push([hi, low]);
low = nHi; // Note this is if we want to end once finding one pair
break; // If you want to find ALL pairs for large numbers then replace these low = nHi; with low++;
}
// And if not, we increment the low counter and restart the hi loop from the top.
else {
low++;
break;
}
} // close for
} // close while
Tutorial:
So we set the few variables. Note that low is set slightly less than half of n, as larger numbers look like they could be a few points less. Also, we don't round, we truncate, which is essentially "always rounding down", and is slightly better for performance, (though it dosenit matter in this instance with just the single assignment).
The while loop starts at the lowest value and increments, potentially all the way up to n-1. The hi FOR loop starts at n (copied to nHi), and then decrements until the factor are found OR it intercepts at low + 1.
The conditionals:
First IF: If we're higher than the sum, we exit, decrement, and continue at a lower value for the hi factor.
ELSE IF: If we are EQUAL, then we're done, and break for lunch. We set low = nHi so that when we break out of the FOR loop, we will also exit the WHILE loop.
ELSE: If we get here it's because we're less than the sum, so we need to increment the while loop and reset the hi FOR loop to start again from n (nHi).
Today I was doing a simple challenge on HackerRank with the code below, which is 100% acceptable and works, but I was wondering if there was a way to even further reduce the loops required by eliminating duplicate calculations.
Let me show you visually what's happening, By the time I'm done, my code example is going to be very far down!
The code takes the first number in an array of numbers and adds it to each subsequent number and checks if its divisible by k = 3.
In an array of 6 numbers, that equates to 15 loops, which would be O(n²), meaning that my loops will grow exponentially to the amount of input. 7 numbers would be 21 loops.
P.S., you might be thinking that 6 should be 21 loops, and 7 should be 28, but keep in mind that I'm always taking the current number and adding it to the next, with the exception of the last number.
Visual Breakdown
input: [1, 3, 2, 6, 1, 2]
1+3, 1+2, 1+6, 1+1, 1+2
3+2, 3+6, 3+1, 3+2
2+6, 2+1, 2+2
6+1, 6+2
1+2
Explanation
If you look at the numbers I've put in bold, you'll see they're duplicate calculations. The italics numbers are numbers divisible by k = 3. Now we're getting to my meat of my question. How can I eliminate this duplicate math, which would bring my loops down from 15 to 8 in this particular example. The algorithm would still have a worse case scenario of O(n²), if all the numbers were different, but this would be an optimization nonetheless.
Code Demo
function divisibleSumPairs(k, a) {
let pairs = 0;
for (let i = 0; i < a.length - 1; i++) {
for (let j = i + 1; j < a.length; j++) {
if ((a[i] + a[j])/k % 1 === 0) pairs++;
}
}
console.log(pairs);
}
divisibleSumPairs(3, [ 1, 3, 2, 6, 1, 2 ])
I spent awhile thinking about how I can preprocess the array of numbers to prevent duplicate calculations, then I stepped away for a bit, and came back to the problem with a clear head and a cold drink of water.
Then I thought "What if I preprocess the divisor instead"?
The downside of this approach is that it creates and array of equal size to the divisor, but it does it in O(n) time complexity (screw space complexity, lol)
For this particular example we have 3 loops for the divisor, and 6 loops for the calculation, for a total of 9 loops, which is a savings of 6 loops over the original solution, and an elimination of O(n²).
This results in my function having an overall time complexity of O(n)
function divisibleSumPairs(k, a) {
const mod = new Array(k).fill(0);
let pairs = 0;
for (let i = 0; i < a.length; i++) {
const position = a[i] % k;
pairs += mod[(k - position) % k];
mod[position]++;
}
console.log(pairs);
}
divisibleSumPairs(3, [ 1, 3, 2, 6, 1, 2 ])
Performance Testing
I ran several iterations of my code through a performance test, I was surprised to see how much better a simple for loop compared to forEach and reduce.
for^2: the original code
for: the code in this post
forEach: this post, using forEach instead
reduce: this post, using reduce instead
https://jsperf.com/for-2-vs-for-vs-foreach-vs-reduce/1
To achieve this dynamic problem
Try to store the result in Object lets say sum_map if found this means we have already calculated this sum if not calculate the sum and store the result in map for future reference.
sample snippet:
let d = [1, 3, 2, 6, 1, 2]
const len = d.length
const sum_map = {}
let pairs = 0
for (let i = 0; i < d.length - 1; i++) {
for (let j = i + 1; j < d.length; j++) {
const key1 = `${d[i]}_${d[j]}`
const key2 = `${d[j]}_${d[i]}`
let result = 0
if (sum_map[key1]) {
result = sum_map[key1]
} else if (sum_map[key2]) {
result = sum_map[key2]
} else {
result = d[j] + d[i]
sum_map[`${d[i]}_${d[j]}`] = result
}
if (result % 3 === 0) {
pairs += 1
}
}
}
console.log(pairs)
In order to avoid O(n^2) simple trick is to know that
Example
lets say number you are checking with is 5 and arr = [1,3,2,6,1,2,5]
you will only find sums divisible by the number if its numbers compliment remainder is present.
like for example number pair divisible by 5 are only ones which gives a compliment remainder i.e. 3 % 5 = 2 and 2 % 5 = 3 so the sum will be divisible by 5
so to solve this just find the compliment remainders and choose from them
like say you are 3 nums giving remainder 2 and 4 nums giving remainder 3
so pairs will choose 1 from those 3 nums * choose 1 from those 4 nums
if number is divisible by 5 but if its only 1 its sum will never be divisible.
code snippet:
let d = [1, 3, 2, 6, 1, 2, 5]
const check_div_num = 5
remainder_map = {}
mod_arr = d.map((i) =>{
const rem = i % 5
if(remainder_map[rem]) {
remainder_map[rem] += 1
} else {
remainder_map[rem] = 1
}
return rem
})
const till = Math.floor(check_div_num / 2)
keys = Object.keys(remainder_map)
let pairs = 0
for (let j = 0; j < keys.length; j++) {
const key = keys[j]
if(key === '0' && remainder_map["0"] > 1) {
pairs += remainder_map[key] / 2
continue
}
if(Number(key) <= till) {
let compliment = remainder_map[check_div_num - Number(key)]
const compliemnt_key = check_div_num - Number(key)
if(compliment) {
pairs += remainder_map[key]*remainder_map[compliemnt_key.toString()]
} else {
continue
}
} else {
break
}
}
console.log(pairs)
mind here I am only looping till half of 5 i.e. Math.floor(5/2) as we are already checking for their compliment
How can I find a number within the interval (from 1 to given number) which is when decomposed into prime numbers has the maximum amount of them.
Example:
Input: 9
Output: 8
Explanation:
8 = 2 * 2 * 2 (3 primes)
7 = 7 * 1 (1 prime)
6 = 3 * 2 ( 2 primes)
And so on... At the end, we'll see that 8 has the greatest amount of primes in decomposition.
Specification:
If there're several numbers having the same amount of primes in decomposition, return the greatest of them.
Okay, I think I understood your requirement.
Here's a simple script to do what you have asked.
//source of this function: https://jsfiddle.net/JamesOR/RC7SY/
function getAllFactorsFor(remainder) {
var factors = [], i;
for (i = 2; i <= remainder; i++) {
while ((remainder % i) === 0) {
factors.push(i);
remainder /= i;
}
}
return factors;
}
function calculate(x) {
lastFactorCount = 0;
highestNumber = 0;
while (x) {
currentCount = getAllFactorsFor(x).length;
if (currentCount > lastFactorCount) {
lastFactorCount = currentCount;
highestNumber = x;
}
x--;
}
return highestNumber;
}
console.log(calculate(7)); //output: 6
console.log(calculate(11)) //output: 8
This pass the two test cases you have given. I borrowed the getAllFactorsFor() function from a jsfiddle I found since we don't need to reinvent anything ;)
calculate() function takes in an input number, then it loops through every number from x to 0, counting how many factors it has, and it keeps track of the last factor count while decrementing x in each iteration.
Finally it outputs the number with highest factor count. Simple.
Hope it helps!!
Notice that after 2 and 3, the next prime is 5, which is bigger than 2*2 (obviously). Therefore, using 2*2 will ALWAYS be better for amount of prime factors, than any higher prime. The number with the highest amount of 2 as prime factors which is still lower or equal is 2 ** Math.floor(Math.log2(num)). The only thing we need to check is whether replacing the last prime factor 2 with a 3 will still be below the number, as that may happen, and would yield a bigger number. Note again, using more than one 3 would be 3*3 = 9 > 8 = 2*2*2, which cannot be a solution again. All of that together yields that the solution should simply be
const f = num => {
let twoEnd = 2 ** Math.floor(Math.log2(num));
let threeEnd = twoEnd / 2 * 3;
return threeEnd <= num ? threeEnd : twoEnd;
}
Some handling for numbers smaller than 2 may be necessary, depending on the circumstances.
The following code results by combing common values into one:
//3,6,9,12,15------
//5,10,15----------
//result: sum of (3,5,6,9,10,12,15) = 60
int = 0;
for(var i=1;i<16;i++){
if(i%3==0 || i%5==0){
int +=i;
}
}
alert(int);//60
But I wanted to get the output without combining:
//3,6,9,12,15------|should ressult:
//5,10,15----------|75
//result without combining: sum of (3,6,9,12,15,5,10,15) == 75
If you say I should do && instead of || then it will just result common sum i.e. 15 here in example.
So, how can I do?
This will do the trick:
int = 0;
for(var i=1;i<16;i++){
if(i%3==0){
int +=i;
}
if(i%5==0){
int +=i;
}
}
alert(int);//75
Or if you prefer a more compact solution:
int = 0;
for(var i=1;i<16;i++){
int += (i % 3 ? 0 : i) + (i % 5 ? 0 : i);
}
alert(int);//75
Basically, for values that are multiples of 15, you count them twice.
Hints regarding a solution without using a loop: We can break the problem down to just list summing all the multiples of n between a and b-1. This can be computed directly without going through each number by taking a look at the sequence it produces. For n=3, a=1, b=28, this is:
3, 6, 9, 12, 15, 18, 21, 24, 27
Notice now that 27+3=30, 24+6=30, 21+9=30, 18+12=30, and there's only one outlier in the middle, 15. So really all you need to know in order to solve this is the minimum element in the sequence, the maximum element, the number of elements, and the middle element if the the number of elements is odd. (In fact you don't even really need to know the middle number once you realize that it's precisely half of the sum the min and the max).
To help you out a bit more:
var max = Math.floor((b - 1) / n) * n;
var min = a + n - (a % n);
var count = (max - min) / n + 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;