Related
I have an array and given an array of size N containing positive integers and I want to count number of smaller elements on right side of each array.
for example:-
Input:
N = 7
arr[] = {12, 1, 2, 3, 0, 11, 4}
Output: 6 1 1 1 0 1 0
Explanation: There are 6 elements right
after 12. There are 1 element right after
1. And so on.
And my code for this problem is like as :-
# python code here
n=int(input())
arr=list(map(int,input().split()))
ans=0
ANS=[]
for i in range(n-1):
for j in range(i+1,n):
if arr[i]>arr[j]:
ans+=1
ANS.append(ans)
ans=0
ANS.append(0)
print(ANS)
but the above my code take O(n^2) time complexity and I want to reduce the this. If anyone have any idea to reduce above python code time complexity please help me. Thank you.
This solution is O(n log(n)) as it is three iterations over the values and one sorting.
arr = [12, 1, 2, 3, 0, 11, 4]
# Gather original index and values
tups = []
for origin_index, el in enumerate(arr):
tups.append([origin_index, el])
# sort on value
tups.sort(key=lambda t: t[1])
res = []
for sorted_index, values in enumerate(tups):
# check the difference between the sorted and original index
# If there is a positive value we have the n difference smaller
# values to the right of this index value.
if sorted_index - values[0] > 0:
res.append([values[0], (sorted_index - values[0])])
elif sorted_index - values[0] == 0:
res.append([values[0], (sorted_index - values[0]) + 1])
else:
res.append([values[0], 0])
origin_sort_res = [0 for i in range(len(arr))]
for v in res:
# Return the from the sorted array to the original indexing
origin_sort_res[v[0]] = v[1]
print(origin_sort_res)
try this(nlog2n)
def solution(nums):
sortns = []
res = []
for n in reversed(nums):
idx = bisect.bisect_left(sortns, n)
res.append(idx)
sortns.insert(idx,n)
return res[::-1]
print(solution([12, 1, 2, 3, 0, 11, 4]))
# [6, 1, 1, 1, 0, 1, 0]
I am writing code with enumerate() in Python, and I am having issues with referencing the first argument in enumerate:
For example, let nums be temperatures of different days:
nums = [1,5,20,9,3,10,50,7]
array = []
for j, distance in enumerate(nums):
for k, distance2 in enumerate(nums[1:],1):
if nums[j] < nums[k]:
array.append(distance2[j]-distance[k])
So, the challenge I have is: how do I reference the 'distance' and 'distance2' of each element respectively in my enumerations?
The aim of the problem is to determine for each day, how many days you'll have to wait for a warmer day, so for the example above, the output would be [1,1,4,3,1,1,0,0]; where there are no warmer days ahead, return 0.
Thanks
You need to calculate the distance based off the indexes not the values at the index.
You should not restart your subscript and inner index at 1 each time but rather at i each iteration.
nums = [1, 5, 20, 9, 3, 10, 50, 7]
array = []
for i, curr_temp in enumerate(nums):
days = 0
for j, future_temp in enumerate(nums[i:], i):
if curr_temp < future_temp:
# Set Days to Distance between Indexes
days = j - i
# Stop Looking Once Higher Value Found
break
array.append(days)
print(array)
Output:
[1, 1, 4, 2, 1, 1, 0, 0]
I am trying to create a list of integers and then scan it in order to find the minimum absolute value of the substractions of the elements of the list. I have created the list, but there is problem in the code which finds the minimum absolute value, as the result it shows is not correct. I think it is probably in the possitions of the elements of the list during the loops. Can you help me find it?
For example, when I create a list Α = [2, 7, 5, 9, 3, 1, 2], the result of min should be 0, but it is 1.
Here is my code:
min=1000
for i in range (1, N-1):
for j in range (i+1, N):
if (abs (A [i-1] - A [j-1])<min):
min = abs (A [i-1] - A [j-1])
print ("%d" %min)
You can do it like this:
A = [2, 7, 5, 9, 3, 1, 2]
temp = sorted(A)
min_diff = min([abs(i - j) for i, j in zip(temp [:-1], temp [1:])])
print(min_diff) # -> 0
Sorting makes sure that the element pair (i, j) which produce the overall smallest difference would be a pair of consecutive elements. That makes the
number of checks you have to perform much less than the brute force approach of all possible combinations.
Something a bit more clever that short-circuits:
A = [2, 7, 5, 9, 3, 1, 2]
def find_min_diff(my_list):
if len(set(my_list)) != len(my_list): # See note 1
return 0
else:
temp = sorted(my_list)
my_min = float('inf')
for i, j in zip(temp [:-1], temp [1:]):
diff = abs(i - j)
if diff < my_min:
my_min = diff
return my_min
print(find_min_diff(A)) # -> 0
Notes:
1: Converting to set removes the duplicates so if the corresponding set has less elements than the original list it means that there is at least one duplicate value. But that necessarily means that the min absolute difference is 0 and we do not have to look any further.
I would be willing to bet that this is the fastest approach for all lists that would return 0.
You should not be subtracting 1 from j in the inner loop as you end up skipping the comparison of the last 2. It is better to make the adjustments in the loop ranges, rather than subtracting 1 (or not) in the loop code:
A = [2, 7, 5, 9, 3, 1, 2]
N = 7
mint = 1000
for i in range (0, N-1):
for j in range (i+1, N):
if (abs(A[i] - A[j]) < mint):
mint = abs(A[i] - A[j])
print(i, j)
print(mint)
print(mint) # 0
I have also avoided the use of a built-in function name min.
To avoid the arbitrary, magic, number 1000, you can perform an initial check against None:
A = [2, 7, 5, 9, 3, 1, 2]
N = 7
mint = None
for i in range (0, N-1):
for j in range (i+1, N):
if mint is None:
mint = abs(A[i] - A[j])
elif (abs(A[i] - A[j]) < mint):
mint = abs(A[i] - A[j])
print(i, j)
print(mint)
print(mint) # 0
This is a brute-force solution:
from itertools import combinations
A = [2, 7, 5, 9, 3, 1, 2]
min(abs(i-j) for i, j in combinations(A, 2)) # 0
using numpy
import numpy as np
A = [2, 7, 5, 9, 3, 1, 2]
v = np.abs(np.diff(np.sort(np.array(A))))
np.min(v)
out : 0
Or You can use numpy only for the diff part like this :
v = min(abs(np.diff(sorted(A))))
This is what you are looking for:
A = [2, 7, 5, 9, 3, 1, 2]
diffs = []
for index1, i in enumerate(A):
for index2, j in enumerate(A):
if index1 != index2:
diffs.append(abs(i-j))
print(min(diffs))
Output:
0
Updated to exclude subtraction of same items
I am searching for a clean and pythonic way of checking if the contents of a list are greater than a given number (first threshold) for a certain number of times (second threshold). If both statements are true, I want to return the index of the first value which exceeds the given threshold.
Example:
# Set first and second threshold
thr1 = 4
thr2 = 5
# Example 1: Both thresholds exceeded, looking for index (3)
list1 = [1, 1, 1, 5, 1, 6, 7, 3, 6, 8]
# Example 2: Only threshold 1 is exceeded, no index return needed
list2 = [1, 1, 6, 1, 1, 1, 2, 1, 1, 1]
I don't know if it's considered pythonic to abuse the fact that booleans are ints but I like doing like this
def check(l, thr1, thr2):
c = [n > thr1 for n in l]
if sum(c) >= thr2:
return c.index(1)
Try this:
def check_list(testlist)
overages = [x for x in testlist if x > thr1]
if len(overages) >= thr2:
return testlist.index(overages[0])
# This return is not needed. Removing it will not change
# the outcome of the function.
return None
This uses the fact that you can use if statements in list comprehensions to ignore non-important values.
As mentioned by Chris_Rands in the comments, the return None is unnecessary. Removing it will not change the result of the function.
If you are looking for a one-liner (or almost)
a = filter(lambda z: z is not None, map(lambda (i, elem) : i if elem>=thr1 else None, enumerate(list1)))
print a[0] if len(a) >= thr2 else false
A naive and straightforward approach would be to iterate over the list counting the number of items greater than the first threshold and returning the index of the first match if the count exceeds the second threshold:
def answer(l, thr1, thr2):
count = 0
first_index = None
for index, item in enumerate(l):
if item > thr1:
count += 1
if not first_index:
first_index = index
if count >= thr2: # TODO: check if ">" is required instead
return first_index
thr1 = 4
thr2 = 5
list1 = [1, 1, 1, 5, 1, 6, 7, 3, 6, 8]
list2 = [1, 1, 6, 1, 1, 1, 2, 1, 1, 1]
print(answer(list1, thr1, thr2)) # prints 3
print(answer(list2, thr1, thr2)) # prints None
This is probably not quite pythonic though, but this solution has couple of advantages - we keep the index of the first match only and have an early exit out of the loop if we hit the second threshold.
In other words, we have O(k) in the best case and O(n) in the worst case, where k is the number of items before reaching the second threshold; n is the total number of items in the input list.
I don't know if I'd call it clean or pythonic, but this should work
def get_index(list1, thr1, thr2):
cnt = 0
first_element = 0
for i in list1:
if i > thr1:
cnt += 1
if first_element == 0:
first_element = i
if cnt > thr2:
return list1.index(first_element)
else:
return "criteria not met"
thr1 = 4
thr2 = 5
list1 = [1, 1, 1, 5, 1, 6, 7, 3, 6, 8]
list2 = [1, 1, 6, 1, 1, 1, 2, 1, 1, 1]
def func(lst)
res = [ i for i,j in enumerate(lst) if j > thr1]
return len(res)>=thr2 and res[0]
Output:
func(list1)
3
func(list2)
false
I have a list of lists and each list has a repeating sequence. I'm trying to count the length of repeated sequence of integers in the list:
list_a = [111,0,3,1,111,0,3,1,111,0,3,1]
list_b = [67,4,67,4,67,4,67,4,2,9,0]
list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]
Which would return:
list_a count = 4 (for [111,0,3,1])
list_b count = 2 (for [67,4])
list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
Any advice or tips would be welcome. I'm trying to work it out with re.compile right now but, its not quite right.
Guess the sequence length by iterating through guesses between 2 and half the sequence length. If no pattern is discovered, return 1 by default.
def guess_seq_len(seq):
guess = 1
max_len = len(seq) / 2
for x in range(2, max_len):
if seq[0:x] == seq[x:2*x] :
return x
return guess
list_a = [111,0,3,1,111,0,3,1,111,0,3,1]
list_b = [67,4,67,4,67,4,67,4,2,9,0]
list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]
print guess_seq_len(list_a)
print guess_seq_len(list_b)
print guess_seq_len(list_c)
print guess_seq_len(range(500)) # test of no repetition
This gives (as expected):
4
2
10
1
As requested, this alternative gives longest repeated sequence. Hence it will return 4 for list_b. The only change is guess = x instead of return x
def guess_seq_len(seq):
guess = 1
max_len = len(seq) / 2
for x in range(2, max_len):
if seq[0:x] == seq[x:2*x] :
guess = x
return guess
I took Maria's faster and more stackoverflow-compliant answer and made it find the largest sequence first:
def guess_seq_len(seq, verbose=False):
seq_len = 1
initial_item = seq[0]
butfirst_items = seq[1:]
if initial_item in butfirst_items:
first_match_idx = butfirst_items.index(initial_item)
if verbose:
print(f'"{initial_item}" was found at index 0 and index {first_match_idx}')
max_seq_len = min(len(seq) - first_match_idx, first_match_idx)
for seq_len in range(max_seq_len, 0, -1):
if seq[:seq_len] == seq[first_match_idx:first_match_idx+seq_len]:
if verbose:
print(f'A sequence length of {seq_len} was found at index {first_match_idx}')
break
return seq_len
This worked for me.
def repeated(L):
'''Reduce the input list to a list of all repeated integers in the list.'''
return [item for item in list(set(L)) if L.count(item) > 1]
def print_result(L, name):
'''Print the output for one list.'''
output = repeated(L)
print '%s count = %i (for %s)' % (name, len(output), output)
list_a = [111, 0, 3, 1, 111, 0, 3, 1, 111, 0, 3, 1]
list_b = [67, 4, 67, 4, 67, 4, 67, 4, 2, 9, 0]
list_c = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 0, 23, 18, 10
]
print_result(list_a, 'list_a')
print_result(list_b, 'list_b')
print_result(list_c, 'list_c')
Python's set() function will transform a list to a set, a datatype that can only contain one of any given value, much like a set in algebra. I converted the input list to a set, and then back to a list, reducing the list to only its unique values. I then tested the original list for each of these values to see if it contained that value more than once. I returned a list of all of the duplicates. The rest of the code is just for demonstration purposes, to show that it works.
Edit: Syntax highlighting didn't like the apostrophe in my docstring.