Here is the implementation on Python of a linear ( O(n) ) algorithm with constant additional memory ( O(1) ), described in the answer @VladD :
#!/usr/bin/env python3 from collections import Counter def make_largest_by_swapping_2_digits(digits): """O(n) time, O(m) space""" # find where given number differs from the largest number with the same digits multiplicity = Counter(digits) # count how many times each digit occurs all_digits = sorted(multiplicity, reverse=True) # m digits in decreasing order largest = (d for d in all_digits for _ in range(multiplicity[d])) for k, (a, b) in enumerate(zip(digits, largest)): if a != b: break else: # already largest possible return # nothing to swap # find on the right where a == b j = next(len(digits) - i for i, a in enumerate(reversed(digits), 1) if a == b) digits[k], digits[j] = digits[j], digits[k] # swap
Example:
digits = [1,2,3,4] print('before', *digits) make_largest_by_swapping_2_digits(digits) print('after ', *digits)
Result
before 1 2 3 4 after 4 2 3 1
Notes on the code:
Counter() simply counts how many times each digit occurs:
print(Counter(str(9997754321))) # -> Counter({'9': 3, '7': 2, '5': 1, '4': 1, '3': 1, '2': 1, '1': 1})
Memory consumption is O(m) , where m is not more than 10 for the decimal system. Can be considered constant.
Counter is essentially a multiset here (a set of numbers with repetitions). If you restrict the type of numbers to only decimal, then you can use a simple array instead of Counter:
multiplicity = [0] * 10 for d in digits: multiplicity[d] += 1
largest is the largest number made up of the same numbers as the input number. A generator is used for presentation, so additional memory is needed for only one digit at each moment. O(1)
enumerate(zip()) allows you to bypass two sequences at the same time one pair of elements at a time, tracking the current index:
>>> list(enumerate(zip(range(3), "abc"))) [(0, (0, 'a')), (1, (1, 'b')), (2, (2, 'c'))]
make_largest_by_swapping_2_digits(digits) accepts any variable sequence ( list , bytearray , mmap , etc) with hashable elements that can be compared.
For example, for large numbers recorded in a file, you can directly work with mmap (assuming that a single digit in the byte fits):
import mmap with open('много-цифр.txt', 'r+b', 0) as file, \ mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_WRITE) as digits: make_largest_by_swapping_2_digits(digits)
After executing the code, the много-цифр.txt will contain the new number — a change in place occurs.
заменить? Swap? - αλεχολυτ