find string containing least operations to make all characters same - python

I have a 3 string(for ex- aabacc,bababb,aaaaba) of equal no. of characters. I want to compare them and find the string which takes less operation to become all character same. Let's say string(aabacc) take 3 operation to become(aaaaaa) while string (bababb) take 2 operation to become(bbbbbb) and string(aaaaba) take 1 operation to become same(aaaaaa). So the output will be string(aaaaba) and operation 1. Can anybody tell me how to approach this problem. I doesn't need entire code even small logic is helpful.
# Function to find the minimum
# operations to convert given
# string to another with equal
# frequencies of characters
def minOperations(s,p,r):
# Frequency of characters
freq = [0] * 26
freq1 = [0] * 26
freq2 = [0] * 26
n = len(s)
n1 = len(p)
n2 = len(q)
# Loop to find the Frequency
# of each character
for i in range(n):
freq[ord(s[i]) - ord('A')] += 1
for i1 in range(n1):
freq[ord(p[i1] - ord('A')] += 1
for i2 in range(n2):
freq[ord(r[i2] - ord('A')] += 1
# Sort in decreasing order
# based on frequency
freq.sort(reverse = True)
freq1.sort(reverse = True)
freq2.sort(reverse = True)
# Maximum possible answer
answer = n
answer1 = n1
answer2 = n2
# Loop to find the minimum operations
# required such that frequency of
# every character is equal
for i in range(1, 27):
if (n % i == 0):
x = n //i
y = 0
for j in range(i):
y += min(freq[j], x)
answer = min(answer, n - y)
for i1 in range(1,27):
if(n1 % i1 == 0):
x1 = n1 // i1
y1 = 0
for j1 in range(i1):
y1 += min(freq1[j1], x1)
answer1 = min(answer1, n1 - y1)
for i2 in range(1,27):
if(n2 % i2 == 0):
x2 = n2 // i2
y2 = 0
for j2 in range(i2):
y2 += min(freq2[j2], x2)
answer2 = min(answer2, n2 - y2)
if (answer < answer1)&&(answer < answer2):
print(answer)
elif (answer1 < answer) && (answer < answer3):
print(answer1)
else:
print(answer2)
# Driver Code
if __name__ == "__main__":
s = "BBC"
p = "AAD"
R = "DDD"
print (minOperations(s,p,r))

from collections import Counter
word = 'aaaaba'
counts = Counter(word)
max_freq = max(counts.values())
conversions = len(word) - max_freq
To get the minimum operations to make all characters of a string same, convert all characters
Get the frequency of all characters in the string.
Get the character with maximum frequency (say, max_freq)
Now convert all other characters, except the one with maximum frequency, to that character with max freq. The number of conversions required is string_length - max_freq.

Based on the formulation of the problem, the solution could look like this:
def str_cmp(str1):
charset = set(str1)
frequent = max(str1.count(s) for s in charset)
return str1, len(str1) - frequent
print(str_cmp('aabacc'))
print(str_cmp('bababb'))
print(str_cmp('aaaaba'))
Output
('aabacc', 3)
('bababb', 2)
('aaaaba', 1)

If you just want the string that takes the least amount of operations (substitute char for char) to equalize with respect to individual characters, isn't the answer always just the result of finding the string for which the amount of characters different from the most frequent character is minimized?
def evaluate(string):
assert len(string) > 0
freq = {string[0]: 1}
most_frequent = string[0]
for char in string[1:]:
if char in freq:
freq[char] += 1
if char != most_frequent and freq[most_frequent] < freq[char]:
most_frequent = char
else:
freq[char] = 1
return len(string) - freq[most_frequent]
def solve(A):
best = min(A, key=evaluate)
print(best)
solve(["awd", "awdawdawd", "awodijawd"])

Related

Find maximum binary number with rotations, exceed time limit

Passed some test cases, but after submission, the time limit exceeded. How to optimize solution to reduce time complexity?
A large binary number is represented by a string A of size N and
comprises of 0s and 1s. You must perform a cyclic shift on this
string. The cyclic shift operation is defined as follows:
If the string A is [A0, A1,..., An-1], then after performing one
cyclic shift, the string becomes [A1, A2,..., An-1, A0].
You performed the shift infinite number of times and each time you
recorded the value of the binary number represented by the string. The
maximum binary number formed after performing (possibly 0) the
operation is B. Your task is to determine the number of cyclic shifts
that can be performed such that the value represented by the string A
will be equal to B for the Kth time.
Input format:
First line: A single integer T denoting the number of test cases For
each test case: First line: Two space-separated integers N and K
Second line: A denoting the string
Output format:
For each test case, print a single line containing one integer that
represents the number of cyclic shift operations performed such that
the value represented by string A is equal to B for the Kth time.
num_test_cases = int(input())
for i in range(num_test_cases):
array_length, num_of_repetition = map(int, input().split())
count = 0
bin_num = input()
original_bin_num = bin_num
dec_num = int(bin_num, 2)
maximum = dec_num
dec_num_array = [dec_num]
for j in range(array_length - 1):
bin_num = bin_num[1:] + bin_num[0]
if bin_num == original_bin_num:
break
dec_num = int(bin_num, 2)
dec_num_array.append(dec_num)
maximum = max(dec_num_array)
maxIndex = dec_num_array.index(maximum)
num_cyclic_shifts = 0
for kek in range(num_of_repetition):
if kek == 0:
num_cyclic_shifts += maxIndex
elif len(dec_num_array) == array_length:
num_cyclic_shifts += array_length
elif len(dec_num_array) < array_length:
num_cyclic_shifts += len(dec_num_array)
print(num_cyclic_shifts)
Since you asked for optimization of your code here's how I did it.
Replace the last for loop with a formula.
num_cyclic_shifts = maxIndex + (len(dec_num_array) * (num_of_repetition-1))
Entire code will become ,
num_test_cases = int(input())
for i in range(num_test_cases):
array_length, num_of_repetition = map(int, input().split())
count = 0
bin_num = input()
original_bin_num = bin_num
dec_num = int(bin_num, 2)
maximum = dec_num
dec_num_array = [dec_num]
for j in range(array_length - 1):
bin_num = bin_num[1:] + bin_num[0]
if bin_num == original_bin_num:
break
dec_num = int(bin_num, 2)
dec_num_array.append(dec_num)
maximum = max(dec_num_array)
maxIndex = dec_num_array.index(maximum)
num_cyclic_shifts = maxIndex + (len(dec_num_array) * (num_of_repetition-1))
print(num_cyclic_shifts)

Speeding Up Python 3.4 Code

I have a problem where I need to find the next largest palindrome after a given number, however I am running into problems with the runtime being over 1 second. Is there any way I can speed this code up?
inp = input()
if inp == '9' * len(inp):
print('1' + ('0' * (len(inp) - 1)) + '1') #ran into a problem where 999 would give 9109
else:
num = list(inp)
oldnum = int(inp)
if len(num) % 2 == 0: #for even length numbers
for i in range(len(num) // 2):
num[len(num) // 2 + i] = num[len(num) // 2 - 1 - i]
if int("".join(num)) > oldnum:
print("".join(num))
else:
#sometimes the palindrome was smaller eg: 1199 --> 1111
num[len(num) // 2 - 1] = str(int(num[len(num) // 2 - 1]) + 1)
num[len(num) // 2] = str(int(num[len(num) // 2]) + 1)
print("".join(num))
else: #basically the same but for odd length numbers
for i in range(len(num) // 2):
num[len(num) // 2 + 1 + i] = num[len(num) // 2 - 1 - i]
if int("".join(num)) > oldnum:
print("".join(num))
else:
num[len(num) // 2] = str(int(num[len(num) // 2]) + 1)
print("".join(num))
Here's how I would break it down,
# simple version, easy to understand and fast enough
# up to maybe a thousand digits
def next_palindrome(n):
"""
Find the first integer p such that p > n and p is palindromic
"""
# There are two forms of palindrome:
# even number of digits, abccba
# odd number of digits, abcba
# Find abc
s = str(n)
abc = s[:(len(s) + 1) // 2]
# There are six possibilites for p:
#
# abcpq < abcba -> p = abcba
# abcpq >= abcba -> p = ab(c + 1)ba (with carries as needed)
# abcpqr == 999999 -> p = 1000001 *(num digits + 1)
#
# abcpqr < abccba -> p = abccba
# abcpqr >= abccba -> p = ab(c+1)(c+1)ba (with carries as needed)
# abcpq == 99999 -> p = 100001 *(num digits + 1)
#
# *Note that the even-number-of-9s case is properly handled by
# odd-digits-with-carry, but odd-number-of-9s needs special handling
#
# Make basis substrings
cba = abc[::-1]
ba = cba[1:]
abc1 = str(int(abc) + 1)
cba1 = abc1[::-1]
ba1 = cba1[1:]
# Assemble candidate values
candidates = [
int(abc + ba), # abcba
int(abc1 + ba1), # ab(c+1)ba
int(abc + cba), # abccba
int(abc1 + cba1), # ab(c+1)(c+1)ba
int(abc1[:-1] + ba1) # handles odd-number-of-9s
]
# Find the lowest candidate > n
return min(c for c in candidates if c > n)
def main():
while True:
n = int(input("\nValue for n (or -1 to quit): "))
if n == -1:
break
else:
print("Next palindrome is {}".format(next_palindrome(n)))
if __name__ == "__main__":
main()
which runs like
Value for n (or -1 to quit): 12301
Next palindrome is 12321
Value for n (or -1 to quit): 12340
Next palindrome is 12421
Value for n (or -1 to quit): 99999
Next palindrome is 100001
Value for n (or -1 to quit): 123001
Next palindrome is 123321
Value for n (or -1 to quit): 123400
Next palindrome is 124421
Value for n (or -1 to quit): 999999
Next palindrome is 1000001
Value for n (or -1 to quit): -1
Edit: I thought you were talking about maybe 100 digits. A million digits makes it worth spending more time minimizing the number of string operations and typecasts, like so:
# Super-efficient version
# for playing with million-digit palindromes
def str_lt(x, y):
"""
Take two integer strings, `x` and `y`,
return int(`x`) < int(`y`)
"""
return len(x) < len(y) or x < y
def str_add_1(n):
"""
Given an integer string `n`,
return str(int(n) + 1)
"""
# find the first non-9 digit, starting from the right
for i in range(len(n) - 1, -1, -1):
if n[i] != '9':
return n[:i] + str(int(n[i]) + 1) + '0' * (len(n) - i - 1)
# string was all 9s - overflow
return '1' + '0' * len(n)
def next_palindrome(n):
"""
For non-negative integer `n` (as int or str)
find the first integer p such that p > n and p is palindromic
Return str(p)
Note: `n` must be well-formed, ie no leading 0s or non-digit characters
"""
# Make sure n is a string
if not isinstance(n, str):
n = str(n)
# There are three forms of palindrome:
# single digit, x (ab == '')
# even number of digits, abba ( x == '')
# odd number of digits, abxba ( x is single digit)
#
if len(n) == 1:
# take care of single digit case
return '11' if n == '9' else str_add_1(n)
else:
# There are six possibilites for p:
#
# (1) abqr < abba -> p = abba
# (2) abqr >= abba -> p = a(b+1)(b+1)a (with carries as needed)
# (3) abqr == 9999 -> p = 10001 (carry results in overflow)
#
# (4) abxqr < abxba -> p = abxba
# (5) abxqr >= abxba -> p = ab(x + 1)ba (with carries as needed)
# (6) abxqr == 99999 -> p = 100001 (carry results in overflow)
#
# Find ab, x, qr
half = len(n) // 2
ab = n[ : half]
x = n[ half:-half] # a 0- or 1-digit string
qr = n[-half: ]
ba = ab[::-1]
if str_lt(qr, ba):
# solve cases (1) and (4)
return "".join([ab, x, ba])
if x == '9':
# do manual carry from x
ab1 = str_add_1(ab)
ba1 = ab1[::-1]
if len(ab1) > len(ab):
# carry results in overflow - case (6)
return ab1 + ba1
else:
# carry but no overflow - case (5)
return "".join([ab1, '0', ba1])
if x:
# no carry - case (5)
return "".join([ab, str_add_1(x), ba])
# x == ''
ab1 = str_add_1(ab)
ba1 = ab1[::-1]
if len(ab1) > len(ab):
# carry results in overflow - case (3)
return ab1[:-1] + ba1
else:
# no overflow - case (2)
return ab1 + ba1
On my machine, this finds a million-digit palindrome in less than 0.002 seconds (vs about 18.5 seconds for your code).
Although your code took less than a second for me. But why so much code for just finding a plaindrome. Why not simple do
def next_palindrome(num):
while True:
if str(num) == str(num)[::-1]:
break
num += 1
return num

Longest common substring

I am trying to create a program which will receive two strings and compeer between, and returns the largest common letters in the order they appear.
examples:
string1="a" string2="b"
return ""
string1="abc" string2="ac"
return "ac"
string1:“abcd” string2:“ acdbb”
return:“ abcd"
I need to write 3 codes - "normal way", recursive way and "in memorization" way.
So far I've succeed to code:
def l_c_s(s1, s2):
for i in range(1 + len(s1))]:
mi = [[0] * (1 + len(s2))
long, x_long = 0, 0
for x in range(1, 1 + len(s1)):
for y in range(1, 1 + len(s2)):
if s1[x - 1] == s2[y - 1]:
m[x][y] = m[x - 1][y - 1] + 1
if m[x][y] > long:
long = m[x][y]
x_long = x
m[x][y] = 0
return s1[x_long - long: x_long]
But I don't get what I wanted. just run this code for the string1="abc" string2="ac"
and the see what happens.
Moreover, I have no idea how to make it recursive and neither to write it in memo.
If what you want is really longest common sub-sequence, here is a version using memoization:
s1 = 'abcdd'
s2 = 'add'
mem = [[-1] * len(s2)] * len(s1)
matched = []
def lcs(i,j):
if i < 0 or j < 0:
return 0
if mem[i][j] >= 0:
return mem[i][j]
if s1[i] == s2[j]:
p = 1 + lcs(i-1, j-1)
if p > mem[i][j]:
mem[i][j] = p
matched.append(s1[i])
return max(mem[i][j], lcs(i-1, j), lcs(i, j-1))
lcs_length = lcs(len(s1)-1, len(s2)-1)
lcs = "".join(matched)
print 'LCS: <%s> of length %d' % (lcs, lcs_length)

Optimizing python code

Any tips on optimizing this python code for finding next palindrome:
Input number can be of 1000000 digits
COMMENTS ADDED
#! /usr/bin/python
def inc(lst,lng):#this function first extract the left half of the string then
#convert it to int then increment it then reconvert it to string
#then reverse it and finally append it to the left half.
#lst is input number and lng is its length
if(lng%2==0):
olst=lst[:lng/2]
l=int(lng/2)
olst=int(olst)
olst+=1
olst=str(olst)
p=len(olst)
if l<p:
olst2=olst[p-2::-1]
else:
olst2=olst[::-1]
lst=olst+olst2
return lst
else:
olst=lst[:lng/2+1]
l=int(lng/2+1)
olst=int(olst)
olst+=1
olst=str(olst)
p=len(olst)
if l<p:
olst2=olst[p-3::-1]
else:
olst2=olst[p-2::-1]
lst=olst+olst2
return lst
t=raw_input()
t=int(t)
while True:
if t>0:
t-=1
else:
break
num=raw_input()#this is input number
lng=len(num)
lst=num[:]
if(lng%2==0):#this if find next palindrome to num variable
#without incrementing the middle digit and store it in lst.
olst=lst[:lng/2]
olst2=olst[::-1]
lst=olst+olst2
else:
olst=lst[:lng/2+1]
olst2=olst[len(olst)-2::-1]
lst=olst+olst2
if int(num)>=int(lst):#chk if lst satisfies criteria for next palindrome
num=inc(num,lng)#otherwise call inc function
print num
else:
print lst
I think most of the time in this code is spent converting strings to integers and back. The rest is slicing strings and bouncing around in the Python interpreter. What can be done about these three things? There are a few unnecessary conversions in the code, which we can remove. I see no way to avoid the string slicing. To minimize your time in the interpreter you just have to write as little code as possible :-) and it also helps to put all your code inside functions.
The code at the bottom of your program, which takes a quick guess to try and avoid calling inc(), has a bug or two. Here's how I might write that part:
def nextPal(num):
lng = len(num)
guess = num[:lng//2] + num[(lng-1)//2::-1] # works whether lng is even or odd
if guess > num: # don't bother converting to int
return guess
else:
return inc(numstr, n)
This simple change makes your code about 100x faster for numbers where inc doesn't need to be called, and about 3x faster for numbers where it does need to be called.
To do better than that, I think you need to avoid converting to int entirely. That means incrementing the left half of the number without using ordinary Python integer addition. You can use an array and carry out the addition algorithm "by hand":
import array
def nextPal(numstr):
# If we don't need to increment, just reflect the left half and return.
n = len(numstr)
h = n//2
guess = numstr[:n-h] + numstr[h-1::-1]
if guess > numstr:
return guess
# Increment the left half of the number without converting to int.
a = array.array('b', numstr)
zero = ord('0')
ten = ord('9') + 1
for i in range(n - h - 1, -1, -1):
d = a[i] + 1
if d == ten:
a[i] = zero
else:
a[i] = d
break
else:
# The left half was all nines. Carry the 1.
# Update n and h since the length changed.
a.insert(0, ord('1'))
n += 1
h = n//2
# Reflect the left half onto the right half.
a[n-h:] = a[h-1::-1]
return a.tostring()
This is another 9x faster or so for numbers that require incrementing.
You can make this a touch faster by using a while loop instead of for i in range(n - h - 1, -1, -1), and about twice as fast again by having the loop update both halves of the array rather than just updating the left-hand half and then reflecting it at the end.
You don't have to find the palindrome, you can just generate it.
Split the input number, and reflect it. If the generated number is too small, then increment the left hand side and reflect it again:
def nextPal(n):
ns = str(n)
oddoffset = 0
if len(ns) % 2 != 0:
oddoffset = 1
leftlen = len(ns) / 2 + oddoffset
lefts = ns[0:leftlen]
right = lefts[::-1][oddoffset:]
p = int(lefts + right)
if p < n:
## Need to increment middle digit
left = int(lefts)
left += 1
lefts = str(left)
right = lefts[::-1][oddoffset:]
p = int(lefts + right)
return p
def test(n):
print n
p = nextPal(n)
assert p >= n
print p
test(1234567890)
test(123456789)
test(999999)
test(999998)
test(888889)
test(8999999)
EDIT
NVM, just look at this page: http://thetaoishere.blogspot.com/2009/04/finding-next-palindrome-given-number.html
Using strings. n >= 0
from math import floor, ceil, log10
def next_pal(n):
# returns next palindrome, param is an int
n10 = str(n)
m = len(n10) / 2.0
s, e = int(floor(m - 0.5)), int(ceil(m + 0.5))
start, middle, end = n10[:s], n10[s:e], n10[e:]
assert (start, middle[0]) == (end[-1::-1], middle[-1]) #check that n is actually a palindrome
r = int(start + middle[0]) + 1 #where the actual increment occurs (i.e. add 1)
r10 = str(r)
i = 3 - len(middle)
if len(r10) > len(start) + 1:
i += 1
return int(r10 + r10[-i::-1])
Using log, more optized. n > 9
def next_pal2(n):
k = log10(n + 1)
l = ceil(k)
s, e = int(floor(l/2.0 - 0.5)), int(ceil(l/2.0 + 0.5))
mmod, emod = 10**(e - s), int(10**(l - e))
start, end = divmod(n, emod)
start, middle = divmod(start, mmod)
r1 = 10*start + middle%10 + 1
i = middle > 9 and 1 or 2
j = s - i + 2
if k == l:
i += 1
r2 = int(str(r1)[-i::-1])
return r1*10**j + r2

Average of two strings in alphabetical/lexicographical order

Suppose you take the strings 'a' and 'z' and list all the strings that come between them in alphabetical order: ['a','b','c' ... 'x','y','z']. Take the midpoint of this list and you find 'm'. So this is kind of like taking an average of those two strings.
You could extend it to strings with more than one character, for example the midpoint between 'aa' and 'zz' would be found in the middle of the list ['aa', 'ab', 'ac' ... 'zx', 'zy', 'zz'].
Might there be a Python method somewhere that does this? If not, even knowing the name of the algorithm would help.
I began making my own routine that simply goes through both strings and finds midpoint of the first differing letter, which seemed to work great in that 'aa' and 'az' midpoint was 'am', but then it fails on 'cat', 'doggie' midpoint which it thinks is 'c'. I tried Googling for "binary search string midpoint" etc. but without knowing the name of what I am trying to do here I had little luck.
I added my own solution as an answer
If you define an alphabet of characters, you can just convert to base 10, do an average, and convert back to base-N where N is the size of the alphabet.
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def enbase(x):
n = len(alphabet)
if x < n:
return alphabet[x]
return enbase(x/n) + alphabet[x%n]
def debase(x):
n = len(alphabet)
result = 0
for i, c in enumerate(reversed(x)):
result += alphabet.index(c) * (n**i)
return result
def average(a, b):
a = debase(a)
b = debase(b)
return enbase((a + b) / 2)
print average('a', 'z') #m
print average('aa', 'zz') #mz
print average('cat', 'doggie') #budeel
print average('google', 'microsoft') #gebmbqkil
print average('microsoft', 'google') #gebmbqkil
Edit: Based on comments and other answers, you might want to handle strings of different lengths by appending the first letter of the alphabet to the shorter word until they're the same length. This will result in the "average" falling between the two inputs in a lexicographical sort. Code changes and new outputs below.
def pad(x, n):
p = alphabet[0] * (n - len(x))
return '%s%s' % (x, p)
def average(a, b):
n = max(len(a), len(b))
a = debase(pad(a, n))
b = debase(pad(b, n))
return enbase((a + b) / 2)
print average('a', 'z') #m
print average('aa', 'zz') #mz
print average('aa', 'az') #m (equivalent to ma)
print average('cat', 'doggie') #cumqec
print average('google', 'microsoft') #jlilzyhcw
print average('microsoft', 'google') #jlilzyhcw
If you mean the alphabetically, simply use FogleBird's algorithm but reverse the parameters and the result!
>>> print average('cat'[::-1], 'doggie'[::-1])[::-1]
cumdec
or rewriting average like so
>>> def average(a, b):
... a = debase(a[::-1])
... b = debase(b[::-1])
... return enbase((a + b) / 2)[::-1]
...
>>> print average('cat', 'doggie')
cumdec
>>> print average('google', 'microsoft')
jlvymlupj
>>> print average('microsoft', 'google')
jlvymlupj
It sounds like what you want, is to treat alphabetical characters as a base-26 value between 0 and 1. When you have strings of different length (an example in base 10), say 305 and 4202, your coming out with a midpoint of 3, since you're looking at the characters one at a time. Instead, treat them as a floating point mantissa: 0.305 and 0.4202. From that, it's easy to come up with a midpoint of .3626 (you can round if you'd like).
Do the same with base 26 (a=0...z=25, ba=26, bb=27, etc.) to do the calculations for letters:
cat becomes 'a.cat' and doggie becomes 'a.doggie', doing the math gives cat a decimal value of 0.078004096, doggie a value of 0.136390697, with an average of 0.107197397 which in base 26 is roughly "cumcqo"
Based on your proposed usage, consistent hashing ( http://en.wikipedia.org/wiki/Consistent_hashing ) seems to make more sense.
Thanks for everyone who answered, but I ended up writing my own solution because the others weren't exactly what I needed. I am trying to average app engine key names, and after studying them a bit more I discovered they actually allow any 7-bit ASCII characters in the names. Additionally I couldn't really rely on the solutions that converted the key names first to floating point, because I suspected floating point accuracy just isn't enough.
To take an average, first you add two numbers together and then divide by two. These are both such simple operations that I decided to just make functions to add and divide base 128 numbers represented as lists. This solution hasn't been used in my system yet so I might still find some bugs in it. Also it could probably be a lot shorter, but this is just something I needed to get done instead of trying to make it perfect.
# Given two lists representing a number with one digit left to decimal point and the
# rest after it, for example 1.555 = [1,5,5,5] and 0.235 = [0,2,3,5], returns a similar
# list representing those two numbers added together.
#
def ladd(a, b, base=128):
i = max(len(a), len(b))
lsum = [0] * i
while i > 1:
i -= 1
av = bv = 0
if i < len(a): av = a[i]
if i < len(b): bv = b[i]
lsum[i] += av + bv
if lsum[i] >= base:
lsum[i] -= base
lsum[i-1] += 1
return lsum
# Given a list of digits after the decimal point, returns a new list of digits
# representing that number divided by two.
#
def ldiv2(vals, base=128):
vs = vals[:]
vs.append(0)
i = len(vs)
while i > 0:
i -= 1
if (vs[i] % 2) == 1:
vs[i] -= 1
vs[i+1] += base / 2
vs[i] = vs[i] / 2
if vs[-1] == 0: vs = vs[0:-1]
return vs
# Given two app engine key names, returns the key name that comes between them.
#
def average(a_kn, b_kn):
m = lambda x:ord(x)
a = [0] + map(m, a_kn)
b = [0] + map(m, b_kn)
avg = ldiv2(ladd(a, b))
return "".join(map(lambda x:chr(x), avg[1:]))
print average('a', 'z') # m#
print average('aa', 'zz') # n-#
print average('aa', 'az') # am#
print average('cat', 'doggie') # d(mstr#
print average('google', 'microsoft') # jlim.,7s:
print average('microsoft', 'google') # jlim.,7s:
import math
def avg(str1,str2):
y = ''
s = 'abcdefghijklmnopqrstuvwxyz'
for i in range(len(str1)):
x = s.index(str2[i])+s.index(str1[i])
x = math.floor(x/2)
y += s[x]
return y
print(avg('z','a')) # m
print(avg('aa','az')) # am
print(avg('cat','dog')) # chm
Still working on strings with different lengths... any ideas?
This version thinks 'abc' is a fraction like 0.abc. In this approach space is zero and a valid input/output.
MAX_ITER = 10
letters = " abcdefghijklmnopqrstuvwxyz"
def to_double(name):
d = 0
for i, ch in enumerate(name):
idx = letters.index(ch)
d += idx * len(letters) ** (-i - 1)
return d
def from_double(d):
name = ""
for i in range(MAX_ITER):
d *= len(letters)
name += letters[int(d)]
d -= int(d)
return name
def avg(w1, w2):
w1 = to_double(w1)
w2 = to_double(w2)
return from_double((w1 + w2) * 0.5)
print avg('a', 'a') # 'a'
print avg('a', 'aa') # 'a mmmmmmmm'
print avg('aa', 'aa') # 'a zzzzzzzz'
print avg('car', 'duck') # 'cxxemmmmmm'
Unfortunately, the naïve algorithm is not able to detect the periodic 'z's, this would be something like 0.99999 in decimal; therefore 'a zzzzzzzz' is actually 'aa' (the space before the 'z' periodicity must be increased by one.
In order to normalise this, you can use the following function
def remove_z_period(name):
if len(name) != MAX_ITER:
return name
if name[-1] != 'z':
return name
n = ""
overflow = True
for ch in reversed(name):
if overflow:
if ch == 'z':
ch = ' '
else:
ch=letters[(letters.index(ch)+1)]
overflow = False
n = ch + n
return n
print remove_z_period('a zzzzzzzz') # 'aa'
I haven't programmed in python in a while and this seemed interesting enough to try.
Bear with my recursive programming. Too many functional languages look like python.
def stravg_half(a, ln):
# If you have a problem it will probably be in here.
# The floor of the character's value is 0, but you may want something different
f = 0
#f = ord('a')
L = ln - 1
if 0 == L:
return ''
A = ord(a[0])
return chr(A/2) + stravg_half( a[1:], L)
def stravg_helper(a, b, ln, x):
L = ln - 1
A = ord(a[0])
B = ord(b[0])
D = (A + B)/2
if 0 == L:
if 0 == x:
return chr(D)
# NOTE: The caller of helper makes sure that len(a)>=len(b)
return chr(D) + stravg_half(a[1:], x)
return chr(D) + stravg_helper(a[1:], b[1:], L, x)
def stravg(a, b):
la = len(a)
lb = len(b)
if 0 == la:
if 0 == lb:
return a # which is empty
return stravg_half(b, lb)
if 0 == lb:
return stravg_half(a, la)
x = la - lb
if x > 0:
return stravg_helper(a, b, lb, x)
return stravg_helper(b, a, la, -x) # Note the order of the args

Categories