python excersice: lists sums - python

i have this excesice:
*Given a list L, we indicate with 𝑥 the generic element of L and with 𝑥 the element in a symmetrical position to 𝑥. Write it down a function examine_list which receives a list L of positive integers of even length and returns a boolean. In in particular, the function returns True if and only if, for each element 𝑥 of L, the sum of the values of 𝑥 and 𝑥 is greater
the sum of the values of the elements positioned between 𝑥 and 𝑥.
Note that, when 𝑥 and 𝑥 are adjacent, the sum of the values of the elements positioned between 𝑥 and 𝑥 can be assumed equal to zero.
Example: If L = [12, 9, 7, 2, 1, 1, 3, 12] then the function returns True, because:
12 + 12> 9 + 7 + 2 + 1 + 1 + 3;
9 + 3> 7 + 2 + 1 + 1;
7 + 1> 2 + 1;
2 + 1> 0.*
My code is this:
def sum_list(l):
list_sum = []
pst_num = 0
ult_num = -1
for num in range(len(l)//2):
list_sum.append(l[pst_num]+l[ult_num])
pst_num +=1
ult_num -=1
return list_sum
def examine_list(l):
somme_xd = sum_list(l)
list_without_first_nums = []
first = 1
last = -1
for n in range(len(l)//2):
list_without_first_nums.append(l[first:last])
first += 1
last -= 1
st_sum = 0
count = 0
for lists in range(len(list_without_first_nums)):
for nums in range(len(list_without_first_nums[lists])):
if somme_xd[st_sum] >= sum(list_without_first_nums[lists][nums]):
st_sum += 1
count += 1
if count == len(somme_xd):
return True
else:
return False
L = [12, 9, 7, 2, 1, 1, 3, 12]
examine_list(L)
I have created the sum_list who create a list of sums of the array.
my problem is the 2nd function: sum gives me always thid error:
Traceback (most recent call last):
File "C:\Users\ALESSA~1\AppData\Local\Temp\tempCodeRunnerFile.python", line 35, in <module>
examine_list(L)
File "C:\Users\ALESSA~1\AppData\Local\Temp\tempCodeRunnerFile.python", line 26, in examine_list
if somme_xd[st_sum] >= sum(list_without_first_nums[lists][nums]):
TypeError: 'int' object is not iterable

You could use recursion for this:
def examine_list(L):
return not L or L[0]+L[-1]>sum(L[1:-1]) and examine_list(L[1:-1])
L = [12, 9, 7, 2, 1, 1, 3, 12]
print(examine_list(L)) # True
Or a comprehension with the all() function:
def examine_list(L):
return all(L[i]+L[-1-i]>sum(L[i+1:-1-i]) for i in range(len(L)//2))
To avoid repeatedly adding subranges of the list (which is somewhat inefficient), you can do it in a loop that starts out with the total and progressively decreases it with the leftmost/rightmost items as it progresses inwards:
def examine_list(L):
total = sum(L)
for a,b in zip(L,reversed(L)): # progress inwards from both sides
total -= a+b # reduce total to get sum in between
if a+b <= total: return False # not x+x' > in-between sum
if total == 0: break # reached middle, stop
return True

Related

How to compare each element in the list and check if it's bigger then the element on the right

hello I am struggling with this problem for school and can't get my code to do what it needs to solve this. The question is: Define an element of a list of items to be a dominator if every element to its right (not just the one
element that is immediately to its right) is strictly smaller than that element. It wants me to count how many denominators are in the list.
def extract_increasing(digits):
countDem = 0
#check and see if there is anything in the list
if not digits:
return 0
#compare the first element to the one on the right of it
for x in range(len(digits)):
for y in range(x + 1, len(digits)):
if digits[x] > digits[y]:
countDem += 1
return countDem
The code below should check if a number in the list is a dominator.
def is_dominator(lst, idx):
for i in range(idx + 1, len(lst)):
if lst[i] >= lst[idx]:
return False
return True
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in digits:
print(is_dominator(digits, i))
The error in your code is that you're adding one for the counter every time the next value meets the condition.
for x in range(len(digits)):
for y in range(x + 1, len(digits)):
if digits[x] > digits[y]:
countDem += 1
Every time digits[x] > digits[y] is met you add one to your counter. You should only add one once you checked that all values to the right meet the condition.
isDem = False
for x in range(len(digits)):
for y in range(x + 1, len(digits)):
if digits[x] > digits[y]:
isDem = True
else:
isDem = False
#Once you went through all the values to the right you can add one to the counter
if isDem ==True:
countDem += 1
Hope that helps!
You start in the last element, and save always the max_element in every iteration, then you know always if exist some number grater than the current number. This is a little more efficient because it runs through the array only once.
def dominator(li: list):
sol = 0
max_number = -math.inf
for i in range(len(li)-1, -1,-1):
if li[i] > max_number:
sol+=1
max_number = li[i]
return sol
Try list comprehension
lst = [0, 10, 2, 6, 7]
new_lst = [v for k,v in enumerate(lst) if all(v > x for x in lst[k+1:])]
# [10, 7]
Update
def extract_increasing(digits: list) -> int:
countDem = 0
for x, y in enumerate(digits):
if all(y > a for a in digits[x+1:]):
countDem += 1
return countDem
lst = [0, 10, 2, 6, 7]
extract_increasing(lst) # -> 2

Python - a custom range where after add +1 to max then return minimum

I wonder if there is any function in python like that.
Example 01:
For example, if I specify the range from (1,12) integer. Then:
if current value is 12 and I add 1, it return 1 (go back to minimum)
if current value is 11 and I add 3, it return 2
Example 02:
Another example is if I set range from (5, 9). Then:
If current value is 8 and I add 2, it return 5
If current value is 8 and I add 7, it return 5
I know I can write a self-defined function for that, I am just curious to know if python has that similar function built in
The self-defined function:
def wrap_range(val, nmin, nmax, add_val):
nrange = nmax - nmin + 1
remain = add_val % nrange
val = val + remain
if val <= nmax:
return val
else:
val = val - nmax + nmin - 1
return val
Itertools has the cycle and islice functions that you can use to get what you want -
from itertools import cycle, islice
def repeated_offset(nmin, nmax, start, n):
rng = range(nmin, nmax + 1)
start_idx = list(rng).index(start)
value, *_ = islice(cycle(rng), start_idx + n, start_idx + n + 1)
return value
repeated_offset(1, 12, 12, 1)
# 1
repeated_offset(1, 12, 11, 3)
# 2
repeated_offset(5, 9, 8, 2)
# 5
repeated_offset(5, 9, 8, 7)
# 5
What about looping, subtracting while the total value is bigger than the lower boundary, while subtracting range wide.
def loopit(val, the_min, the_max, addition):
total = val + addition
diff = the_max - the_min + 1
if not total > the_min:
raise ValueError("The total value must be larger then lowest boundary of the range")
while the_max < total:
total -= diff
return total
if __name__ == '__main__':
print(loopit(12, 1, 12, 1))
print(loopit(11, 1, 12, 3))
print(loopit(8, 5, 9, 2))
print(loopit(8, 5, 9, 7))
output:
1
2
5
5

FibFrog Codility Problem - Optimising for Performance

I'm trying to solve the FibFrog Codility problem and I came up with the following approach:
If len(A) is 0 we know we can reach the other side in one jump.
If len(A) + 1 is a fibonacci number, we can also reach it in one jump.
Else, we loop through A, and for the positions we can reach, we check if we can either reach them directly from -1 using a fibonacci number (idx + 1 in fibonaccis) or if we can reach them by first jumping to another position (reachables) and then jumping to the current position. In either case, we also check if we can go from the current position to the end of the river - if we can, then we can return because we found the minimum number of steps required.
Finally, if unreachable is True once this loop completes, this means we can't reach any position using a Fibonacci number, so we return -1.
I'm getting 83% correctness and 0% performance with this approach.
I understand the solution is O(n^2), assuming the array consists of only 1, the nested loop for v in reachables: would run n times - however I'm not sure how else I can compute this, since for each of the positions I need to check whether we can reach it from the start of the array, or from any previous positions using a fibonacci number.
def solution(A):
if len(A) == 0: return 1
fibonaccis = fibonacci(len(A) + 3)
if len(A) + 1 in fibonaccis: return 1
leaves = [0] * len(A)
unreachable = True
reachables = []
for idx, val in enumerate(A):
if val == 1:
if idx + 1 in fibonaccis:
unreachable = False
leaves[idx] = 1
if len(A) - idx in fibonaccis:
return 2
reachables.append(idx)
elif len(reachables) > 0:
for v in reachables:
if idx - v in fibonaccis:
leaves[idx] = leaves[v] + 1
if len(A) - idx in fibonaccis:
return leaves[v] + 2
reachables.append(idx)
break
if unreachable: return -1
if len(A) - reachables[-1] in fibonaccis:
return leaves[reachables[-1]] + 1
def fibonacci(N):
arr = [0] * N
arr[1] = 1
for i in range(2, N):
arr[i] = arr[i-1] + arr[i-2]
return arr
Some suggestions for improving performance of your algorithm -
If len(A) = 100000, you are calculating 100003 fibonacci numbers, while we only need fibonacci numbers which are less than 100k, which would be <30 of them.
Your solution is O(n^4), since each X in reachables or Y in fibonaccis operation is O(N) where N is len(A). (and length of fibonaccis being N because of above issue)
Since you are doing a lot of item in list operations on fibonaccis and reachables, consider making it a set or a dictionary for faster(O(1) instead of O(n)) lookup.
Even with the above changes, the algorithm would be O(N^2) because of nested looping across A and reachables, so you need to come up with a better approach.
With your existing implementation, you need to traverse through all the paths and then in the end you will get the smallest number of jumps.
Instead of this approach, if you start at 0, and then keep a count of the number of jumps you have taken so far, and maintain how far(and to which numbers) you can reach after each jump then you can easily find the minimum jumps required to reach the end. (this will also save on redundant work you would have to do in case you have all 1s in A.
e.g. for
A = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
fibonacci = set(1, 2, 3, 5)
At first jump, we can reach following 1-based indexes -
reachable = [1, 2, 3, 5]
jumps = 1
After second jump
reachables = [2, 3, 4, 5, 6, 7, 8]
jumps = 2
After third jump
reachables = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
jumps = 3
so you have reached the end(10) after 3 jumps.
Please check out #nialloc's answer here - https://stackoverflow.com/a/64558623/8677071 which seems to be doing something similar.
Check out also my solution, which scores 100% on Codility tests and is easy to comprehend.
The idea is to track all possible positions of the frog after k jumps. If possible position == n, return k.
def fib_up_to(n):
numbers = [1]
i = 1
while True:
new_num = (numbers[-2] + numbers[-1]) if i > 1 else 2
if new_num > n:
break
numbers.append(new_num)
i += 1
return numbers
def solution(A):
n = len(A)
if n == 0:
return 1
numbers = fib_up_to(n+1)
possible_positions = set([-1])
for k in range(1, n+1):
positions_after_k = set()
for pos in possible_positions:
for jump in numbers:
if pos + jump == n:
return k
if pos + jump < n and A[pos + jump]:
positions_after_k.add(pos + jump)
possible_positions = positions_after_k
return -1

Counting elements in 2 arrays (GFG)

I was working on a GFG question
Question:
Given two unsorted arrays arr1[] and arr2[]. They may contain duplicates. For each element in arr1[] count elements less than or equal to it in array arr2[].
Example 1:
Input:
m = 6, n = 6
arr1[] = {1,2,3,4,7,9}
arr2[] = {0,1,2,1,1,4}
Output: 4 5 5 6 6 6
Explanation: Number of elements less than
or equal to 1, 2, 3, 4, 7, and 9 in the
second array are respectively 4,5,5,6,6,6
Example 2:
Input:
m = 5, n = 7
arr1[] = {4 8 7 5 1}
arr2[] = {4,48,3,0,1,1,5}
Output: 5 6 6 6 3
Your Task :
Complete the function countEleLessThanOrEqual() that takes two array arr1[], arr2[], m, and n as input and returns an array containing the required results(the count of elements less than or equal to it in arr2 for each element in arr1 where ith output represents the count for ith element in arr1.)
Expected Time Complexity: O((m + n) * log n).
Expected Auxiliary Space: O(1).
Constraints:
1<=m,n<=10^5
1<=arr1[i],arr2[j]<=10^5
My python solution:
def countEleLessThanOrEqual(arr1,n1,arr2,n2):
#returns the required output
res=[]
arr2.sort()
for i in range(n1):
search=arr1[i]
count=0
start=0
end=n2-1
while(start<=end):
mid = int(start+(end-start)/2)
if search==arr2[mid]:
start=mid+1
elif search>arr2[mid]:
start=mid+1
elif search<arr2[mid]:
end=mid-1
count=end+1
res.append(count)
return res
When I submit it, it gives me TLE error even though my solution is similar to the one posted in the editorial:
Editorial solution:
# python implementation of For each element in 1st
# array count elements less than or equal to it
# in 2nd array
# function returns the index of largest element
# smaller than equal to 'x' in 'arr'. For duplicates
# it returns the last index of occurrence of required
# element. If no such element exits then it returns -1
def bin_search(arr, n, x):
l = 0
h = n - 1
while(l <= h):
mid = int((l + h) / 2)
# if 'x' is greater than or equal to arr[mid],
# then search in arr[mid + 1...h]
if(arr[mid] <= x):
l = mid + 1;
else:
# else search in arr[l...mid-1]
h = mid - 1
# required index
return h
# function to count for each element in 1st array,
# elements less than or equal to it in 2nd array
def countElements(arr1, arr2, m, n):
# sort the 2nd array
arr2.sort()
# for each element in first array
for i in range(m):
# last index of largest element
# smaller than or equal to x
index = bin_search(arr2, n, arr1[i])
# required count for the element arr1[i]
print(index + 1)
# driver program to test above function
arr1 = [1, 2, 3, 4, 7, 9]
arr2 = [0, 1, 2, 1, 1, 4]
m = len(arr1)
n = len(arr2)
countElements(arr1, arr2, m, n)
# This code is contributed by Aditi Sharma
You could use a binary search on the second array after sorting it in place:
from bisect import bisect_right
def lowerCount(arr1,arr2):
arr2.sort()
return [bisect_right(arr2,v) for v in arr1]
print(*lowerCount([1,2,3,4,7,9],[0,1,2,1,1,4])) # 4 5 5 6 6 6
print(*lowerCount([4, 8, 7, 5, 1],[4,48,3,0,1,1,5])) # 5 6 6 6 3
Sorting arr2 is O(N log N), and binary searches will take O(M log N) for a total of O( (N+M) log N ).
If you can't use libraries, you could always write your own bisect_right function:
def bisect_right(A,x):
lo,hi = 0,len(A)-1
while lo <= hi:
mid = (lo+hi)//2
if A[mid] <= x: lo = mid+1
else: hi = mid-1
return hi+1
#AasthaJha, would you like to try this similar but simplified alternative version:
def bin_search(A, n, x):
low, high = 0, n-1
while low <= high:
mid = (low + high) // 2
# if 'x' is greater than or equal to A[mid],
# then search in arr[mid + 1...h]
if A[mid] <= x:
low = mid + 1;
else:
high = mid -1 # else search in A[l...mid-1]
return high
# function to count for each element in 1st array,
# elements less than or equal to it in 2nd array
def countElements(A, B, m, n):
B.sort()
result = []
# loop element in A - first array
for i in range(m):
# last index of largest element smaller than or equal to x
index = bin_search(B, n, A[i])
print(index + 1) # count
result.append(index + 1)
return result
# Testing
A = [1, 2, 3, 4, 7, 9]
B = [0, 1, 2, 1, 1, 4]
m, n = len(A), len(B)
print(countElements(A, B, m, n))

Fibonacci sequence using codelab

In the following sequence, each number (except the first two) is the sum of the previous two number: 0, 1, 1, 2, 3, 5, 8, 13, .... This sequence is known as the Fibonacci sequence.
Given the positive integers m and n (with m < n) create a list consisting of the portion of the Fibonacci sequence greater than or equal to m and less than or equal to n. For example, if m is 3 and n is 6, then the list would be [3, 5] and if m is 2 and n is 20, then the list would be [2, 3, 5, 8, 13].
Associate the list with the variable fib.
Have done this far, but still getting error.
Where does it need to be fixed?
fib = [0,1,1]
result = 0
while result <=n:
result=fib[-1]+fib[-2]
if result <=n and result>=m:
fib.append(result)
# create a fibonacci series from 0 to n
f = [0,1]
for i in range(1, n+1):
x = f[i]+f[i-1]
if x > n:
break
else:
f.append(x)
# copy only those numbers of series that are in range m to n
fib = []
for i in range(0, len(f)):
if f[i] >= m and f[i] <= n:
fib.append(f[i])
You could use the code below.
fib = [0,1,1]
fibrange = [] # keeps your digits that are in range m < n
result = 0
n = 80
m = 2
while result <=n:
result =fib[-1]+fib[-2]
fib.append(result)
if result <=n and result>=m:
fibrange.append(result)
print fibrange
fib=[0,1]
i=0
while i <=n:
i=fib[-1]+fib[-2]
if i<=n:
fib.append(i)

Categories

Resources