问题
I'm stressing on the point of without using an array. Is there any mathematics derivation for this?
回答1:
You can use "Gosper's hack" manipulating binary numbers but you are limited by the word length of the machine on the size of combinations you can generate/represent this way.
// find next k-combination
bool next_combination(unsigned long& x) // assume x has form x'01^a10^b in binary
{
unsigned long u = x & -x; // extract rightmost bit 1; u = 0'00^a10^b
unsigned long v = u + x; // set last non-trailing bit 0, and clear to the right; v=x'10^a00^b
if (v==0) // then overflow in v, or x==0
return false; // signal that next k-combination cannot be represented
x = v +(((v^x)/u)>>2); // v^x = 0'11^a10^b, (v^x)/u = 0'0^b1^{a+2}, and x ← x'100^b1^a
return true; // successful completion
}
Initialise x
with the 1st k
-combination i.e x = (1L<<k) - 1L
(k
one
s are set)
What this does:
- Uses two different representations of a combination a) as a choice and b) as a binary number
- Uses gray coding (or minimal change coding) to move from one combination (binary number) to the next combination (binary number), maintaining same number of
one
s in the binary representation - Eventually all combinations are generated this way (but not lexicographicaly)
For a more number-theoretic representation of a combination see Combinatorial number system which represents combinations as integers, i.e a bijection from combinations to integers (if you want to use strictly artithmetic without using arrays explicitly)
回答2:
An decimal integer is essentially an array of digits. Some simple math will allow the indexing of those digits in the integer just like any other array.
The following python sample code will do exactly what you wanted by exploiting this fact:
#!/usr/bin/python3
def getNumDigits(number):
if number == 0:
digits = 1
else:
digits = 0
while number > 0:
digits += 1
number //= 10
return digits
def getDigitAtPosition(position, number):
return (number // (10**position)) % 10
def swapDigits(number, position_one, position_two):
digit_one = getDigitAtPosition(position_one, number)
digit_two = getDigitAtPosition(position_two, number)
difference = digit_one - digit_two
return number + (difference * 10**position_two) - (difference * 10**position_one)
def sortNumber(number, num_digits=None):
if num_digits is None:
num_digits = getNumDigits(number)
for i in range(num_digits-1):
for j in range(i+1, num_digits):
if getDigitAtPosition(j, number) < getDigitAtPosition(i, number):
number = swapDigits(number, i, j)
return number
def isDigitInNumber(digit, number):
for i in range(getNumDigits(number)):
if getDigitAtPosition(i, number) == digit:
return True
return False
def printCombinations_sorted(number, prepend, num_digits):
if num_digits == 1:
print(number + (prepend * (10**num_digits)))
else:
lead_position = num_digits-1
lead_digit = getDigitAtPosition(lead_position, number)
digits_swapped = lead_digit
printCombinations_sorted(number % 10**(lead_position), (prepend*10) + lead_digit, num_digits-1)
for i in range(num_digits-1):
sub_number = swapDigits(number, num_digits-1, num_digits-2-i)
sub_lead_digit = getDigitAtPosition(lead_position, sub_number)
if not isDigitInNumber(sub_lead_digit, digits_swapped):
digits_swapped = digits_swapped*10 + sub_lead_digit
printCombinations_sorted(sub_number % 10**(lead_position), (prepend*10) + sub_lead_digit, num_digits-1)
def printCombinations(number):
num_digits = getNumDigits(number)
number = sortNumber(number, num_digits)
printCombinations_sorted(number, 0, num_digits)
if __name__ == "__main__":
number = 101010
printCombinations(number)
Since it was not specified if repeated digits would be allowed, I wrote this with the assumption that they would. It could be simplified quite a bit if that is not the case.
来源:https://stackoverflow.com/questions/30684360/how-to-print-all-the-possible-combinations-of-a-n-digit-number-without-using-arr