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().
Related
I want to write a code for this question:
write a code which creates a new number 'n2' which consists reverse order of digits of a number 'n' which divides it without any remainder for example if input is 122
it will print 221 because 1,2,2 can divide 122 without any remainder another example is 172336 here 1,2,3,3,6 can divide it without any remainder so the output should be 63321(reverse order).
my code is:
n = str(input())
x = ""
z = 0
for z in range(len(n)):
if int(n)%int(n[z])==0:
x = n[z] + ""
else:
n.replace(n[z],"")
z = z+1
print(x[::-2])
if I input the number 122 here i get the output 2 but i should be getiing output of 221 why.
The reason why you are not getting the desired output in this code is because of several logical and syntactical errors in your code. Here are some of them:
You are using x = n[z] + "" to append the digits that divide n without any remainder, but this will overwrite the previous value of x every time. You should use x = x + n[z] instead.
You are using n.replace(n[z],"") to remove the digits that do not divide n without any remainder, but this will not modify the original value of n, since strings are immutable in Python. You should assign the result of n.replace(n[z],"") to a new variable, or use a different approach to filter out the unwanted digits.
You are using z = z+1 to increment the loop variable, but this is unnecessary and redundant, since the for loop already does that for you. You can remove this line.
You are using print(x[::-2]) to print the reversed value of x, but this will skip every other digit, since the negative step of -2 means you are slicing the string from the end to the beginning with a step of 2. You should use print(x[::-1]) instead, which will reverse the whole string. A possible corrected version of your code is:
python
n = str(input())
x = ""
for z in range(len(n)):
if int(n)%int(n[z])==0:
x = x + n[z]
print(x[::-1])
This code will print the reversed order of the digits of n that divide it without any remainder, as expected. For example, if the input is 122, the output will be 221.
The code works by iterating over each digit of the input number n, which is converted to a string for convenience. For each digit, it checks if it divides n without any remainder, using the modulo operator %. If it does, it appends the digit to the end of the string x, using the + operator. If it does not, it ignores the digit. After the loop, it prints the reversed value of x, using the slicing notation [::-1], which means start from the end and go backwards until the beginning.
This should do the Trick
num = input()
new_num = ""
for i in num:
if int(num)%int(i) == 0:
new_num += i
print(new_num[::-1])
I am new to programming and I am trying to find the python solution to the below exercise:
I need to compare the binary form of 2 numbers for the 3 cases from the attached image(AND, OR, XOR).Bellow is my code but I dont know how to make it work for all 3 cases. Thank you!
a,b = int(input("Please enter the first number: ")),int(input("Please enter the second number: "))
m = ""
n = ""
p = ""
print(sep="\n")
print(bin(a),bin(b),sep="\n")
print(sep="\n")
length = max([len(bin(a)), len(bin(b))])-2
# AND
for i in range(length):
if bin(a)[-1]== "1" and bin(b)[-1]== "1":
m+= "1"
else:
m+= "0"
a = a >> 1
b = b >> 1
print ("0b" + m[::-1],"| AND")
#OR
for i in range(length):
if bin(a)[-1]== "1" or bin(b)[-1]== "1":
n+= "1"
else:
n+= "0"
a = a >> 1
b = b >> 1
print ("0b" + n[::-1],"| OR")
#XOR
for i in range(length):
if bin(a)[-1] != bin(b)[-1] :
p+= "1"
else:
p+= "0"
a = a >> 1
b = b >> 1
print ("0b" + p[::-1],"| XOR")
The problem is that the first loop modifies your input variables a and b and leaves them at zero. That means the second and third loops have nothing to work with.
The easiest way to fix this is to put each loop in a separate function, the function can't modify the values that are passed in so they'll be automatically restored.
I've written out a long answer because I wish someone had when I was first learning python. Note that I very deliberately walk through all the steps and I don't present final code for everything. Sorry if it goes too slowly: I was trying to be clear, not patronising. Note the 'problem' with your code is merely the use of bitshifts to modify a and b.
There are quite a few 'interesting' ways of doing things in this code which it might be worth considering the 'standard' solutions to:
Printing blank lines
print(sep="\n")
This does nothing at all, because sep is only applied when there are multiple entries. Compare this:
print("hello", "world", sep="\n")
Can you see what sep does? The reason this line does what you think it does is that the default for end is also \n. To print a blank line you can use print(end="\n"), which is equivalent to print(), so the latter form is preferred.
Bitwise comparison
The easiest way to compare two numbers on the bit level is to do it with bitwise operations:
a = 0b11110000
b = 0b10101010
a & b # and
For the other bitwise operators, see:
https://wiki.python.org/moin/BitwiseOperators
Manual bitwise
The manual bitwise problem can be thought of as 'iterate the numbers by digit and do something on the digit'. You already have a good solution to the first problem: use bin() to get a string and iterate that. But you have a few paradigms in play, including using << to shift, which as #MarkRansom notes is modifying your integers. It would be more 'standard' to adopt a single iterating paradigm. Naively:
a = bin(0b11110000)
b = bin(0b10101010)
for i in range(len(a):
a_digit = int(a[i])
b_digit = int(b[i])
# comparison here
but more idiomatically:
for a_digit, b_digit in zip(a, b):
comparison(int(a_digit), int(b_digit))
Taking the 'and' case, since it's the easiest (I leave the other comparisons to you), the test is clearly a_digit == 1 and b_digit == 1. So we would write:
res = []
for a_digit, b_digit in zip(a,b):
res.append(int(a_digit) == 1 and int(b_digit == 1))
# res = [True, True, True, True, False, False, False, False]
but remembering that 1 is truthy in python, better would be:
res.append(int(a_digit) and int(b_digit))
And if we want 1 and 0:
res.append(1 if int(a_digit) and int(b_digit) else 0)
At which point we are ready to wrap it all up into a list comprehension:
res = [1 if int(a_digit) and int(b_digit) else 0 for a_digit, b_digit in zip(a,b)]
This paradigm is really worth learning. A listcomp is probably the most normal way to solve each of these problems 'manually', and the steps I've followed here can be worked through for the other cases (or, xor, nand, etc).
Addendum: unequal lengths
As pointed out in the comments, what happens if a and b aren't equal in length? I didn't address this, or skipping the b representation. (Note that bin() truncates e.g. 001 to 1) Personally if doing it manually I would make the user enter strings and handle those. For unequal lengths you have two options: pad with zeros, or use zip_longest on reversed inputs:
a = "100100"
b = "1011100"
l = max(len(a), len(b))
for a_digit, b_digit in zip(a.rjust(l, "0"), b.rjust(l, "0")):
...
here we take right-justify to the longest length (since the LSB is on the right hand side). Alternatively:
from itertools import zip_longest
for a_digit, b_digit in zip_longest(reversed(a), reversed(b), fillvalue="0"):
...
Note that in this case we deliberately work from LSB to MSB, so the order of digits is backwards. zip_longest will fill in for us, by default with None, but here with "0". Note that zip truncates to the length of the shortest argument.
Of course, if your numbers are represented as big-endian strings rather than the little-endian strings you get from python's bin() then the reversing is not needed, and you would want ljust for the other solution.
def decimalToBinary(n):
return bin(n).replace("0b", "")
## Uncomment the below two lines of code, if you are inputting the numbers in decimal format
# bin_a = str(decimalToBinary(int(input("Enter first number: "))))
# bin_b = str(decimalToBinary(int(input("Enter second number: "))))
## Uncomment the below two lines of code, if you are inputting the numbers in binary format
# bin_a = str(int(input("Enter first number: ")))
# bin_b = str(int(input("Enter second number: ")))
len_bin_a = len(bin_a)
len_bin_b = len(bin_b)
if len_bin_a > len_bin_b:
bin_b = "0" * (len_bin_a - len_bin_b) + bin_b
elif len_bin_a < len_bin_b:
bin_a = "0" * (len_bin_b - len_bin_a) + bin_a
or_result = "".join([str(int(bin_a[i]) | int(bin_b[i])) for i in range(len(bin_a))])
and_result = "".join([str(int(bin_a[i]) & int(bin_b[i])) for i in range(len(bin_a))])
xor_result = "".join([str(int(bin_a[i]) ^ int(bin_b[i])) for i in range(len(bin_a))])
print(or_result + "\tOR")
print(and_result + "\tAND")
print(xor_result + "\tXOR")
I will leave a link below if you wanna wander deep into Bitwise Operators in Python
https://www.geeksforgeeks.org/python-bitwise-operators/
Hope the code serves the purpose
Regards
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]
This question already has answers here:
How to determine the longest increasing subsequence using dynamic programming?
(20 answers)
Closed 6 years ago.
I need to find the minimum number of deletions required to make string sorted.
Sample Test case:
# Given Input:
teststr = "abcb"
# Expected output:
1
# Explanation
# In this test case, if I delete last 'b' from "abcb",
# then the remaining string "abc" is sorted.
# That is, a single deletion is required.
# Given Input:
teststr = "vwzyx"
# Expected output:
2
# Explanation
# Here, if I delete 'z' and 'x' from "vwzyx",
# then the remaining string "vwy" is a sorted string.
I tried the following but it gives time limit exceeded error.
Any other approach to this problem?
string = input()
prev_ord = ord(string[0])
deletion = 0
for char in string[1:]:
if ord(char) > prev_ord +1 or ord(char) < prev_ord:
deletion += 1
continue
prev_ord = ord(char)
print(deletion)
Your current algorithm will give incorrect results for many strings.
I suspect that there's a more efficient way to solve this problem, but here's a brute-force solution. It generates subsets of the input string, ordered by length, descending. The elements in the subsets retain the order from the original string. As soon as count_deletions finds an ordered subset it returns it (converted back into a string), as well as the number of deletions. Thus the solution it finds is guaranteed to be no shorter than any other sorted selection of the input string.
Please see the itertools docs for info about the various itertools functions I've used; the algorithm for generating subsets was derived from the powerset example in the Recipes section.
from itertools import chain, combinations
def count_deletions(s):
for t in chain.from_iterable(combinations(s, r) for r in range(len(s), 0, -1)):
t = list(t)
if t == sorted(t):
return ''.join(t), len(s) - len(t)
# Some test data.
data = [
"abcdefg",
"cba",
"abcb",
"vwzyx",
"zvwzyx",
"adabcef",
"fantastic",
]
for s in data:
print(s, count_deletions(s))
output
abcdefg ('abcdefg', 0)
cba ('c', 2)
abcb ('abc', 1)
vwzyx ('vwz', 2)
zvwzyx ('vwz', 3)
adabcef ('aabcef', 1)
fantastic ('fntt', 5)
That data set is not really adequate to fully test algorithms designed to solve this problem, but I guess it's an ok starting point. :)
Update
Here's a Python 3 implementation of the algorithm mentioned by Salvador Dali on the linked page. It's much faster than my previous brute-force approach, especially for longer strings.
We can find the longest sorted subsequence by sorting a copy of the string and then finding the Longest Common Subsequence (LCS) of the original string & the sorted string. Salvador's version removes duplicate elements from the sorted string because he wants the result to be strictly increasing, but we don't need that here.
This code only returns the number of deletions required, but it's easy enough to modify it to return the actual sorted string.
To make this recursive function more efficient it uses the lru_cache decorator from functools.
from functools import lru_cache
#lru_cache(maxsize=None)
def lcs_len(x, y):
if not x or not y:
return 0
xhead, xtail = x[0], x[1:]
yhead, ytail = y[0], y[1:]
if xhead == yhead:
return 1 + lcs_len(xtail, ytail)
return max(lcs_len(x, ytail), lcs_len(xtail, y))
def count_deletions(s):
lcs_len.cache_clear()
return len(s) - lcs_len(s, ''.join(sorted(s)))
data = [
"abcdefg",
"cba",
"abcb",
"vwzyx",
"zvwzyx",
"adabcef",
"fantastic",
]
for s in data:
print(s, count_deletions(s))
output
abcdefg 0
cba 2
abcb 1
vwzyx 2
zvwzyx 3
adabcef 1
fantastic 5
Hope it works for all cases :)
s = input()
s_2 = ''.join(sorted(set(s), key=s.index))
sorted_string = sorted(s_2)
str_to_list = list(s_2)
dif = 0
for i in range(len(sorted_string)):
if sorted_string[i]!=str_to_list[i]:
dif+=1
print(dif+abs(len(s)-len(s_2)))
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".