Mimic Permutations Counter - python

With a given number with no repeating digits, I want to add the correct amount to get to the next number that has no repeating digits it it. This may be as simple as adding 1, or adding hundreds as it gets complex when the given number is high. Examples of numbers with repeating digits in them are 11, 345675, 4335, 24364. Examples of numbers with no repeating digits are 12, 735691, 89, 623490.
An interesting point to make is that there will never be more than 2 repeating digits in a number when caught as soon as it repeats, nor will multiple sets of repeating digits. For example, numbers 1232, 654334, 765661 will never come up.
Some conditions I do not want to occur. I do not want there to be loops counting up and just returning numbers that have no repeating digits. I want the program to be able to take a number with no repeating digits and know how many to add by dissecting and evaluating the number.
An example of what I do not want. This just loops until it detects a number with no repeating digits.
start = 532461 # given number
while True:
start += 1
if len(set(str(start))) >= len(str(start)):
print(start)
break
This will print 532467, the next number with no repeating digits.
This program should (in my thought of it, that may be wrong) pass the given number into a function, do whatever is needed to know how much to add to the given number to get to the next number with no repeating digits, or add as it figures out what is needed but preferably added in one shot, and end. The program may iterate through the place values of the number, or change the number to a string, or dissect it in a list or whatever is needed. The same algorithm will need to work from single digits to 10 digit numbers.
An example without the function. (the most important part)
number = 231
mimicPermutations(number)
print(number)
>> 234
This very well may not be possible or be really really complicated, but I'm not looking for the fastest or most practical way to do this. Please ask clarifying questions or comment if you don't know what I'm trying to explain and if possible what you don't understand about it and I will edit my explanation accordingly.
There are 3 rules that come closest to what I want to do. Using the given number plus 1 to detect repeating digits:
If there are no conflicts, add 1.
If a non-zero conflict in digits is detected, determine the lowest place value in which the conflict occurs.
If there are no other conflicts in digits, but there is a conflict with zeros, add 1.
The input 5850 will detect to add 1 to the tens place. 91235264 will detect to add 1 to the hundreds place, giving 91235364, then again to give 91235464, then again to give 91235564, then again to give 91235664, then again to finally give 91235764.
The input 6598, plus one is 6599, which has repeating digits. Taking the lowest value place digit of where the non-zero conflict occurs, which is the ones place, the program adds 1. Then the output is 6600. The program then sees that there is a non-zero conflict with the thousands place and the hundreds place, and 1 to the hundreds place. The output is 6700. Then, there being no non-zero conflicts, the program adds 1, to finally give 6701. This method only adds 1 to a determined value place at a time, and as the example shows, does not skip all repeating digit numbers at once.
This question is not about using the most efficient method or way of accomplishing the desired output.

First, you increment the number by 1.
If this number has no repeating digits, you are done.
Else, you can follow the following algorithm.
(We look at the number as a string.)
Locate the first repeated digit.
Mark it as a "location to change" (change_at_location in the code).
At a location to change, increment the digit to the next highest "available" digit (i.e. a digit that is not repeated till that point in the number). [Note: Such a digit might not always be available, since all the higher digits might already be used.]
IF such a digit is available,
Increment the digit at the location to change.
After that location, look at all the available (i.e. unused up to that point) digits in the increasing order, and insert them one by one.
ELSE
Move the location to change back by 1
Note: If location to change reaches -1, insert a dummy '0' at the start, and update the location to 0, and redo the whole thing.
Following are two snippets, one with the loop, the solution you don't want, but is simple to convince ourselves that it "works", and second without loop using the above algorithm.
def next_non_repeating(x):
x = int(x) + 1
x_int = int(x)
x_str = str(x)
while True:
if len(set(str(x_int))) == len(str(x_int)):
return x_int
x_int += 1
def next_non_repeating_no_loop(x):
x = int(x) + 1
def next_digit(c):
if int(c) >= 9:
return None
return str(int(c) + 1)
x_str = str(x)
x_digits = list(x_str)
locations = {}
digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
repeated = False
repeated_digit = None
for idx, c in enumerate(x_str):
if c in locations:
repeated = True
repeated_digit = c
locations[c].append(idx)
break
else:
locations[c] = [idx]
if not repeated:
return int(x_str)
change_at_location = locations[repeated_digit][-1]
while True:
if change_at_location == -1:
x_digits.insert(0, '0')
change_at_location = 0
answer_digits = x_digits.copy()
change_digit = x_digits[change_at_location]
next_available_digit = None
_n = change_digit
while True:
_n = next_digit(_n)
if _n is None:
break
if _n not in x_digits[:change_at_location]:
next_available_digit = _n
break
if next_available_digit is not None:
available_digits = digits.copy()
answer_digits[change_at_location] = next_available_digit
for d in answer_digits[:change_at_location + 1]:
available_digits.remove(d)
for idx in range(change_at_location + 1, len(x_digits)):
answer_digits[idx] = available_digits.pop(0)
break
else:
change_at_location -= 1
return int(''.join(answer_digits))
If you want to empirically convince yourself (as opposed to by following the logic),
You can do so as follows,
bad = []
invalid = []
for i in range(9876543211):
if len(str(i)) > len(set(str(i))) + 1:
invalid.append(i)
continue
if next_non_repeating(i) != next_non_repeating_no_loop(i):
bad.append(i)
The list bad remains empty thereby "proving" the correctness.
Word of caution, however, that this loop will take a long long time to run, since the loop-y way is actually quite inefficient as can be seen by the following comparison,
%time next_non_repeating(987654322)
CPU times: user 42.5 s, sys: 91.8 ms, total: 42.6 s
Wall time: 42.6 s
Out[107]: 1023456789
%time next_non_repeating_no_loop(987654322)
CPU times: user 52 µs, sys: 0 ns, total: 52 µs
Wall time: 55.3 µs
Out[108]: 1023456789
So the non-loop variant is actually much faster, thereby also justifying the need for looking for such variant beyond purely academic curiosity.
Note 1: This function does not care for the restriction of "no repeated digits in the original number" or "only one set of repeated digits" etc, given any number it will find the next non-repeating number whenever possible.
Note 2: Code can be cleaned up etc a bit. It is written so purposefully to make it easy to follow the thought process.

Find the least significant digit which you can increase to something that's not one of the higher digits. Change that digit to that value, and then replace each of the remaining digits with the lowest digit that's not already used.
Example code with test-cases:
def next_nonrepeating(n):
digits = [int(x) for x in ('0' + str(n))[::-1]]
for i in range(0, len(digits)):
higher = set(d for d in digits[i+1:-1])
d = min((x for x in range(digits[i]+1, 10) if x not in higher), default=None)
if d is not None:
digits[i] = d
higher.add(d)
for j in range(i-1, -1, -1):
m = min(x for x in range(10) if x not in higher)
digits[j] = m
higher.add(m)
return int(''.join(str(x) for x in reversed(digits)))
test_cases = [
(6598, 6701),
(987654321, 1023456789),
(1234, 1235),
(1239, 1240),
(9876, 10234),
]
for x, want in test_cases:
got = next_nonrepeating(x)
if got != want:
print('next_nonrepeating(%d) = %s, want %d' % (x, got, want))

Related

Minimum number from matchsticks, python

I'm having trouble finding the smallest number possible from the following question:
Matchsticks are ideal tools to represent numbers. A common way to represent the ten decimal digits with matchsticks is the following:
This is identical to how numbers are displayed on an ordinary alarm clock. With a given number of matchsticks you can generate a wide range of numbers. We are wondering what the smallest and largest numbers are that can be created by using all your matchsticks.
Input:
On the first line one positive number: the number of testcases, at most 100. After that per testcase:
One line with an integer n (2 <= n <= 100): the number of matchsticks you have.
Output:
Per testcase:
One line with the smallest and largest numbers you can create, separated by a single space. Both numbers should be positive and contain no leading zeroes.
I've tried multiple different ways to try to solve this problem, I'm currently trying to:
find the minimal number of digits needed for the smallest number
send digit to a function minimum() which should generate all the different combinations of numbers that are the length of digits. I want to store all these numbers in a list and then take min() to get the smallest one. I'm not getting this part to work, and would appreciate some inspiration.
Something to remember is that the number can't start with a 0.
if 2 <= n <= 100:
value = (n+6)//7
Unless I'm mistaken, this should work for part 2 (added a fix for 17, 24...):
numdict = {2:1,3:7,4:4,5:2,6:0,7:8,8:10,9:18,10:22,11:20,12:28,13:68}
def min_stick(n):
if 2 <= n <= 13:
return numdict[n]
digits = (n + 6) // 7
base = str(numdict[7+n%7])
if base == '22':
base = '200'
return int(base+"8"*(digits - len(base)))
And, though this one's a no-brainer:
def max_stick(n):
if n%2:
return int("7"+"1"*((n-3)//2))
return int("1"*(n//2))
Ok, so just for the sake of it, I coded what you asked: a recursive function that returns all possible combinations with n matchsticks.
stick = {0:6,1:2,2:5,3:5,4:4,5:5,6:6,7:3,8:7,9:6}
def decompose(n):
retlist = []
if n==0:
return [""]
for i in stick:
if (left := n-stick[i]) >1 or left == 0:
retlist += [str(i)+el for el in decompose(left)]
return retlist
def extr_stick(n):
purged_list = [int(i) for i in decompose(n) if not i.startswith('0')]
return min(purged_list), max(purged_list)
It becomes slow when n grows, but anyway...
extr_stick2(30)
Out[18]: (18888, 111111111111111)

Python homework regarding prime numbers

My homework is simple, declare a function named printPrimeNumbersTo with a single argument named to
I created the skeleton of the code itself, however, I needed some help from the net.
GeeksforGeeks was the site where I "borrowed" a line of code, which I don't completely understand. (Site: https://www.geeksforgeeks.org/python-program-to-print-all-prime-numbers-in-an-interval/)
My code looks like this (I have comments on nearly every line, describing what I think that the line of code does):
def printPrimeNumbersTo(to):
x = 0
prime_list = [] # This was a string, however, I changed it to a list so I won't have to convert the numbers to a string every time I wanted to append it to the list
for i in range(x, to + 1): # Create a for loop, using the function range an starting the loop at number 0. Add 1 to 'to', because range excludes the end integer
if i == 0 or i == 1:
continue
else:
for j in range(2, i // 2 + 1): # <--
if i % j == 0: # If 'j' is divided by any number in the list and remainder is 0, then the number is not a prime number, which means I can break the loop
break
else:
prime_list.append(i) # Append the prime number to the list
return str(prime_list)[1:-1] # Returns '[2,3,5,7..]', I use the square brackets the get rid of the brackets themselves
print(printPrimeNumbersTo(7)) # >>> 2, 3, 5, 7
The one line I don't understand is marked with an arrow, it's the 8th line of the code.
Why am I dividing the number by 2? And then making it an integer? When I do the calculations, it works, but... where is the logic? Anybody help?
The biggest number which could possibly be an even factor of a number is the half of that number. The integer division operator // produces this number as an integer.
Because of how range works, the ending index needs to be the desired number plus one.
There are two points to note:
the code needs to be indented correctly, in Python indentation matters as it forms the code blocks.
aside from this and specifically adressing the question: the range function that you refer to requires integers otherwise it would throw an typeerror like this: 'float' object cannot be interpreted as an integer .
# this will throw an error
for i in range(1, 10.5):
print(i)
# this will work
for i in range(1, 10):
print(i)
So the reason why the line of code you queried was written like that was to ensure that the upper bound of the range was an integer.
You should also note that the // has a meaning, for example try this:
x = 5//2
print(x)
y = 5/2
print(y)
x is the integer part only (x=2)
y is the full number (y=2.5)
In terms of implementaiton, there are a number of methods that would be better (suggested here):
Print series of prime numbers in python
Dividing the number by 2 is done to reduce the number of iterations. For example, the number 12 you can divide it without a remainder by 1,2,3,4,6. Notice that there is no number bigger than (6) which is 12 / 2. And this goes on with all of the numbers.
16 ---> 1,2,8 no number bigger than its half (8)

Counting how many times I used one equation until it reaches a specific result in python

import math
#entrada
x=int(input("Put a number here:"))
#processo
num1=int(math.sqrt(x))
num2=round(num1,0)
num3=num2**2
remaining=x-num3
#saída
print("The remaining is:",remaining)
I made this code to get the remaining of a perfect square, for any "int" number, now I want to improve on this code so it keeps doing the equation using the last answer(stored in "remaining")is "0"(and stop calculating after that).
And then, after it finishes calculating, I want to count how many times I used the equation until it reaches "0"
I know this is hard to understand put ill try with one example:
For the number 87, the remaining will be 6 in this code because 87-(9²)=6, I want to use this result(6)and make the same equation and then the result will be (2) because 6-(2²)=2, then doing it again (1), then stop once it returns (0).
After that, I want to count how many times the equation was used to reach (0), in this example, it would be 4 (87 6)(6 2)(2 1)(1 0). And I want to print that counting...in this case(4)
I know it is a lot to ask to help me in this(it's a big request), but I'm just staring programming now(10 days ago)and I couldn't find what I wanted anywhere else in the internet. Thanks for the help. Also, if there is any way to make mine original code better tell me please.
I think you need something like this:
def count_squares(x):
count = 0
remaining = 1
while remaining:
min_square = (int(x**0.5) // 1) **2
remaining = x - min_square
count +=1
print('X = {}, remaining = {}, count = {}'.format(x, remaining, count))
x = remaining
return count
print(count_squares(87))
Explaining:
** operator — for exponentiation.
// operator — for floor division. In this case it is similiar to "int" and "round" bound, that you used for calculating num2, because "//1" will throw away all digits after dot. By the way int() function is not necessary in this case at all.
we will exit from while loop as soon as remaining value will be equal to zero, because zero integer value is interpreted as false.
format is method of strings used to do formatting(surprisingly). All {} will be filled with arguments passed to the "format" method. There are other ways to do formatting in python( % operator, and formatted strings).
Output is:
X = 87, remaining = 6, Count = 1
X = 6, remaining = 2, Count = 2
X = 2, remaining = 1, Count = 3
X = 1, remaining = 0, Count = 4
4

I need help finding a smart solution to shorten the time this code runs

2 days ago i started practicing python 2.7 on Codewars.com and i came across a really interesting problem, the only thing is i think it's a bit too much for my level of python knowledge. I actually did solve it in the end but the site doesn't accept my solution because it takes too much time to complete when you call it with large numbers, so here is the code:
from itertools import permutations
def next_bigger(n):
digz =list(str(n))
nums =permutations(digz, len(digz))
nums2 = []
for i in nums:
z =''
for b in range(0,len(i)):
z += i[b]
nums2.append(int(z))
nums2 = list(set(nums2))
nums2.sort()
try:
return nums2[nums2.index(n)+1]
except:
return -1
"You have to create a function that takes a positive integer number and returns the next bigger number formed by the same digits" - These were the original instructions
Also, at one point i decided to forgo the whole permutations idea, and in the middle of this second attempt i realized that there's no way it would work:
def next_bigger(n):
for i in range (1,11):
c1 = n % (10**i) / (10**(i-1))
c2 = n % (10**(i+1)) / (10**i)
if c1 > c2:
return ((n /(10**(i+1)))*10**(i+1)) + c1 *(10**i) + c2*(10**(i-1)) + n % (10**(max((i-1),0)))
break
if anybody has any ideas, i'm all-ears and if you hate my code, please do tell, because i really want to get better at this.
stolen from http://www.geeksforgeeks.org/find-next-greater-number-set-digits/
Following are few observations about the next greater number.
1) If all digits sorted in descending order, then output is always “Not Possible”. For example, 4321.
2) If all digits are sorted in ascending
order, then we need to swap last two digits. For example, 1234.
3) For
other cases, we need to process the number from rightmost side (why?
because we need to find the smallest of all greater numbers)
You can now try developing an algorithm yourself.
Following is the algorithm for finding the next greater number.
I)
Traverse the given number from rightmost digit, keep traversing till
you find a digit which is smaller than the previously traversed digit.
For example, if the input number is “534976”, we stop at 4 because 4
is smaller than next digit 9. If we do not find such a digit, then
output is “Not Possible”.
II) Now search the right side of above found digit ‘d’ for the
smallest digit greater than ‘d’. For “534976″, the right side of 4
contains “976”. The smallest digit greater than 4 is 6.
III) Swap the above found two digits, we get 536974 in above example.
IV) Now sort all digits from position next to ‘d’ to the end of
number. The number that we get after sorting is the output. For above
example, we sort digits in bold 536974. We get “536479” which is the
next greater number for input 534976.
"formed by the same digits" - there's a clue that you have to break the number into digits: n = list(str(n))
"next bigger". The fact that they want the very next item means that you want to make the least change. Focus on changing the 1s digit. If that doesn't work, try the 10's digit, then the 100's, etc. The smallest change you can make is to exchange two furthest digits to the right that will increase the value of the integer. I.e. exchange the two right-most digits in which the more right-most is bigger.
def next_bigger(n):
n = list(str(n))
for i in range(len(n)-1, -1, -1):
for j in range(i-1, -1, -1):
if n[i] > n[j]:
n[i], n[j] = n[j], n[i]
return int("".join(n))
print next_bigger(123)
Oops. This fails for next_bigger(1675). I'll leave the buggy code here for a while, for whatever it is worth.
How about this? See in-line comments for explanations. Note that the way this is set up, you don't end up with any significant memory use (we're not storing any lists).
from itertools import permutations
#!/usr/bin/python3
def next_bigger(n):
# set next_bigger to an arbitrarily large value to start: see the for-loop
next_bigger = float('inf')
# this returns a generator for all the integers that are permutations of n
# we want a generator because when the potential number of permutations is
# large, we don't want to store all of them in memory.
perms = map(lambda x: int(''.join(x)), permutations(str(n)))
for p in perms:
if (p > n) and (p <= next_bigger):
# we can find the next-largest permutation by going through all the
# permutations, selecting the ones that are larger than n, and then
# selecting the smallest from them.
next_bigger = p
return next_bigger
Note that this is still a brute-force algorithm, even if implemented for speed. Here is an example result:
time python3 next_bigger.py 3838998888
3839888889
real 0m2.475s
user 0m2.476s
sys 0m0.000s
If your code needs to be faster yet, then you'll need a smarter, non-brute-force algorithm.
You don't need to look at all the permutations. Take a look at the two permutations of the last two digits. If you have an integer greater than your integer, that's it. If not, take a look at the permutations of the last three digits, etc.
from itertools import permutations
def next_bigger(number):
check = 2
found = False
digits = list(str(number))
if sorted(digits, reverse=True) == digits:
raise ValueError("No larger number")
while not found:
options = permutations(digits[-1*check:], check)
candidates = list()
for option in options:
new = digits.copy()[:-1*check]
new.extend(option)
candidate = int(''.join(new))
if candidate > number:
candidates.append(candidate)
if candidates:
result = sorted(candidates)[0]
found = True
return result
check += 1

HackerRank "AND product"

When I submit the below code for testcases in HackerRank challenge "AND product"...
You will be given two integers A and B. You are required to compute the bitwise AND amongst all natural numbers lying between A and B, both inclusive.
Input Format:
First line of the input contains T, the number of testcases to follow.
Each testcase in a newline contains A and B separated by a single space.
from math import log
for case in range(int(raw_input())):
l, u = map(int, (raw_input()).split())
if log(l, 2) == log(u, 2) or int(log(l,2))!=int(log(l,2)):
print 0
else:
s = ""
l, u = [x for x in str(bin(l))[2:]], [x for x in str(bin(u))[2:]]
while len(u)!=len(l):
u.pop(0)
Ll = len(l)
for n in range(0, len(l)):
if u[n]==l[n]:
s+=u[n]
while len(s)!=len(l):
s+="0"
print int(s, 2)
...it passes 9 of the test cases, Shows "Runtime error" in 1 test case and shows "Wrong Answer" in the rest 10 of them.
What's wrong in this?
It would be better for you to use the Bitwise operator in Python for AND. The operator is: '&'
Try this code:
def andProduct(a, b):
j=a+1
x=a
while(j<=b):
x = x&j
j+=1
return x
For more information on Bitwise operator you can see: https://wiki.python.org/moin/BitwiseOperators
Yeah you can do this much faster.
You are doing this very straightforward, calculating all ands in a for loop.
It should actually be possible to calculate this in O(1) (I think)
But here are some optimisations:
1) abort the for loop if you get the value 0, because it will stay 0 no matter what
2)If there is a power of 2 between l and u return 0 (you don't need a loop in that case)
My Idea for O(1) would be to think about which bits change between u and l.
Because every bit that changes somewhere between u and l becomes 0 in the answer.
EDIT 1: Here is an answer in O(same leading digits) time.
https://math.stackexchange.com/questions/1073532/how-to-find-bitwise-and-of-all-numbers-for-a-given-range
EDIT 2: Here is my code, I have not tested it extensively but it seems to work. (O(log(n))
from math import log
for case in [[i+1,j+i+1] for i in range(30) for j in range(30)]:
#Get input
l, u = case
invL=2**int(log(l,2)+1)-l
invU=2**int(log(u,2)+1)-u
#Calculate pseudo bitwise xnor of input and format to binary rep
e=format((u&l | invL & invU),'010b')
lBin=format(l,'010b')
#output to zero
res=0
#boolean to check if we have found any zero
anyZero=False
#boolean to check the first one because we have leading zeros
firstOne=False
for ind,i in enumerate(e):
#for every digit
#if it is a leading one
if i=='1' and (not anyZero):
firstOne=True
#leftshift result (multiply by 2)
res=res<<1
#and add 1
res=res+int(lBin[ind])
#else if we already had a one and find a zero this happens every time
elif(firstOne):
anyZero=True
#leftshift
res=res<<1
#test if we are in the same power, if not there was a power between
if(res!=0):
#print "test",(int(log(res,2))!=int(log(l,2))) | ((log(res,2))!=int(log(u,2)))
if((int(log(res,2))!=int(log(l,2))) or (int(log(res,2))!=int(log(u,2)))):
res=0
print res
Worked for every but a single testcase. Small change needed to get the last one. You'll have to find out what that small change is yourself. Seriously

Categories