Python recursion exercises - python

"Write a function bin_rep(n) that returns a string with the binary representation of n.
Extend bin_rep(n) to create base_rep(n, k) to give a string representing non-netavie integer n in base k, where 2 <= k <= 10. In base k, the only digits allowed are {0, ..., k-1}.
For a list of distinct integers, L, define switches(L) as the number of pairs in L that are not in increasing order. For example, switches([6, 1, 4]) returns 2, since (6, 1) and (6, 4) are out of order."
Above is the extra credit exercise in lab class. I can't understand how to write those codes at all. I do have the bin_rep(n) function from class notes, but that is about it. Please help. This exercise is not marked at all, but I would like to know how it can be written. Thanks.
def bin_rep(n):
if n == 0:
return ['']
else:
short_strings = bin_rep(n - 1)
strings = []
for s in short_strings:
strings.append('0' + s)
for s in short_strings:
strings.append('1' + s)
return strings

Rather than give you the code, I'll explain how to solve this, so you can write it yourself.
First, note that, contrary to your description, bin_rep does not give the binary representation of the number n; instead, it gives a list of all of the binary strings of up to n digits.
So, assuming you want to do the same thing—that is, give a list of all the base-k strings of up to n digits—you have to identify where the "base 2-ness" comes in.
Look at this code:
for s in short_strings:
strings.append('0' + s)
for s in short_strings:
strings.append('1' + s)
That does something for the digit 0, and then for the digit 1. Those are the two digits of base 2. So, to make this work for base 3 instead, it would be:
for s in short_strings:
strings.append('0' + s)
for s in short_strings:
strings.append('1' + s)
for s in short_strings:
strings.append('2' + s)
But for arbitrary base k, you have to do this for every digit from 0 up to (but not including) k. So, you're going to write some loop that goes through all the numbers in that (half-open) range, and then, instead of repeating this two-liner, just use it once, as a nested loop inside that loop over the digits.
Also, of course, instead of hardcoding the string '0', you're going to need to write the string representation of the digit. (You can't add a number to a string; you have to convert the number to its string representation, and then add that to the string.)
Also keep in mind that you can't just call base_rep(n - 1), because base_rep takes two arguments. What should the second argument be?

Related

Why do I get a wrong XOR output

I just started the cryptopals.com challenge and I'm already stuck at the second problem.. For some reason my output is wrong by only one character instead of 7 I get a 3 as the first number of my XOR operation.
Could you help me find the mistake in my code:
def XORfunction(input_1, input_2):
bin_input_1 = hexToBinary(input_1)
bin_input_2 = hexToBinary(input_2)
# check if length of strings is the same for XOR compare or add "0" to the end
if len(bin_input_1) != len(bin_input_2):
if len(bin_input_1) > len(bin_input_2):
number_length = len(bin_input_1)
temp_input = list(bin_input_2)
for x in xrange(0, number_length - len(bin_input_2)):
temp_input.insert(0, "0")
bin_input_2 = "".join(temp_input)
if len(bin_input_1) < len(bin_input_2):
number_length = len(bin_input_2)
temp_input = list(bin_input_1)
for x in xrange(0, number_length - len(bin_input_1)):
temp_input.insert(0, "0")
bin_input_1 = "".join(temp_input)
solution = []
# XOR is like a sum so if el1+el2 == 1 output is 1 else output is 0
for x in xrange(0, len(bin_input_1) - 1):
# the array is iterated from [0] to len(bin_input_1)-1 so the elements are calculated from last to first
current_compare = int(bin_input_1[x]) + int(bin_input_2[x])
if current_compare == 1:
solution.insert(-1, "1")
else:
solution.insert(-1, "0")
return dec_to_hex(int("".join(solution), 2))
# the final solution has to be converted from decimal to hexadecimal
def dec_to_hex(value):
dictionary_hex = "0123456789abcdef"
solution = []
while value != 0:
solution.insert(0, dictionary_hex[value % 16])
value = value / 16
return "".join(solution)
# Hex is converted to a binary string to make comparisons easy as the digits become easy to select as an array of chars
def hexToBinary(text):
# first Hex is converted to decimal, then to binary (that needs to be sliced for a clean output), lastly it becomes a string
return str(bin(int(text, base=16))[2:])
print XORfunction("1c0111001f010100061a024b53535009181c", "686974207468652062756c6c277320657965")
# expected output: 746865206b696420646f6e277420706c6179
# my output: 346865206b696420646f6e277420706c6179
This is my first time posting, so any tip on formatting/on the code is welcome.
PS: I know I should be using libraries, but I want to figure out what is my mistake first
You have several issues:
Your hexToBinary() function doesn't produce padded binary. bin() will not return 8 bits per byte; leading zeros are not included! As such, you are missing 000 from the start of the first string, 0 from the other. You try to compensate for this in your XORfunction function, but that only adds back 2 zeros, not 3.
You could use the str.format() method instead to ensure that you get the right number of bits, zero padded:
return '{:0{}b}'.format(int(text, base=16), len(text) * 4)
The b formatting instruction tells str.format() to produce the binary representation of a number. 0 before the width means to zero-pad the number to the required length, and the {} placeholder for the length is taken from the len(text) * 4 value, so 4 bits per hex character in the input.
You are inserting the solution bits before the last element in the list. This leaves the very first bit right at the end of your solution, with everything else inserted before it:
>>> demo = []
>>> demo.insert(-1, 'foo') # inserting into an empty list
>>> demo
['foo']
>>> demo.insert(-1, 'bar') # inserting before the last element
>>> demo
['bar', 'foo']
>>> demo.insert(-1, 'spam') # inserting before the last element
['bar', 'spam', 'foo']
Just use appending to add elements to the end of a list:
solution.append("1")
and
solution.append("0")
You skip processing the last bit. You need to iterate all the way to len(bin_input_1):
for x in xrange(len(bin_input_1)):
With those 3 fixes applied, your code works and produces the expected output.
Your code is indeed re-inventing standard wheels in the Python language and standard library:
Rather than manually XOR every bit, use the ^ operator to work on a whole byte at a time.
Use the binascii.hexlify() and binascii.unhexlify() functions to convert between hexadecimal and bytes.
In Python 2, use the bytearray() type to work with binary data as a sequence of integers, this is much easier to apply XOR operations to.
Use the zip() function to iterate over two sequences together, pairing up elements from both.
Put together as a Python 2 solution:
from binascii import hexlify, unhexlify
def XORfunction(input_1, input_2):
input_1 = bytearray(unhexlify(input_1))
input_2 = bytearray(unhexlify(input_2))
return hexlify(bytearray(
a ^ b for a, b in zip(input_1, input_2)))
In Python 3, you can simply omit the first two bytearray() calls, and replace the last with bytes().

How to implement a place value based multiplication algorithm?

Place value (positional) encoded numbers
To make it possible to multiply a number in a place value based fashion, I have encoded numbers in a list format, digit by digit in reverse order. Say for example 34 is [4 3] and 12 is [2 1].
To encode numbers I use:
def eN(n):
return list(map(int, reversed(str(n))))
To decode I use:
def dN(l):
return int(''.join(map(str, reversed(l))))
So that: dN(eN(34)) -> 34
Positive integers can be from 0 to any digits long.
Multiplication constraints
Now, I need to create a multiplication algorithm with the next constraints:
1.
Division method to find out integer and remainder part of the divided number that satisfy this function:
from math import floor
# div(5, 3) -> [1, 2]
def div(n, base = 10):
return [floor(n / base), n % base]
only permitted arithmetic operations are div, * and + methods, which however can be used in conjunction with recursion
numbers must be encoded as stated above except the base is given as a native integer from 2 and up
at any part of the algorithm numbers cannot exceed two digits. For example 9+9 = 18 or 9*9=81 are good, but 100 is too much
result should also be a list of numbers encoded in a reverse list format. numbers in a list must be in single digits so that we can use decode function (dN) to transform it back to native integer
algorithm should work with any number base by using div or builtin Python divmod as suggested by #ShadowRanger.
Maybe other restrictions becomes necessary to stress, when answers are suggested.
Alleged algorithm
I would think of a root function similar to this, where two encoded numbers are given as arguments, plus an optional base number, default is 10:
def mul(a, b, base = 10):
def _(c, d, e):
# arithmetics, carrying digits, list processing, recursive calls goes here
pass
# initially, the first digit of the number a is reduced and 10^0 parts of the both numbers are multiplied and "div"ided
return _(a[1:], b, div(a[0]*b[0], base))
Finally, the expected result is:
mul(eN(34), eN(12)) # [8, 0, 4]
or
dN([8, 0, 4]) # 408
If necessary, I can add more to the multiplication _ function, which only has pass at the moment...
Added later...
Working, but messy and unoptimized version of the algo
One might want to use this as a starting point for optimization. I should note, that this should already do the job exactly as I need, but other approaches are welcome:
def mul(a, b, base = 10):
# init function with some default values
def _(c, d, f = [], g = [], h = [], e = 0):
# if there are no more items in list d, this is the end result
if not d:
return h + f
# if there are items in list list c, get integer and reminder parts and other stuff
# and proceed with the rest of the list c
if c:
x = divmod(c[0] * d[0] + (f.pop(1) if len(f) > 1 else 0) + e, base)
return _(c[1:], d, f, g + [x[1]], h, x[0])
# else we have reached the end of the list c and must begin again with the rest of the list d!
# also append reminders to the result lists h and f, not that content of f comes from g at this point
return _(a, d[1:], (g + [e] if e else g), [], (h + [f[0]] if f else h))
# start calling the recursive function and return the end result
return _(a, b)
I will accept any answer that does the same job, even the ones using above code, if solution makes good improvements like minifies the need of lists i.e. usage of memory, or other way simplifies and explains the solution.

make binary number its 'opposite' in python

trying to take a list of binary numbers, and display their 'opposites', im putting this word in quotes because I'm not sure if it's the best way to describe what I mean.
board=[1,10,101]
I want to make a function that will show the complement of opposite of these numbers like this:
newboard=[0,01,010]
basically swapping the 0 for a 1 and the 1 for a 0. Since they are integers I cant iterate through each binary number and manually change the value, I've tried using two's compliment but that doesn't semantically do what I'm trying to do it seems. Does anyone know a function for how to do this, or what this process would be called? thanks!
Can you represent your binary numbers as strings? Then you could simply do the following:
opposite = { '0':'1', '1':'0'}
board=['1', '10', '101']
newboard = [''.join([opposite[c] for c in n]) for n in board]
You can't really store [0, 01, 010] in a list as it just becomes [0, 1, 10] you can use strings though
def reverse_binary(input):
reversed = []
for x in [list(str(x)) for x in input]:
reversed.append(''.join(['%s' % (int(x) ^ 1) for x in x]))
return reversed
if __name__ == '__main__':
print(reverse_binary([1, 10, 101]))
I believe what you are referring to is just called complementing numbers; you are trying to flipping the digits of binary numbers. The natural thing to do is to use the XOR operator.
Consider the following piece of code:
get_bin = lambda x: format(x, 'b')
def Complement_binary(x):
complemented = []
for num in x:
i = 1
while i <= num:
i = i << 1
complemented.append(get_bin((i - 1) ^ num))
return complemented
The Complement_binary function receives a list of numbers and returns a list of numbers in binary representation in strings (get_bin converts the numbers to binary numbers in strings). If you don't want strings, you may remove the get_bin function in complemented.append(get_bin((i - 1) ^ num)).
Source for get_bin function: https://stackoverflow.com/a/21732313/6833761 by #Martin Thoma
You can swap all the ones for zeros and all the zeros for ones inside every string. To do this simple iterate over the list, and for each value, create a new entry swapping 1 and 0. In order to preform the swap, replace '1' with a value thats never used (such as 'U'), assign '0' to '1' and assign the temp value 'U' to '0'.
newboard = [a.replace('1','U').replace('0','1').replace('U','0') for a in board]

Lucky Numbers Python Program Incorrect Python Output

Practice Problems /
Lucky String
All submissions to this problem are public. View all submissions.
Lucky numbers are those numbers which contain only "4" and/or "5". For example 4, 5, 44, 54,55,444 are lucky numbers while 457, 987 ,154 are not.
Lucky number sequence is one in which all lucky numbers exist in increasing order for example 4,5,44,45,54,55,444,445,454,455...
Now we concatenate all the lucky numbers (in ascending order) to make a lucky string "4544455455444445454455..."
Given n, your task is to find the nth digit of the lucky string. If the digit is 4 then you >have to print "Hacker" else you have to print "Earth".
Input:
first line contain number of test cases T , next T line contain a single integer n.
Output:
For each test case print Hacker if n-th digit of lucky string is 4 else print Earth if n-th digit of lucky string is 5.
Constraints:
1 <= t <= 10^5
1 <= n <= 10^15
Following is the python code :
test_cases = int(input())
final = []
def check(stra,num):
if stra[num-1]==4:
final.append("Hacker")
else:
final.append("Earth")
def GenStr(num):
stra = "4"
i = int(5)
while(len(stra)<num+2):
X = str(i)
flag = True
for j in range(len(str(i))):
if(X[j]==4 or X[j]==5):
pass
else:
flag = False
if flag==True:
stra+=X
i+=1
print(stra)
return stra
for i in range(test_cases):
num = int(input())
# generate string
stra = GenStr(num)
print("stra "+stra)
# check the stat
check(stra,num)
print("\n".join(final))
What is wrong in this code, please do not mind if it is a silly mistake I am just a beginner in python programming
Comments on your Code
There are several things in your code which don't quite make sense, and need to be addressed:
int(input()) says to ask the user nothing, try to convert any string they type before pressing enter to an integer, and crash otherwise.
The pattern for i in range(len(x)) is almost always wrong in Python. Strings are iterable (they are lists of characters), which is why you can use the list-style index operator (as you do with x[j]), so just iterate over them: for j in str(i).
The pattern if x==True: is always wrong in Python. We prefer if x:.
i = int(5). There is no need to convert an integer literal to an integer. i = 5 is the correct assignment statement.
Try to use better variable names. It's very difficult to follow your code and your reasoning because it is littered with meaningless identifiers like stra (string a??), X, num, etc.
How to Approach the Assignment
I will be honest: I don't fully understand the assignment as presented. It's not clear what a "test case" is or how the input will be formatted (or, for that matter, where the input is coming from). That said, a few thoughts on how to approach this:
Finding numbers that contain only 4 or 5 means treating them as strings. This could be as easy as testing len(str(x).replace('4', '').replace('5', '')), and there are better ways than that.
Listing 'lucky numbers' in increasing order can be accomplished with the built-in sorted function.
Concatenating that list would be ''.join(sorted(lucky_numbers)) or similar.
Taking the nth digit of that list could then be done with string indexing as before.
The immediately incorrect thing is the following. stra is 4. flag always becomes False. Thus stra never grows, and while(len(stra)<num+2): is an infinite loop.
The approach itself will not fully solve the problem, since you can't construct a string of length 1015, it would take too much time and just won't fit into memory.
As #Gassa points out, brute-forcing this is just not going to work; you would need a million gigabytes of RAM, and it would take far too long.
So what would an analytic solution look like?
If you replace "4" with "0" and "5" with "1", you will see that the lucky number sequence becomes 0, 1, 00, 01, 10, 11, 000, 001, 010, 011, 100, 101, 110, 111, .... This should look familiar: it is every 1-digit binary number in ascending order, followed by every 2-digit binary number in ascending order, followed by every 3-digit binary number in ascending order, etc.
So if you do something like
n = 491 # the digit we are seeking (for example)
d = 1 # number of binary digits
p = 2 # 2**d == number of items encoded
while n > d*p: # sought digit is past the end of the next binary expansion?
n -= d*p # reduce offset by appropriate number of digits
d += 1
p *= 2
then n = 233, d = 6 means we are looking for the 233rd character in the 6-bit expansion.
But we can improve on that:
k, n = n // d, n % d
which gives n = 5, k = 38, d = 6 means we are looking at the 5th character of the 38th 6-bit value.
Note: all offsets here are 0-based; if you expect 1-based offsets, you will have to adjust your math accordingly!
The 38th 6-bit value is just 38 converted to a 6-bit binary value; you could muck about with strings to extract the character you want, but it's probably easier to remember that integers are stored as binary internally so we can get what we want with a bit of math:
digit = (k >> (d - n - 1)) & 1 # => 0
so the character in the original string would be a "4".

Define a function using a variable?

I am trying to define a function that will include a variable n where n will be a string of numbers e.g. "3884892993", the definition of the function starts as is_true(n), however if n is going to be a string should it be is_true(n) and then once the string is defined I can test the function with an example string such as n = "3884892993". I get a syntax error when I use is_true(n) however. And I am just wondering how I would go about testing this function with an example string for n.
My entire function to define is shown here: http://oi44.tinypic.com/282i3qo.jpg but bear in mind I am an absolute novice so there will most probably be many mistakes, but I would appreciate some help from some experts if at all possible :)
def is_valid("n"): #n is the number to be checked.
number =
[int(y) for y in A] #converts the string into a list of useable digits.
altern1 = integer[-2::-2] #sets altern1 as one set of alternating digits.
double = [x*2 for x in altern1] #doubles each element of the list altern1.
sum1 = sum(double) # adds together all the doubled items of the list.
altern2 = integer[-1::-2] #sets altern2 as the other set of alternating digits.
return sum2 = sum(altern2)#sums the other set of alternating digits.
sumtotal = sum1 + sum2 #works out the total sum to be worked with.
for mod = sumtotal % 10: #works out remainder when sumtotal is divided by 10
if mod == 0 : #if remainder is zero sumtotal is a multiple of 10
print 'True' #sumtotal is a multiple of 10 therefore n is a credit card number
else:
print 'False' #sumtotal is NOT a multiple of 10 therefore not a valid credit card number
Here is the actual question:
The algorithm for verifying a number is as follows:
(a) Starting with the penultimate digit, and working towards the rst digit, double each alternating digit.
(b) Sum the doubled digits, treating 13 as 1+3, etc, and add the result to the sum of the undoubled
digits
(c) If the sum is divisible by 10 the number is a valid credit card number.
Write and test a function is_valid() which takes as an argument a credit card number as a string
(eg is valid("49927398716")) and returns True or False depending on whether the number is a
valid credit card number.
Quotes are only used for string literals, you wouldn't enclose a variable or parameter name in quotes to indicate that it will be a string. The function definition would look like:
def is_true(n):
And then in the body of the function you use n to reference the value that is passed in by the caller.
To call the function on a specific value, you do:
is_true("3884892993")
Side suggestion: Think of more explanatory names for your functions and variables. For instance, it seems like your function might be reasonably called is_valid_card_number.
I am not sure what is your question, but if you are trying to:
correctly define the function:
pay attention to the indentation (this is required by Python!),
see here for examples of function definitions,
convert a string variable into integer, you can do this:
new_var = int(old_var)
Generally please pay attention to types, because it is not like in some other dynamically typed languages and strings are not dynamically converted into numbers - you should do it explicitly.
read the value of the variable, based on its name:
my_var = vars().get('variable_name')
(where variable_name is the name of the variable and optionally you can give context within brackets after vars - see help(vars) for details)
Did any of the above solve your problem?
EDIT (based on the clarification):
This should solve your problem:
def is_true(my_variable):
# Here the variable named "my_variable" is accessible
If you want to do something "in-place" on the passed variable, I have a bad news: strings and integers are immutable in Python, thus you are not able to simply change them - you should probably return them as a result of the function (there are at least two workarounds, but I do not recommend them if you are a novice in Python).
EDIT (for proper code styling):
You should probably read PEP 8 to get familiar with what is the coding standard for Python scripts - this is commonly used across Python community and you should follow that (at some point you should appreciate it).
From the Wikipedia article on the Luhn algorithm:
def is_luhn_valid(cc):
num = map(int, str(cc))
return sum(num[::-2] + [sum(divmod(d * 2, 10)) for d in num[-2::-2]]) % 10 == 0
I have no idea what your function is supposed to do, but here are some remarks.
First of all, if you define the function then you use the following syntax
def is_true(n):
# do something
you can call this function like this is_true("3884892993"), i.e. you can pass string as n. Your function now need to treat variable n as a string. So you can use
number = [int(d) for d in n]
which will result in converting string into a list of digits.
One more remark: you used a return statement inside your is_true function. This statement will stop executing the function and return the value. Every code below return will never be executed.
May be like this. I leave your comments
def is_valid(n): #n is the number to be checked.
numbers = [int(y) for y in n] #converts the string into a list of useable digits.
double_alt = [sum([int(i) for i in str(x*2)]) for x in numbers[-2::-2]] #doubles and sum if more than 10each element of the list altern1.
sum1 = sum(double_alt) # adds together all the doubled items of the list.
sum2 = sum(numbers[-1::-2]) #sums the other set of alternating digits.
sumtotal = sum1 + sum2 #works out the total sum to be worked with.
return not sumtotal % 10
Here an implementation of the luhn algorithm that I had to make recently.
def is_valid_luhn(cc):
return not sum([sum(divmod(int(d) * 2, 10)) for d in cc[-2::-2]] + [int(d) for d in cc[-1::-2]]) % 10
# | double | |--- every -2th --| |--- every -1th --|
# |--------- step 1 -----------------|
# |------------- sum doubled digits --------------| |-- sum undoubled digits --|
# |---------------------- step 2: sum doubled/undoubled digits -----------------------|
# |-------------------------- step 3: sum % 10 == 0 --> not sum % 10 --------------------------|
Or if you'd like a more verbose version:
def is_valid_luhn(cc):
total = 0
# Double and sum every 2nd digit starting at -2.
for d in cc[-2::-2]:
# divmod(d*2, 10) returns (d*2 // 10, d*2 % 10)
# sum(divmod) return (d*2 // 10) + (d*2 % 10)
total += sum(divmod(int(d) * 2, 10))
# Sum every 2nd digit starting at -1.
for d in cc[-1::-2]:
total += int(d)
# Check module 10 of total: total % 10 == 0 --> not total % 10
return not total % 10

Categories

Resources