Skip to main content
added 163 characters in body
Source Link
konijn
  • 33.8k
  • 5
  • 69
  • 264
//H4ck: We trust that n is part of the list
function removeNumber(list, n){
  list.splice(list.indexOf(n), 1);
  return list;
}

//Takes a string that looks like a positive integer number 
//and returns the next bigger number formed by the same digits
//Return the same number if we can not find a next bigger number
function nextBiggerString(s){
  
  let digits = s.split('');
  let wip = [...digits]; //Work in progress
    
  //Special case we don't want to deal with, 2 digits
  //Very useful for a recursive approach
  if(digits.length == 2){
    //Don't reverse if we are already at max
    return Math.max(digits.reverse().join(""), s);
  }
  
  //First digit has to be equal or next biggest after target digit to make sense
  const target = digits[0];
  //Only keep valid starting candidates 
  wip = wip.sort().filter(i=>i>target);
  //Very often the solution is option 1, kicking the can down the road
  const option1 = target + nextBiggerString(s.slice(1));
  if(wip.length==0){
    //The first digit was the highest digit of them all, so we can only kick the can
    return option1;
  }else{
    if(option1 != s){
      //Only return option1 is it different from what we started with
      return option1
    } else{
      //Otherwise take the next digit, and sort the rest ascendingly
        return wip[0] + removeNumber(digits,wip[0]).sort().join('');      
    }   
  }
}

//Takes a positive integer number and returns the next bigger number formed by the same digits
//Return -1 if we cant find a next bigger number
//this uses a stringbased biggerString because this uses an iterative solution
//where for example 034 from 1034 becomes 34, which would return then 143
function nextBigger(n){
  const maybe = nextBiggerString(String(n))*1;
  return maybe == n ? -1 : maybe;
}


console.log(nextBigger(12));
console.log(nextBigger(513));
console.log(nextBigger(531));
console.log(nextBigger(2017));
console.log(nextBigger(2721));
//H4ck: We trust that n is part of the list
function removeNumber(list, n){
  list.splice(list.indexOf(n), 1);
  return list;
}

//Takes a string that looks like a positive integer number 
//and returns the next bigger number formed by the same digits
//Return the same number if we can not find a next bigger number
function nextBiggerString(s){
  
  let digits = s.split('');
  let wip = [...digits]; //Work in progress
    
  //Special case we don't want to deal with, 2 digits
  //Very useful for a recursive approach
  if(digits.length == 2){
    //Don't reverse if we are already at max
    return Math.max(digits.reverse().join(""), s);
  }
  
  //First digit has to be equal or next biggest after target digit to make sense
  const target = digits[0];
  //Only keep valid starting candidates 
  wip = wip.sort().filter(i=>i>target);
  //Very often the solution is option 1, kicking the can down the road
  const option1 = target + nextBiggerString(s.slice(1));
  if(wip.length==0){
    //The first digit was the highest digit of them all, so we can only kick the can
    return option1;
  }else{
    if(option1 != s){
      //Only return option1 is it different from what we started with
      return option1
    } else{
      //Otherwise take the next digit, and sort the rest ascendingly
        return wip[0] + removeNumber(digits,wip[0]).sort().join('');      
    }   
  }
}

//Takes a positive integer number and returns the next bigger number formed by the same digits
//Return -1 if we cant find a next bigger number
function nextBigger(n){
  const maybe = nextBiggerString(String(n))*1;
  return maybe == n ? -1 : maybe;
}


console.log(nextBigger(12));
console.log(nextBigger(513));
console.log(nextBigger(531));
console.log(nextBigger(2017));
console.log(nextBigger(2721));
//H4ck: We trust that n is part of the list
function removeNumber(list, n){
  list.splice(list.indexOf(n), 1);
  return list;
}

//Takes a string that looks like a positive integer number 
//and returns the next bigger number formed by the same digits
//Return the same number if we can not find a next bigger number
function nextBiggerString(s){
  
  let digits = s.split('');
  let wip = [...digits]; //Work in progress
    
  //Special case we don't want to deal with, 2 digits
  //Very useful for a recursive approach
  if(digits.length == 2){
    //Don't reverse if we are already at max
    return Math.max(digits.reverse().join(""), s);
  }
  
  //First digit has to be equal or next biggest after target digit to make sense
  const target = digits[0];
  //Only keep valid starting candidates 
  wip = wip.sort().filter(i=>i>target);
  //Very often the solution is option 1, kicking the can down the road
  const option1 = target + nextBiggerString(s.slice(1));
  if(wip.length==0){
    //The first digit was the highest digit of them all, so we can only kick the can
    return option1;
  }else{
    if(option1 != s){
      //Only return option1 is it different from what we started with
      return option1
    } else{
      //Otherwise take the next digit, and sort the rest ascendingly
        return wip[0] + removeNumber(digits,wip[0]).sort().join('');      
    }   
  }
}

//Takes a positive integer number and returns the next bigger number formed by the same digits
//Return -1 if we cant find a next bigger number
//this uses a stringbased biggerString because this uses an iterative solution
//where for example 034 from 1034 becomes 34, which would return then 143
function nextBigger(n){
  const maybe = nextBiggerString(String(n))*1;
  return maybe == n ? -1 : maybe;
}


console.log(nextBigger(12));
console.log(nextBigger(513));
console.log(nextBigger(531));
console.log(nextBigger(2017));
console.log(nextBigger(2721));
Source Link
konijn
  • 33.8k
  • 5
  • 69
  • 264

Stimulating question;

Both the edit of @dustytrash and the comment of @Ry are giving a great hint.

But before we go there, let's look at this part:

  let newNum = 0;
  let otherNum = 0;
  let indicator = 0;
  while (num > newNum) {
    if (indicator === 0) {
      otherNum = num;
      indicator++;
      continue;
    }

You are setting up otherNum up within the loop, you only do it once with indicator but you are still performing an if statement every cycle. You can just drop indicator completely and start with the smallest possible value of otherNum:

  let otherNum = num + 1;
  while (num > newNum) {

Then you can replace this part:

  if (otherNum > num) {
    newNum = otherNum;
  }

with simply a return statement there:

if (String(num).split("").sort().join("") === String(otherNum).split("").sort().join(""){
        return otherNum;
}

You would not need newNum at all any more. Still, to your point in the question, we are looking for more than minor tweaks.

This code basically tries out every integer between num and the solution, that is to say potentially a ton of numbers. For 2017 -> 2071 there are 54 tries, but there are only 24 possible combinations with 4 digits (432*1). From those 24 possible combinations we know that none of the combinations can start with either 0 or 1 because that would give a number smaller than 2017. Which leaves us with only 12 combinations to test.

To go further, if we want to check the next big number of 2341, we know that the next biggest number starts with either 2 possibly, or 3. I could not be 1 since then the number is too small, it could not be 4 because any number starting with 4 is going to be both greater than any number starting with 3.

Finally, we know that if the next biggest number started with '3', we should just apply the remaining digits from low to high (so 3124), there is no way to make a lower number than that.

This is my rewrite, very commented since I am still wrapping my brains around it a bit, but it seems to work. I made one small change for my benefit, the code returns -1 if it cannot find a bigger number with the same digits.

(Which is another issue with your code, it seems that running it for say 531, it will run forever).

//H4ck: We trust that n is part of the list
function removeNumber(list, n){
  list.splice(list.indexOf(n), 1);
  return list;
}

//Takes a string that looks like a positive integer number 
//and returns the next bigger number formed by the same digits
//Return the same number if we can not find a next bigger number
function nextBiggerString(s){
  
  let digits = s.split('');
  let wip = [...digits]; //Work in progress
    
  //Special case we don't want to deal with, 2 digits
  //Very useful for a recursive approach
  if(digits.length == 2){
    //Don't reverse if we are already at max
    return Math.max(digits.reverse().join(""), s);
  }
  
  //First digit has to be equal or next biggest after target digit to make sense
  const target = digits[0];
  //Only keep valid starting candidates 
  wip = wip.sort().filter(i=>i>target);
  //Very often the solution is option 1, kicking the can down the road
  const option1 = target + nextBiggerString(s.slice(1));
  if(wip.length==0){
    //The first digit was the highest digit of them all, so we can only kick the can
    return option1;
  }else{
    if(option1 != s){
      //Only return option1 is it different from what we started with
      return option1
    } else{
      //Otherwise take the next digit, and sort the rest ascendingly
        return wip[0] + removeNumber(digits,wip[0]).sort().join('');      
    }   
  }
}

//Takes a positive integer number and returns the next bigger number formed by the same digits
//Return -1 if we cant find a next bigger number
function nextBigger(n){
  const maybe = nextBiggerString(String(n))*1;
  return maybe == n ? -1 : maybe;
}


console.log(nextBigger(12));
console.log(nextBigger(513));
console.log(nextBigger(531));
console.log(nextBigger(2017));
console.log(nextBigger(2721));