Python function to add or subtract digits of a number - python

My problem is that I'm trying to write a function PlusMinus(num) which will read the integer being passed, and determine if it's possible to separate the digits of the integer with either a plus or minus sign to form an expression which evaluates to zero.
For example: if num is 35132 then it's possible to separate the digits the following way, 3 - 5 + 1 + 3 - 2, and this expression equals 0.
The function should return a string of the signs used, so for this example the program should return "-++-". If it's not possible to get the digit expression to equal zero, it should return the string "not possible". If there are multiple ways to get the final expression to equal zero, it should return the one that contains more minus characters. For example: if num is 26712 the function should return "-+--" and not "+-+-".
Sample Test Cases:
Input: 199
Output: not possible
Input: 26712
Output: -+--
My code:
num=int(input())
PlusMinus(num)
def PlusMinus(num):
s=str(num)
l=len(s)
rs=''
r=0
if(l<2):
print("not possible")
else:
for i in range(1,l):
if i<2:
r=int(s[0])-int(s[1])
rs='-'
else:
if r<=0:
r=int(r)+int(s[i])
rs+='+'
else:
r=int(r)-int(s[i])
rs+='-'
if(r==0):
print(rs)
else:
print("not possible")

This is a fun problem. Your code works for the test cases you've outlined in your post, but the logic falls down in some cases. For example, your code naively attempts to add a subtract sign if the current sum is greater than 0, and a plus sign if not. This means that if we try:
945
--
We get the correct answer, however if we try:
459
not possible
We get an incorrect answer, as clearly 4 + 5 - 9 = 0, so we expect to get +-.
My approach to the problem would be to use itertools.product to generate all possible combinations of plus and minus signs, starting with ---... and ending with +++..., and loop through them in order, breaking if we find a solution. This brute force solution is also naive, as with some analysis & heuristics, we could eliminate a fair few solutions, but it does work and will provide the correct answer.
Code:
import itertools
def PlusMinus(num):
# make our num into a string
s=str(num)
# For each possible operations combination:
for op in itertools.product('-+', repeat=len(s)-1):
# If when applied, we make 0
if apply_ops(s, op) == 0:
# Return the operations as a string
return ''.join(op)
# If we've exhausted all possibilities, it's not possible
return 'not possible'
# Apply a series of operations op to a string s
def apply_ops(s, op):
# Set return val to the first digit of s
rv = int(s[0])
# For each remaining digit, either increment or decrement according to the
# operation
for i, n in enumerate(s[1:]):
if op[i] == '+':
rv += int(n)
else:
rv -= int(n)
# Return result
return rv
num=int(input())
print(PlusMinus(num))
Tests:
945
--
459
+-
26712
-+--
199
not possible

Related

How can I write this code so that I do not have to round the logarithm?

I was doing a programming challenge question where you need to found out if a given number (n) is equal to 3 raised to some exponent(x)
9 is True since 3^x -> 3^3 = 9
10 is False since no x for 3^x is equal to 10
my problem occurred when 243 was entered into my code, which returned a result of 4.999 repeating.
my solution was to simply add a round function, in which I arbitrarily decided on 5 decimal places, this solved the problem.
now another problem occurred when the input was 531440, this returns an x value of 11.999998287222695 which, according to the challenge, was false, but with my code returned a true since I rounded to the fifth decimal place. I then changed my round to 10 decimal places and this fixed the code.
I was wondering if there was a way to implement my solution without having to round, as I'm sure if I plugged in enough numbers eventually another one would need to round past >10 decimal places and cause my code to fail. Please see the code below.
import math as math
def isPowerOfThree(n):
print(math.log(n,3)) #this line prints the unrounded log result
print(round((math.log(n,3)),10)) #this line prints the rounded result
return n>0 and round((math.log(n,3)),10).is_integer()
n = 243
print(isPowerOfThree(n))
The 'trick' allowing to avoid problems with chosen precision is to round to an integer and then check if this exponent gives the required result. The code below implements this approach:
import math
def isPowerOfThree(N):
if 3**round(math.log(N,3)) == N:
return True
return False
N = 531440 # 243
print(isPowerOfThree(N)) # gives False
Another approach will be to check all powers of 3 against the target number:
def isPowerOfThree(N):
x = 1
while True:
n = 3**x
if n == N:
return True
elif n > N:
return False
x += 1
And here an approach detecting directly without the need to run multiple loop runs if a number is not a power of 3:
def isPowerOfThree(N):
while True:
N , r = divmod(N, 3)
if r != 0:
return False
if N == 1:
return True
P.S. the two last approaches provide code to what Karl Knechtel mentioned in his comment to the question.

How to get prime numbers from string using permutations and combinations

Complete the following function to return a list of strings lesser than 999 which form prime numbers from a given string of numbers.
For example if the given string is “23167”. All the prime numbers less than or equal to 999 in the string are 2,3,23,31,7,167. So, your function must return [2,3,23,31,7,167]. Although 23167 is a prime number we can ignore it because it is greater than 999.
Output: should be list of integers
def primenumber_from_string(string1):
#your code goes here
return []
if _name=='main_':
#you can run any test cases here
print(primenumber_from_string("8487934"))
Approach the problem systematically. Start with all the possible one-digit numbers, and check if they are prime. Then try all the possible two-digit numbers and see if they are prime. Then try all the possible three-digit numbers and check them all. Lastly show your accumulated results in the expected format.
So it's a basic algorithmic problem.
I'll give you some pseudo - code.
At this point, I'll only give you Brut-force solution, but I'll think about "proper" approach.
So:
Take first digit -> check
Second -> check
Third -> check
{ ... }
compose two digit numbers -> check.
When this is completed, put them into your list.
For checking if number is prime fast ( O(sqrt(N)) ) you can use this function:
## Made by kam021m on: 12.12.2019 ##
## Resources used:
## * GeeksForGeeks article how to check primes fast
## *
def is_prime(n):
if n == 1:
return False
i = 2
while i*i <= n:
if n % i == 0:
return False
i += 1
return True
This basically checks if number is prime by % (i) when i is lower than sqrt from n.
If I'll find faster solution, I will post it here.
EDIT 1: also wanted to ask, is it your homework or sth? Do you have time limits on it?

Can I make this recursion work with negative numbers?

I wrote this code and it's alright with positive numbers, but when I tried negative numbers it crashes. Can you give any hints on how to make it work with negative numbers as well? It needs to be recursive, not iterative, and to calculate the sum of the digits of an integer.
def sum_digits(n):
if n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0
if __name__=='__main__':
print(sum_digits(123))
Input: 123
Output: 6
On the assumption that the 'sum' of the three digits of a negative number is the same as that of the absolute value of that number, this will work:
def sum_digits(n):
if n < 0:
return sum_digits(-n)
elif n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0
That said, your actual problem here is that Python's handling of modulo for a negative number is different than you expect:
>>> -123 % 10
7
Why is that? It's because of the use of trunc() in the division. This page has a good explanation, but the short answer is that when you divide -123 by 10, in order to figure out the remainder, Python truncates in a different direction than you'd expect. (For good, if obscure, reasons.) Thus, in the above, instead of getting the expected 3 you get 7 (which is 10, your modulus, minus 3, the leftover).
Similarly, it's handling of integer division is different:
>>> -123 // 10
-13
>>> 123 // 10
12
This is un-intuitively correct because it is rounding 'down' rather than 'towards zero'. So a -12.3 rounds 'down' to -13.
These reasons are why the easiest solution to your particular problem is to simply take the absolute value prior to doing your actual calculation.
Separate your function into two functions: one, a recursive function that must always be called with a non-negative number, and two, a function that checks its argument can calls the recursive function with an appropriate argument.
def sum_digits(n):
return _recursive_sum_digits(abs(n))
def _recursive_sum_digits(n):
if n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0
Since _recursive_sum_digits can assume its argument is non-negative, you can dispense with checking its sign on every recursive call, and guarantee that n // 10 will eventually produce 0.
If you want to just sum the digits that come after the negative sign, remove the sign by taking the absolute value of the number. If you're considering the first digit of the negative number to be a negative digit, then manually add that number in after performing this function on the rest of the digits.
Here is your hint. This is happening because the modulo operator always yields a result with the same sign as its second operand (or zero). Look at these examples:
>>> 13 % 10
3
>>> -13 % 10
7
In your specific case, a solution is to first get the absolute value of the number, and then you can go on with you approach:
def sum_digits(n):
n = abs(n)
if n != 0:
return (n % 10 + sum_digits(n // 10))
else:
return 0

Mimic Permutations Counter

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))

Python Debugging: weird event when negative sign is in front

I was doing an assignment question.
Write a program, divisible_by_11(num), to return the divisibility of num
by 11. i.e. divisible_by_11(num) should return True is num is divisible by 11,
or False otherwise. Implement this function recursively and using the following algorithm.
Note: a number is divisible by 11 if the difference between the sum of odd digits
and the sum of even digits is divisible by 11. Note that 0 is divisible by 11.
def divisible_by_11(num):
def helper(num,i):
if num==0:
return 0
elif i%2:
return helper(num//10,i+1)-num%10
Question is about replacing the above line with return -num%10+ helper(num//10,i+1)
elif i%2==0:
return num%10+helper(num//10,i+1)
return helper(num,0)%11==0
this code works, however if I wrote return -num%10+ helper(num//10,i+1) instead of return helper(num//10,i+1)-num%10, my code would fail. Can anyone tell me what's happening?
The issue with the alternate form is due to order of operations. The unary-minus operator binds more tightly than the mod operator. That is, the expression -num%10 is interpreted as (-num) % 10, and the modulus of a negative number is not the same thing as its last digit.
There are a few ways you could fix it. The easiest would probably be to add your own parentheses so that the mod happens first: return -(num%10) + helper(num//10,i+1) should work as expected.
Unrelated to that issue, I'm very skeptical that your assignment allows you to do %11 in the final return, since that operation is all you would need to solve the whole problem without the rest!
Instead, I suspect it wants you to use recursion for that part too (and maybe not for adding up the digits). Instead of return helper(num,0)%11==0, try:
while num > 10:
num = helper(num, 0)
return num == 0

Categories