Related
Take integer input from a user and then delete the elements from an array having those many consecutive ocurences from the array.
Eg the input array is "aabcca" and the input from the user is 2.
Then the answer should be "ba".
I tried it when the elements are not repeated. My code works perfectly for examples like "aaabbccc".
for j in range(t, (n+1)):
if (t == n):
if (count == k):
array = [x for x in array if x != temp]
print array
exit()
if (t == n and count == k):
array = [x for x in array if x != temp]
print array
exit()
if temp == data[j]:
count += 1
t += 1
if temp != data[j]:
if count == k:
array = [x for x in array if x != temp]
temp = data[t]
count = 1
t += 1
you can use sliding window or two pointers to solve it.
the key point is use [start, end] range to record a consecutive seq, and only add the seq whose length less than n:
def delete_consecutive(s, n):
start, end, count = 0, 0, 0
res, cur = '', ''
for end, c in enumerate(s):
if c == cur:
count += 1
else:
# only add consecutive seq less than n
if count < n:
res += s[start:end]
count = 1
start = end
cur = c
# deal with tail part
if count < n:
res += s[start:end+1]
return res
test and output:
print(delete_consecutive('aabcca', 2)) # output: ba
print(delete_consecutive('aaabbccc', 3)) # output: bb
Hope that helps you, and comment if you have further questions. : )
Here is one way to do that:
def remove_consecutive(s, n):
# Number of repeated consecutive characters
count = 0
# Previous character
prev = None
# Pieces of string of result
out = []
for i, c in enumerate(s):
# If new character
if c != prev:
# Add piece of string without repetition blocks
out.append(s[i - (count % n):i])
# Reset count
count = 0
# Increase count
count += 1
prev = c
# Add last piece
out.append(s[len(s) - (count % n):])
return ''.join(out)
print(remove_consecutive('aabcca', 2))
# ba
print(remove_consecutive('aaabbccc', 2))
# ac
print(remove_consecutive('aaabbccc', 3))
# bb
I am trying to develop a method for finding the orderd rank of a particular sequence in the following lists.
a = list(sorted(itertools.combinations(range(0,5),3)))
b = list(sorted(itertools.permutations(range(0,5),3)))
a represents a list of elemnts of a combinatorial number system so the formula for rank is pretty straight forward.
What I need are 2 function magic_rank_1 and magic_rank_2 which have the following definitions
def magic_rank_1(perm_item,permutation_list_object):
## permutation_list_object is actually b
return list_object.index(perm_item)
def magic_rank_2(perm_item,permutation_list_object,combination_list_object):
## permutation_list_object is actually b and combination_list_object is actually a
return combination_list_object.index(tuple(sorted(perm_item)))
So basically magic_rank_2((0,1,2),b,a) = magic_rank_2((2,0,1),b,a)
Sounds easy.. but i have a few restrictions.
I cant use the indexof function because I cannot afford to search lists >100000000 items for every item
I need magic_rank_1 and magic_rank_2 to be purely mathematical without using any sort function or comparison functions or search function. All the information I will have is the tuple whose rank needs to be identified and the last letter of my alphabet (in this case that will be 5)
magic rank 2 need not be a number between 0 and k-1 when k = len(a) as long as it is a unique number between 0 and 2^(ceiling((max_alphabet/2)+1))
I know magic_rank_1 can be calculated by something similar to this but there is a difference ,there every letter of the input alphabet is used, in my case it is a subset
Lastly yes this is supposed to be a substitute for a hashing function, currently using a hashing function but I am not taking advantage of the fact that magic_rank_2((0,1,2),b,a) = magic_rank_2((2,0,1),b,a) . If i can it will reduce my storage space requirements significantly as the length of my sequences is actually 5 , so if I can calculate a method for magic_rank_2 I reduce my storage requirement to 1% of current requirement
UPDATE
- For magic_rank_2 there should be no comparison operation between elements of the tuple, i.e no sorting, min,max etc
that only makes the algorithm less efficient than regular hashing
The following two functions will rank a combination and permutation, given a word and an alphabet (or in your case, a tuple and a list).
import itertools
import math
def rank_comb(word, alph, depth=0):
if not word: return 0
if depth == 0:
word = list(word)
alph = sorted(alph)
pos = 0
for (i,c) in enumerate(alph):
if c == word[0]:
# Recurse
new_word = [x for x in word if x != c]
new_alph = [x for x in alph if x > c]
return pos + rank_comb(new_word, new_alph, depth+1)
else:
num = math.factorial(len(alph)-i-1)
den = math.factorial(len(alph)-i-len(word)) * math.factorial(len(word)-1)
pos += num // den
def rank_perm(word, alph, depth=0):
if not word: return 0
if depth == 0:
word = list(word)
alph = sorted(alph)
pos = 0
for c in alph:
if c == word[0]:
# Recurse
new_word = [x for x in word if x != c]
new_alph = [x for x in alph if x != c]
return pos + rank_perm(new_word, new_alph, depth+1)
else:
num = math.factorial(len(alph)-1)
den = math.factorial(len(alph)-len(word))
pos += num // den
#== Validation =====================================================================
# Params
def get_alph(): return range(8)
r = 6
a = list(sorted(itertools.combinations(get_alph(), r)))
b = list(sorted(itertools.permutations(get_alph(), r)))
# Tests
PASS_COMB = True
PASS_PERM = True
for (i,x) in enumerate(a):
j = rank_comb(x, get_alph())
if i != j:
PASS_COMB = False
print("rank_comb() FAIL:", i, j)
for (i,x) in enumerate(b):
j = rank_perm(x, get_alph())
if i != j:
PASS_PERM = False
print("rank_perm() FAIL:", i, j)
print("rank_comb():", "PASS" if PASS_COMB else "FAIL")
print("rank_perm():", "PASS" if PASS_PERM else "FAIL")
The functions are similar, but there are few differences:
new_alph is filtered differently.
The calculation of both num and den are different.
Update:
rank_comb2 doesn't require sorting the input word (a 3-tuple):
import itertools
import math
def rank_comb2(word, alph, depth=0):
if not word: return 0
if depth == 0:
word = list(word)
alph = sorted(alph)
pos = 0
for (i,c) in enumerate(alph):
if c == min(word):
# Recurse
new_word = [x for x in word if x != c]
new_alph = [x for x in alph if x > c]
return pos + rank_comb2(new_word, new_alph, depth+1)
else:
num = math.factorial(len(alph)-i-1)
den = math.factorial(len(alph)-i-len(word)) * math.factorial(len(word)-1)
pos += num // den
r1 = rank_comb2([2,4,1], range(5))
r2 = rank_comb2([1,4,2], range(5))
r3 = rank_comb2([4,1,2], range(5))
print(r1, r2, r3) # 7 7 7
I was wondering if there is any easier way to achieve what this code is achieving. Now the code creates all 4-digits number in a list (if the number starts with a 0 is doesn't count as a 4-digit, for example 0123) and no digit is repeated within the number. So for example 1231 is not in the list. Preferable I want a code that does what this one is doing but a depending on what argument N is given to the function upon calling it creates this kind of list with all numbers with N digits. I hope this wasn't impossible to understand since Im new to programing.
def guessables():
'''creates a list of all 4 digit numbers wherest every
element has no repeating digits inside of that number+
it doesn't count as a 4 digit number if it starts with a 0'''
guesses=[]
for a in range(1,10):
for b in range(0,10):
if a!=b:
for c in range(0,10):
if b!=c and a!=c:
for d in range(0,10):
if c!=d and d!=b and d!=a:
guesses.append(str(a)+str(b)+str(c)+str(d))
return guesses
This can be expressed more easily.
def all_digits_unique(number):
# `set` will only record unique elements.
# We convert to a string and check if the unique
# elements are the same number as the original elements.
return len(str(number)) == len(set(str(number)))
Edit:
def guesses(N):
return filter(all_digits_unique, range(10**(N-1), 10**N))
print guesses(4)
I'd use itertools for this which is in my opinion the simplest generic answer:
import itertools
def guessables(num):
guesses = []
for p in itertools.permutations(xrange(10),num):
if p[0] != 0:
guesses.append(''.join(map(str, p)))
return guesses
Simply call this function with guessables(4) and get a list with all the numbers you want.
You can do in one line:
print([str(a)+str(b)+str(c)+str(d) for a in range(1,10) for b in range(0,10) if a!=b for c in range(0,10) if b!=c and a!=c for d in range(0,10) if c!=d and d!=b and d!=a])
Try the following:
def guessables(n):
''' Returns an array with the combination of different digits of size "n" '''
if n > 10:
raise ValueError("The maximum number of different digits is 10.")
elif n < 1:
raise ValueError("The minimum number of digits is 1.")
else:
results = []
for i in range(1, 10):
_recursiveDigit([i], n, results)
return results
def _formatDigit(l):
''' Return a formated number from a list of its digits. '''
return "".join(map(str, l))
def _recursiveDigit(l, n, results):
''' Recursive function to calculate the following digit. '''
if len(l) < n:
for i in range(0, 10):
if i not in l:
_recursiveDigit(l + [i], n, results)
else:
results.append(_formatDigit(l))
The functions that are prefixed with an underscore(_) should not be called from outside of this script. If you prefer to have the result as something different than an array of strings, such as an array of ints for example, you can change the _formatDigit() function as follows:
def _formatDigit(l):
''' Return a formated number from a list of its digits. '''
return int("".join(map(str, l)))
c=list(range(10))
print c
def fun(n,k,i,getnum): # function , result in getnum
if n==0:
if k not in getnum and len(set(list(k)))==len(k) and k[0]!='0':
getnum.append(k)
return
if i>=len(c):
return
fun(n-1,k+str(c[i]),0,getnum)
fun(n,k,i+1,getnum)
getnum=[]
d=fun(4,"",0,getnum)
print getnum
These types of problems are easily solved with recursion.
def gen(num, n, saveto):
if len(num) == 1 and num[0] == '0':
return
if len(num) == n:
saveto.append(int(''.join(num)))
return
for i in range(0, 10):
i= str(i)
if i not in num:
gen(num+[i], n, saveto)
saveto= []
# generate 4 digit numbers
gen([], 4, saveto)
print(saveto)
Here I'm using the list num to construct the numbers by placing one digit at each call. When there are four digits added, it stores the number to the saveto list.
Edit: Here's a version of the above function that returns the list of numbers instead of appending them to a list.
def gen(num, n):
if len(num) == 1 and num[0] == '0':
return []
if len(num) == n:
return [int(''.join(num))]
ans = []
for i in range(0, 10):
i= str(i)
if i not in num:
ans.extend(gen(num+[i], n))
return ans
saveto= gen([], 4)
print(saveto)
numPool = []
for i in range(0, 10):
for j in range(0, 10):
for k in range(0,10):
for l in range(0,10):
if i != j and i != k and i != l and j != k and j != l and k != l :
numPool.append(str(i) + str(j) + str(k) + str(l))
This works, but keep in mind that this will also add "0123" or "0234" to the list as well. If you do not want the numbers that are starting with zero, you might want to add "i != 0" to the if query. Hope it helps.
I try to write it clear for absolute beginers ^^ Ofcourse it is possible to make it faster and shorter if you use combianations and advance array methods.
def f(n)
s = list(range(10**(n-1), 10**n))
number_list = []
for ss in s:
test_list = []
a = ss
while ss:
if ss % 10 in test_list:
break
test_list.append(ss % 10)
ss = ss // 10
if len(test_list) == n:
number_list.append(a)
return number_list
print(f(4))
This would sovlve the problem, without repeating digits:
from itertools import permutations
myperm = permutations([0,1,2,3,4,5,6,7,8,9],4)
for digits in list(myperm):
print(digits)
How about this?
def check_count(num):
if isinstance(num, str) == False:
num = str(num) # Convert to str
if len(num) == 1: # If total length number is single, return False
return False
return any(num.count(x) > 1 for x in num) # Check here
Return False if numbers all different, else return True
Usage:
# Get all numbers has all different. (1000-9999)
[x for x in range(1000, 10000) if check_count(x) == False]
Problem: Given two binary strings, return their sum (also a binary string).
For example, add_binary_strings('11', '1') should return '100'.
Implementation 1:
def addBinary(a, b):
"""
:type a: str
:type b: str
:rtype: str
"""
a = a[::-1]
b = b[::-1]
carry = '0'
result = ''
# Pad the strings to make their size equal
if len(a) < len(b):
for i in range(len(a), len(b)):
a += '0'
elif len(a) > len(b):
for i in range(len(b), len(a)):
b += '0'
n = len(a)
carry = 0
s = ''
for i in range(n):
l, m, c = int(a[i]), int(b[i]), carry
s += str(l^m^c) # sum is XOR of three bits
carry = (l&m) | (m&c) | (c&l) # carry is pairwise AND of three bits
if carry == 1:
s += str(carry)
return s[::-1]
Implementation 2
def addBinary(self, a, b):
"""
:type a: str
:type b: str
:rtype: str
"""
a = a[::-1]
b = b[::-1]
m = min(len(a), len(b))
carry = '0'
result = ''
for i in range(m):
r, carry = add_digit(a[i], b[i], carry=carry)
result += r
larger, shorter = a, b
if len(a) < len(b):
larger, shorter = b, a
for i in range(len(shorter), len(larger)):
if carry != '0':
r, carry = add_digit(larger[i], carry)
result += r
else:
result += larger[i]
if carry != '0':
result += carry
return result[::-1]
def add_digit(digit1, digit2, carry=None):
if carry is None:
carry = '0'
d1, d2, c = int(digit1), int(digit2), int(carry)
s = d1 + d2 + c
return str(s%2), str(s//2)
According to an online judge, the performance for the first implementation is better in terms of time. However, I find the first implementation to be a bit too verbose because I always have to make both the strings of the same size.
What is the time complexity of creating a new string of length n? I would like to know what are the corresponding space and time complexities for these implementations and how can I improve on the code.
What are the tradeoffs between the implementations and when should I not use a particular one of them?
For example, I should use the 2nd implementation in favour of the 1st
when the size of input strings will differ considerably on the
general.
If problem is defined as:
Given two binary strings, return their sum (also a binary string).
For example, add_binary_strings('11', '1') should return '100'.
Then you just need to do:
def add_binary_strings(a, b):
return '{:b}'.format(int(a,2) + int(b,2))
print(add_binary_strings('11', '1'))
This solution should be faster than the one you found.
I would modify your solution to:
def addBinary(a, b):
max_len = max(len(a), len(b))
a = a.zfill(max_len)
b = b.zfill(max_len)
c = ''
reminder = 0
for i in range(max_len-1, -1, -1):
c = str((int(a[i]) + int(b[i]) + reminder) % 2) + c
reminder = 1 if int(a[i]) + int(b[i])+ reminder > 1 else 0
c = str(reminder) + c
return c
this would save some inversions compared yo your solutions, which would save a bit of time (ouch!). You can omit the last assignment to c if you do not want to increase the length of the output, though you may overflow!
Given any iterable, for example: "ABCDEF"
Treating it almost like a numeral system as such:
A
B
C
D
E
F
AA
AB
AC
AD
AE
AF
BA
BB
BC
....
FF
AAA
AAB
....
How would I go about finding the ith member in this list? Efficiently, not by counting up through all of them. I want to find the billionth (for example) member in this list. I'm trying to do this in python and I am using 2.4 (not by choice) which might be relevant because I do not have access to itertools.
Nice, but not required: Could the solution be generalized for pseudo-"mixed radix" system?
--- RESULTS ---
# ------ paul -----
def f0(x, alph='ABCDE'):
result = ''
ct = len(alph)
while x>=0:
result += alph[x%ct]
x /= ct-1
return result[::-1]
# ----- Glenn Maynard -----
import math
def idx_to_length_and_value(n, length):
chars = 1
while True:
cnt = pow(length, chars)
if cnt > n:
return chars, n
chars += 1
n -= cnt
def conv_base(chars, n, values):
ret = []
for i in range(0, chars):
c = values[n % len(values)]
ret.append(c)
n /= len(values)
return reversed(ret)
def f1(i, values = "ABCDEF"):
chars, n = idx_to_length_and_value(i, len(values))
return "".join(conv_base(chars, n, values))
# -------- Laurence Gonsalves ------
def f2(i, seq):
seq = tuple(seq)
n = len(seq)
max = n # number of perms with 'digits' digits
digits = 1
last_max = 0
while i >= max:
last_max = max
max = n * (max + 1)
digits += 1
result = ''
i -= last_max
while digits:
digits -= 1
result = seq[i % n] + result
i //= n
return result
# -------- yairchu -------
def f3(x, alphabet = 'ABCDEF'):
x += 1 # Make us skip "" as a valid word
group_size = 1
num_letters = 0
while 1: #for num_letters in itertools.count():
if x < group_size:
break
x -= group_size
group_size *= len(alphabet)
num_letters +=1
letters = []
for i in range(num_letters):
x, m = divmod(x, len(alphabet))
letters.append(alphabet[m])
return ''.join(reversed(letters))
# ----- testing ----
import time
import random
tries = [random.randint(1,1000000000000) for i in range(10000)]
numbs = 'ABCDEF'
time0 = time.time()
s0 = [f1(i, numbs) for i in tries]
print 's0 paul',time.time()-time0, 'sec'
time0 = time.time()
s1 = [f1(i, numbs) for i in tries]
print 's1 Glenn Maynard',time.time()-time0, 'sec'
time0 = time.time()
s2 = [f2(i, numbs) for i in tries]
print 's2 Laurence Gonsalves',time.time()-time0, 'sec'
time0 = time.time()
s3 = [f3(i,numbs) for i in tries]
print 's3 yairchu',time.time()-time0, 'sec'
times:
s0 paul 0.470999956131 sec
s1 Glenn Maynard 0.472999811172 sec
s2 Laurence Gonsalves 0.259000062943 sec
s3 yairchu 0.325000047684 sec
>>> s0==s1==s2==s3
True
Third time's the charm:
def perm(i, seq):
seq = tuple(seq)
n = len(seq)
max = n # number of perms with 'digits' digits
digits = 1
last_max = 0
while i >= max:
last_max = max
max = n * (max + 1)
digits += 1
result = ''
i -= last_max
while digits:
digits -= 1
result = seq[i % n] + result
i //= n
return result
Multi-radix solution at the bottom.
import math
def idx_to_length_and_value(n, length):
chars = 1
while True:
cnt = pow(length, chars)
if cnt > n:
return chars, n
chars += 1
n -= cnt
def conv_base(chars, n, values):
ret = []
for i in range(0, chars):
c = values[n % len(values)]
ret.append(c)
n /= len(values)
return reversed(ret)
values = "ABCDEF"
for i in range(0, 100):
chars, n = idx_to_length_and_value(i, len(values))
print "".join(conv_base(chars, n, values))
import math
def get_max_value_for_digits(digits_list):
max_vals = []
for val in digits_list:
val = len(val)
if max_vals:
val *= max_vals[-1]
max_vals.append(val)
return max_vals
def idx_to_length_and_value(n, digits_list):
chars = 1
max_vals = get_max_value_for_digits(digits_list)
while True:
if chars-1 >= len(max_vals):
raise OverflowError, "number not representable"
max_val = max_vals[chars-1]
if n < max_val:
return chars, n
chars += 1
n -= max_val
def conv_base(chars, n, digits_list):
ret = []
for i in range(chars-1, -1, -1):
digits = digits_list[i]
radix = len(digits)
c = digits[n % len(digits)]
ret.append(c)
n /= radix
return reversed(ret)
digits_list = ["ABCDEF", "ABC", "AB"]
for i in range(0, 120):
chars, n = idx_to_length_and_value(i, digits_list)
print "".join(conv_base(chars, n, digits_list))
What you're doing is close to a conversion from base 10 (your number) to base 6, with ABCDEF being your digits. The only difference is "AA" and "A" are different, which is wrong if you consider "A" the zero-digit.
If you add the next greater power of six to your number, and then do a base conversion to base 6 using these digits, and finally strip the first digit (which should be a "B", i.e. a "1"), you've got the result.
I just want to post an idea here, not an implementation, because the question smells a lot like homework to me (I do give the benefit of the doubt; it's just my feeling).
First compute the length by summing up powers of six until you exceed your index (or better use the formula for the geometric series).
Subtract the sum of smaller powers from the index.
Compute the representation to base 6, fill leading zeros and map 0 -> A, ..., 5 -> F.
This works (and is what i finally settled on), and thought it was worth posting because it is tidy. However it is slower than most answers. Can i perform % and / in the same operation?
def f0(x, alph='ABCDE'):
result = ''
ct = len(alph)
while x>=0:
result += alph[x%ct]
x /= ct-1
return result[::-1]
alphabet = 'ABCDEF'
def idx_to_excel_column_name(x):
x += 1 # Make us skip "" as a valid word
group_size = 1
for num_letters in itertools.count():
if x < group_size:
break
x -= group_size
group_size *= len(alphabet)
letters = []
for i in range(num_letters):
x, m = divmod(x, len(alphabet))
letters.append(alphabet[m])
return ''.join(reversed(letters))
def excel_column_name_to_idx(name):
q = len(alphabet)
x = 0
for letter in name:
x *= q
x += alphabet.index(letter)
return x+q**len(name)//(q-1)-1
Since we are converting from a number Base(10) to a number Base(7), whilst avoiding all "0" in the output, we will have to adjust the orginal number, so we do skip by one every time the result would contain a "0".
1 => A, or 1 in base [0ABCDEF]
7 => AA, or 8 in base [0ABCDEF]
13 => BA, or 15 in base [0ABCDEF]
42 => FF, or 48 in base [0ABCDEF]
43 =>AAA, or 50 in base [0ABCDEF]
Here's some Perl code that shows what I'm trying to explain
(sorry, didn't see this is a Python request)
use strict;
use warnings;
my #Symbols=qw/0 A B C D E F/;
my $BaseSize=#Symbols ;
for my $NR ( 1 .. 45) {
printf ("Convert %3i => %s\n",$NR ,convert($NR));
}
sub convert {
my ($nr,$res)=#_;
return $res unless $nr>0;
$res="" unless defined($res);
#Adjust to skip '0'
$nr=$nr + int(($nr-1)/($BaseSize-1));
return convert(int($nr/$BaseSize),$Symbols[($nr % ($BaseSize))] . $res);
}
In perl you'd just convert your input i from base(10) to base(length of "ABCDEF"), then do a tr/012345/ABCDEF/ which is the same as y/0-5/A-F/. Surely Python has a similar feature set.
Oh, as pointed out by Yarichu the combinations are a tad different because if A represented 0, then there would be no combinations with leading A (though he said it a bit different). It seems I thought the problem to be more trivial than it is. You cannot just transliterate different base numbers, because numbers containing the equivalent of 0 would be
skipped in the sequence.
So what I suggested is actually only the last step of what starblue suggested, which is essentially what Laurence Gonsalves implemented ftw. Oh, and there is no transliteration (tr// or y//) operation in Python, what a shame.