问题
Create a function that takes a positive integer and returns the next bigger number that can be formed by rearranging its digits.
To accomplish this I used the following code:
Logic used:
- Write a script do all the permutations of the number e.g. 123 -> 132,321,231,...
- select the largest number from the possible combinations
- if that number is bigger than original number provided it returns that number - if not it returns -1.
Code Block:
import itertools
def next_bigger(n):
# [int(x) for x in str(n)] ex: convert 123 to array [1,2,3]
# list(set(itertools.permutations... gives you a list of permutation e.g. [[1,3,2],[3,2,1],[2,3,1],...]
# [int(''.join(map(str,x))) for x in ... converts each permuted list into a number e.g. convert [2,3,1] -> 231
# for num in sorted(...if num>n: --> if 321 is bigger than 123, return it
for num in sorted([int(''.join(map(str,x))) for x in list(set(itertools.permutations([int(x) for x in str(n)])))]):
if num>n:
return num
else:
return -1
Expected Output:
nextBigger(num: 12) // returns 21
nextBigger(num: 513) // returns 531
nextBigger(num: 2017) // returns 2071
nextBigger(num: 9) // returns nil
nextBigger(num: 111) // returns nil
nextBigger(num: 531) // returns nil
Actual Output: Test results fail
Solution Attempt#2:
import itertools
def next_bigger(n):
# [int(x) for x in str(n)] ex: convert 123 to array [1,2,3]
# list(set(itertools.permutations... gives you a list of permutation e.g. [[1,3,2],[3,2,1],[2,3,1],...]
# [int(''.join(map(str,x))) for x in ... converts each permuted list into a number e.g. convert [2,3,1] -> 231
# for num in sorted(...if num>n: --> if 321 is bigger than 123, return it
a = []
results = 0
for num in sorted([int(''.join(map(str,x))) for x in list(set(itertools.permutations([int(x) for x in str(n)])))]):
if num>n:
a.append(num)
results = a[0]
return results
Expected output: Passes all tests cases except for long numbers
What's wrong with my code?
回答1:
The title says 'using permutations', but you don't need to use permutations for this.
The order of the tuples itertools.permutations emitted is defined; but unfortunately it will not always produce digits that when combined are in increasing order. Also calculating all permutations will take an extremely long time if the number of digits is very large.
To rephrase the question: for any given N
, what is the smallest number (N2
) such that:
0 <= N < N2
, and- The number of times each digit appears in
N
andN2
are the same
(if N2
doesn't exist, return None
)
We could start from N
and do N+=1
until condition 2 is satisfied, or until condition 2 can no longer be satisfied because the total number of digits in N
increased. (An int
in Python 3 has no defined limit for how big it can get, so we would not get an overflow.) This is still (on average) extremely slow if N
is very large, however it will in theory eventually return.
Here is how I would solve this:
def main(N):
n=list(map(int,str(N)))
for i_r in reversed(range(len(n))):
for i_l in reversed(range(i_r)):
if n[i_l]<n[i_r]:
t_l=n[i_l]
t_r=n[i_r]
n[i_l]=t_r
n[i_r]=t_l
return int(''.join(map(str,n)))
return None
First convert N
into a list of digits (while preserving the order). This will make N
easier to work on.
Make 2 markers i_l
and i_r
. i_l
and i_r
will always be on the left and right respectively. They will start on the least significant (i.e. right) side of N
.
They will go through N
like this for example:
4321 4321 4321 4321 4321 4321
lr l r l r lr l r lr
When i_l < i_r
, swap those digits to make a bigger number, which satisfies condition 1. Since i_l
and i_r
start from the least significant side of N
, that new number is the smallest number that satisfies condition 2. If that number doesn't exist, the function returns None
.
(The return None
is actually unnecessary, as functions by default return None
, however explicitly stating it makes it more clear that this is the intended behavior.)
With this solution, even if N
is 10000 digits, the function will return in a reasonable amount of time.
回答2:
You need the next biggest number, but currently you pick any
permutation-number greater than the input-number. You should be the picking the minimum among such numbers
Also notice, for example for input 9
or 111
; there are no other permutations; so you might just want to return the next biggest-permutation or None
.
You might consider modifying to this:
import itertools
def next_bigger(n):
# [int(x) for x in str(n)] ex: convert 123 to array [1,2,3]
# list(set(itertools.permutations... gives you a list of permutation e.g. [[1,3,2],[3,2,1],[2,3,1],...]
# [int(''.join(map(str,x))) for x in ... converts each permuted list into a number e.g. convert [2,3,1] -> 231
# for num in sorted(...if num>n: --> if 321 is bigger than 123, return it
minval = -1
for num in sorted([int(''.join(map(str,x))) for x in list(set(itertools.permutations([int(x) for x in str(n)])))]):
if num>n:
if minval == -1 or minval > num:
minval = n
return minval
Appropriate test-cases:
nextBigger(num: 1176) //should return 1617
来源:https://stackoverflow.com/questions/64886787/using-permutations-to-find-the-next-biggest-number