How to efficiently generate a list by the specified rules?
Rules:
num 20 occurs with step 2 in the list
num 40 occurs with step 4 in the list
num 60 occurs with step 8 in the list
num 80 occurs with step 16 in the list
The end result of a list of length 15 should look like this:
[20,40,20,60,20,40,20,80,20,40,20,60,20,40,20]
The "step" rules are always a power of something. In this example is power of 2.
So, let's say we have it written as:
rules_power = 2
n1 = 20
n1_step = 2
n2 = 40
n2_step = 4
n3 = 60
n3_step = 8
n4 = 80
n4_step = 16
How do we efficiently generate such a list?
Since you mentioned step rules are always powers, there is a rule to find where each element starts (appears the first time).
[20,40,20,60,20,40,20,80,20,40,20,60,20,40,20]
0 1 3 7
As you see each new element(20, 40, 60, 80) appears first where (2 ** i - 1). Knowing this, one could easily fill the empty list using indices and steps.
length = 15
lst = [0] * length # better use comprehension
for i in xrange(2 ** 0 - 1, length, n1_step):
lst[i] = n1
for i in xrange(2 ** 1 - 1, length, n2_step):
lst[i] = n2
for i in xrange(2 ** 2 - 1, length, n3_step):
lst[i] = n3
for i in xrange(2 ** 3 - 1, length, n4_step):
lst[i] = n4
print lst
Replace the power with your other cases, and the print, xrange for python 3 usage.
If you store the values and the steps inside a list, you can do this process with two nested for loops, no matter how many rules are there.
The complexity of this is O(2n), therefore n, should be enough, however because I don't know the original problem, I cannot give more.
Related
We are given a number N and we have to find pairs i and j where i^3=j^2
For example, let N=50 so for this we will have 3 pairs (1,1),(4,8),(9,27)
basically, we have to find pairs where the cube of one number is the same as the square of the other number in a given pair
the constraint is
1<=N<10^6
1<=i,j<N
Naive approach use 2 for loops iterate through each element and get those pairs where cube is equal to sum time complexity is O(n*2)
def get_pair(N):
for i in range(1,N):
for j in range(1,N):
if i*i*i==j*j:
print(i,j)
N=50
get_pair(N)
what will be an optimal way to solve this problem with a better time complexity?
Since you're working with integers, if there exists some number M = i^3 = j^2 for i and j between 1 and N, then that means there exists a k such that M = k^6. To find i and j, simply compare the representations of M:
(1) M = k^6 = i^3 = (k^2)^3 therefore i = k^2
(2) M = k^6 = j^2 = (k^3)^2 therefore j = k^3
Since j is always greater than or equal to i, you only need to check if 1 < k^3 < N. In other words, k should be less than the cube root of N.
k
M = k^6
i = k^2
j = k^3
2
64
4
8
3
729
9
27
4
4,096
16
64
5
15,625
25
125
6
46,656
36
216
...
...
...
...
97
8.329x10^11
9409
912,673
98
8.858x10^11
9604
941,192
99
9.415x10^11
9801
970,299
Note that 100 isn't a valid candidate for k because that would make j less than or equal to N instead of strictly less than N (if we're going with N = 10^6).
So to get the list of tuples that satisfy your problem, find the values of k such that 1 < k^3 < N and return its square and cube in a tuple.
import math
from typing import List, Tuple
N: int = 10**6
pairs: List[Tuple[int, int]] = [(k * k, k * k * k) for k in range(2, math.ceil(N**(1 / 3)))]
print(pairs)
This is a list comprehension, a shorthand for a for-loop.
I'm basically asking Python to generate a list of tuples over an index k that falls in the range defined as range(2, math.ceil(N**(1 / 3)). That range is exactly the first column of the table above.
Then, for every k in that range I make a tuple of which the first item is k^2 and the second item is k^3, just like the last two columns of the table.
Also threw in the typing library in there for good measure. Clear code is good code, even for something as small as this. Python can figure out that pairs is a list of tuples without anyone telling it, but this way I've explicitly enforced that variable to be a list of tuples to avoid any confusion when someone tries to give it a different value or isn't sure what the variable contains.
Another naive approach could be to use the "basic" values ?
def get_pair(N):
for i in range(N):
if(i**3 > MAX):
break # Limit to the max you want, and i**3 > i**2 if i > 1
print(i**2, i**3)
Time complexity seems to be O(n) (Not an expert, so correct me if i'm wrong)
This is made so that the first element cubed == second element squared:
first = a^2
second = a^3
first^3 = a^(2*3) = a^6
second^2 = a^(3*2) = a^6
You can use itertool's combinations_with_replacement function.
from itertools import combinations_with_replacement as combinations
def get_pair(N):
for i, j in combinations(range(1,N), 2):
if i*i*i==j*j:
print(i,j)
N=50
get_pair(N)
You do this with one loop (and minimal iterations) if you know that that pairs (x, y) are always y = x * i, this means you can use:
def get_pair(N):
i = 1
a = 1
while a * i < N:
b = a * i
print(a,b)
i += 1
a = i**2
N=50
get_pair(N)
This gets all 3 pairs:
1 1
4 8
9 27
In only 3 total iterations.
import itertools as itt
layer_thickness=[1,2,3,4,5]
permu= itt.permutations(layer_thickness,5)
permu_list=list(permu)
for i in permu_list:
if sum(i)==15:
print(i)
Here, I want permutations of the elements in the layer_thickness and those sum of the permutations should be to 5. But the number of elements in prmutation is not constrained by any limit unless it gives the desired sum.
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 , 2 2 2 2 2 2 2 1, etc are should be an element also.
what modifications should I do to achieve that?
You cant create all permutation as list for any total - it will simply hug too much memory:
Assuming [1,2,3,4,5] as numbers, 1 is your lowest element.
Assuming you want to reach a total = 15 - your "biggest" solution is (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1).
To create all possible permutation of 5 numbers over 15 places you need to create 15**5 list entries: 15**5 = 2.562.890.625 possible number permutations
Storing each combination as 1 byte this would need 2.56 Terabyte of ram. Doubt you got that much.
The best you can do is to generate only numbers that work and quit out as soon as you reached your total. To do that for a fixed number set you can start with this question: Finding all possible combinations of numbers to reach a given sum
Using that and provide a "maximized" list of your numbers that can be added up to achieve your goal might lead to something:
def subset_sum(numbers, target, partial=[], partial_sum=0):
if partial_sum == target:
yield partial
if partial_sum >= target:
return
for i, n in enumerate(numbers):
remaining = numbers[i + 1:]
yield from subset_sum(remaining, target, partial + [n], partial_sum + n)
Credit: https://stackoverflow.com/a/4633515/7505395
def calc_nums_for_permutate(nums, total):
"""Creates a list of numbers from num - each single number is added as
many times as itself fits into total"""
return [n for n in nums for _ in range(total//n)]
if __name__ == "__main__":
nums = [1, 2, 3, 4, 5]
total = 15
print( *subset_sum( calc_nums_for_permutate(nums, total), total))
This will not work for all and any inputs - good luck with your runtime, this will still work reasonably well for a total = 10 - for a total = 15 it will take more time then I needed to format/copy paste and formulate this answer here.
I am trying to solve a Dynamic programming problem which is as follows but unable to solve it.
You are given a primitive calculator that can perform the following three operations with the current number đť‘Ą: multiply đť‘Ą by 2, multiply đť‘Ą by 3, or add 1 to đť‘Ą. Your goal is given a positive integer đť‘›, find the minimum number of operations needed to obtain the number đť‘› starting from the number 1
I found the solution on stackoverflow itself but unable to understand what's going on.
I have heard that every DP problem can be solved by creating matrix which I was trying to do but don't know where I am going wrong. The table is created below which shows number of steps required to reach to n from 1, initially I take values as infinity.
i / j 0 1 2 3 4 5
plus 1 0 1 2 3 4 5
multiple by 2 0 infinity 2 infinity 3 infinity
multiple by 3 0 infinity infinity 2 infinity infinity
I am trying to solve this problem in Python.
Can someone please help me.
I found the solution which is as follows but not able to understand exactly what is going on:
import math
target = int(input())
def optVal(target, cache):
result = [1] * cache[-1] # 1
for i in range(1, cache[-1]): # 2
result[-i] = target # 3
if cache[target-1] == cache[target] - 1: # 4
target -= 1
elif target % 2 == 0 and (cache[target // 2] == cache[target] - 1): # 5
target //= 2
else: # 6 # target % 3 == 0 and (cache[target // 3] == cache[target] - 1):
target //= 3
return result
cache = [0] + [math.inf] * target # 1
for i in range(1, len(cache)): # 2
temp1 = math.inf
temp2 = math.inf
temp3 = math.inf
temp1 = cache[i - 1] + 1
if i % 2 == 0:
temp2 = cache[i // 2] + 1
if i % 3 == 0:
temp3 = cache[i // 3] + 1
cache[i] = min(temp1, temp2, temp3)
print('Minimum operation: ', cache[target] - 1)
finalLst = optVal(target, cache)
print(' '.join([str(x) for x in finalLst]))
Input:
5
Output:
3
1245
This algorithm is split in two parts. The first is in the main, the second is in the optVal function.
The first part builds the cache list, where cache[i] holds the minimum number of steps necessary to arrive from 0 to i applying, at each step, one of the three possible operations: +1, *2 or *3. This list is the 1-dimensional case of the matrix you read about.
When cache[i] is calculated, all indices lower than i already have been calculated. One can get to i in three possible ways, so a maximum of three possible sources of i, i.e., elements of cache, need to be examined: i-1, i//2 and i//3, but i//2 only if i is even, and i//3 only if i can be divided by 3. These elements of cache are compared, and the content of the winner, incremented by 1 (because of the extra step to get to i), is stored in cache. This process is bootstrapped by putting a 0 in cache[0]. In the end, cache[target] will contain the minimum number of steps to get to target starting from 0 (which is 1 more than the steps to get there starting from 1, which is how the problem was stated – note that you only can apply the +1 operation to move out from 0).
Now, if I had written the code, I probably would have stored the “parent” or the “winning operation” of each cache[i] together with the number of steps to get there (BTW, those math.inf are not really needed, because there always is a finite number of steps to reach i, because of the +1 operation.) The approach of the author is to infer this information from the content of the possible parents (max 3) of each cache[i] that needs to be examined. In both cases, the chain of “ancestors” has to be reconstructed backwards, starting from cache[target], and this is what happens in optVal().
In optVal() the target is changed at each iteration (a bit confusingly), because at each iteration the info you have is the minimum number of steps needed to reach a certain target number. Knowing that, you look at the 1, 2 or 3 possible parents to check which one contains exactly that number of steps minus 1. The one that passes the test is the actual parent, and so you can continue building the chain backwards replacing target with the parent.
to solve this DP, you have to construct a table of minimum number of steps required to get n, if one two or all the operations were available. you will be creating it left to right, top to bottom, ie 1 to n, add 1 to mul 3. As you go down more number of operations are available
A cells value only depends on the value above it (if available) and atmax 3 values in the left side eg. for (n = 6),(mul 3) cell will depend only on (n = 6),(mul 2) and (n = 2)(mul 3), (n = 3)(mul 3), (n = 5)(mul 3). you will then compare these values and whichever is smaller after operation, you will put that value, so you will be comparing value of (n = 2)(mul 3) + 1 vs (n = 3)(mul 3) + 1 vs (n = 5)(mul 3) + 1 vs (n = 6)(mul 2), and then whichever is smaller you will put that value
since n = 1 is given, the first column would have all the values as zero
for n = 2, its values will depend on values of n = 1. you can "add 1" or "multiply by 2" (1 step), both are valid. so this column will have all the values as 0 + 1 = 1
for n = 3, its values will depend on values of n = 1 (because 1 = 1/3 of 3) AND n = 2. if you can only "add 1" or "multiply by 2", then you will choose to add 1 to n = 2 so total steps 1+1 = 2. BUT if you could also multiply by three you will need only one step so 0 + 1 = 1. since 1 < 2 you will put 1 as this value. so the entries for n = 3 is 2, 2, 1
for n = 4, it will depend on n = 3 (add 1), and n = 2 (mul 2). so the values will be 3, 2, 2
for n = 5, it will depend on n = 4 (add 1). so the values will be 4, 3, 3
so the minimum steps are 3 to reach n = 5
final table:
1 2 3 4 5
add 1 0 1 2 3 4
mul 2 0 1 2 2 3
mul 3 0 1 1 2 3
#include <bits/stdc++.h>
using namespace std;
int rec(vector<int> &dp,int n)
{
if(n==1) return 0;
if(dp[n]!=INT_MAX) return dp[n];
return dp[n]=min({1+rec(dp,n-1),(n%2==0)?1+rec(dp,n/2):INT_MAX,(n%3==0)?1+rec(dp,n/3):INT_MAX});
}
string genseq(vector<int> &dp, int n){
string res="";
while(n>1)
{
res=to_string(n)+" "+res;
if(dp[n-1]==(dp[n]-1)) n--;
else if(n%2==0&&( dp[n/2]==dp[n]-1)) n/=2;
else if(n%3==0&&( dp[n/3]==dp[n]-1)) n/=3;
}
return "1 "+res;
}
int main()
{
int n;
cin>>n;
vector<int> dp(n+1,INT_MAX);
dp[0]=0;
dp[1]=0;
std::cout << rec(dp,n) << std::endl;
std::cout << genseq(dp,n) << std::endl;
return 0;
}
I am trying to print prime numbers less than 'n'.The code is below:
def prime_numbers(n):
A=[1 for i in range(n+1)]
for i in range(2,int(sqrt(n))):
if A[i]==1:
for j in range(i*2,n,i):
A[j]=0
for i in range(n):
if A[i]:
print(i)
Output for
prime_numbers(10)
is
0
1
2
3
5
7
9
The program correctly prints for 100. What changes do I need to make?
The end point in a range() is not included. Since sqrt(10) is 3.1623, your range() loops to 2 and no further, and the multiples of 3 are not removed from your list. Your code works for 100, because it doesn't matter if you test for multiples 10 (those are already covered by 2 and 5).
The same issue applies to your other loops; if you want to include n itself as a candidate prime number you should also include it in the other ranges.
Note that you also want to ignore 0 and 1, those are not primes. You could add A[0] = A[1] = False at the top to make sure your last loop doesn't include those, or start your last loop at 2 rather than 0.
You want to add one to the floored square root to make sure it is tested for:
for i in range(2, int(sqrt(n)) + 1):
I'd use booleans rather than 0 and 1, by the way, just for clarity (there is not much of a performance or memory footprint difference here):
def prime_numbers(n):
sieve = [True] * (n + 1) # create a list n elements long
for i in range(2, int(sqrt(n)) + 1):
if sieve[i]:
for j in range(i * 2, n + 1, i):
sieve[j] = False
for i in range(2, n + 1):
if sieve[i]:
print(i)
I used [..] * (n + 1) to create a list of n items (plus 0); this produces a list with n shallow copies of the contents of the left operand. That's faster than a list comprehension, and the shared references are fine since True is a singleton in Python.
Demo:
>>> prime_numbers(31)
2
3
5
7
11
13
17
19
23
29
31
Note that 31 is included there; your code would have resulted in incorrect output as you'd have left in all the multiples of 5.
Hi I'm trying to figure out a function where given a length n of a list [x1, x2... xn], how many digits would be needed for a base 2 number system to assign a unique code to each value in the list.
For example, one digit can hold two unique values:
x1 0
x2 1
two digits can hold four:
x1 00
x2 01
x3 10
x4 11
etc. I'm trying to write a python function calcBitDigits(myListLength) that takes this list length and returns the number of digits needed. calcBitDigits(2) = 1, calcBitDigits(4) = 2, calcBitDigits(3) = 2, etc.
>>> for i in range(10):
... print i, i.bit_length()
0 0
1 1
2 2
3 2
4 3
5 3
6 3
7 3
8 4
9 4
I'm not clear on exactly what it is you want, but it appears you want to subtract 1 from what bit_length() returns - or maybe not ;-)
On third thought ;-), maybe you really want this:
def calcBitDigits(n):
return (n-1).bit_length()
At least that gives the result you said you wanted in each of the examples you gave.
Note: for an integer n > 0, n.bit_length() is the number of bits needed to represent n in binary. (n-1).bit_length() is really a faster way of computing int(math.ceil(math.log(n, 2))).
Clarification: I understand the original question now ;-) Here's how to think about the answer: if you have n items, then you can assign them unique codes using the n integers in 0 through n-1 inclusive. How many bits does that take? The number of bits needed to express n-1 (the largest of the codes) in binary. I hope that makes the answer obvious instead of mysterious ;-)
As comments pointed out, the argument gets strained for n=1. It's a quirk then that (0).bit_length() == 0. So watch out for that one!
Use the following -
import math
int(math.ceil(math.log(x,2)))
where x is the list length.
Edit:
For x = 1, we need to have a separate case that would return 1. Thanks #thefourtheye for pointing this out.
I am not comfortable with the other answers, since most of them fail at the corner case (when n == 1). So, I wrote this based on Tim's answer.
def calcBitDigits(n):
if n <= 0: return 0
elif n <= 2: return 1
return (n-1).bit_length()
for i in range(10):
print i, calcBitDigits(i)
Output
0 0
1 1
2 1
3 2
4 2
5 3
6 3
7 3
8 3
9 4
x = int(log(n,2))+1
x will be the number of bits required to store the integer value n.
If for some reason you don't want to use .bit_length, here's another way to find it.
from itertools import count
def calcBitDigits(n):
return next(i for i in count() if 1<<i >= n)