Given an array of scores sorted in increasing order, return true if the array contains 3 adjacent scores that differ from each other by at most 2, such as with {3, 4, 5} or {3, 5, 5}.
Examples
scoresClump([3, 4, 5]) → true
scoresClump([3, 4, 6]) → false
scoresClump([1, 3, 5, 5]) → true
A solution below here seems to work but Translating it into Python looks tricky.
function scoresClump(scores) {
for (let i = 0; i < scores.length - 1; i++) {
if (scores[i + 2] - scores[i] <= 2) {
return true;
}
}
return false;
}
I have tried this in Python and it keeps going out of range or giving the wrong output.
arr=[1,3, 5, 5]
i=0
while i<(len(arr)-1):
if (arr[i+2]-arr[i])<=2 and (arr[i+1]-arr[i])<=2:
print("True")
i=i+1
else:
print("False")
break
You're iterating until i < len(arr)-1, but you're reaching for arr[i+2], which is out of range.
In Python you usually do not need to use an index variable. As you've seen they're a source of errors, and Python offers cleaner syntax without using them. For instance:
# unpythonic
for i in range(len(scores)):
print(scores[i])
# pythonic
for score in scores:
print(score)
zip combines two (or more) things you can iterate over.
scores[2:] means "the scores list, but discarding the first two values".
scores = [1, 2, 3, 4, 5, 6]
for a, b in zip(scores, scores[2:]):
print(a, b)
# 1 3
# 2 4
# 3 6
# zip then ends because it reached the end of scores[2:]
So, you can use zip and list slicing to compare the list with itself without index variables:
def scores_clump(scores):
for a, b in zip(scores, scores[2:]):
if b - a <= 2:
return True
return False
scores_clump([1, 3, 4, 5])
# 4 - 1 is not <= 2
# 5 - 3 is <= 2, return True
scores_clump([1, 3, 6, 7, 9])
# 6 - 1 is not <= 2
# 7 - 3 is not <= 2
# 9 - 6 is not <= 2
# reached end of loop with no match, return False
scores_clump([3, 3, 7, 7, 9])
# 7 - 3 is not <= 2
# 7 - 3 is not <= 2
# 9 - 7 is <= 2, return True
Taking a leaf from Max's answer, you can reduce it further using any:
def scores_clump(scores):
return any(b - a <= 2 for a, b in zip(scores, scores[2:]))
You can use this following function -
def scoresClump(nums):
for x in range(2, len(nums)):
if nums[x] - nums[x-2] <= 2:
return True
return False
if you want a one-liner using any() -
def scoresClump(nums):
return any(nums[x] - nums[x-2] <= 2 for x in range(2, len(nums)))
>>> scoresClump([3, 4, 5])
True
>>> scoresClump([3, 4, 6])
False
>>> scoresClump([3, 4, 5, 5])
True
>>> scoresClump([3, 4])
False
>>> scoresClump([3])
False
>>> scoresClump([3, 3, 7, 7, 9])
True
Your if statement will reach arr[:-1] and then try and check two elements ahead of that, which don't exist, therefore going out of range. Rather than a while loop I would try something like this:
for x in range(0, len(arr)-2)
This is basically a "sliding window" problem where window size=3 and we keep iterating over the array until we find a window where difference between adjacent elements is less than or equal to 2.
Here we can simply check if difference between last and first element of the window is <=2 or not because we are given a sorted array.
def scoresClump(array):
for i in range(2,len(array)):
if array[i]-array[i-2]<=2:
return True
return False
print(scoresClump([1, 3, 5, 5]))
Related
I'd like to sum the first element and last elements of a list, and then exclude those two numbers and repeat that process again until there is only one element in the list. Like this:
[5,4,3,2,1,6]
[11,5,5]
[16,5]
[21]
I used some methods but didn't work.
I am just a computer science student starting to python so help me out please guys.
Thank you.
Main logic of this answer is revolve around len of last list print. Lets break it in few points :
LOGIC :
1. Basically we need sum of first-ith and last-ith value for that we used this code:
l_u[-1][i] + l_u[-1][-i - 1]
2. Above point is only valid when lenght of last append list is even for odd-length we have to append this only at even poistion :
l_u[-1][i]
3. Among above two statement which is going to true this is done by this condition:
len(l_u[-1])%2 != 0 and i%2 != 0
CODE :
l = [5, 4, 3, 2, 1, 6]
l_u = [l]
condn = True
j = 0
while condn:
l_u.append([
l_u[-1][i] if len(l_u[-1]) % 2 != 0 and i % 2 != 0 else l_u[-1][i] +
l_u[-1][-i - 1] for i in range(
len(l_u[-1]) // 2 if len(l_u[-1]) % 2 == 0 else len(l_u[-1]) // 2 +
1)
])
if len(l_u[-1]) <= 1:
break
print(l_u)
OUTPUT :
[[5, 4, 3, 2, 1, 6], [11, 5, 5], [16, 5], [21]]
I'm trying to write a python code that allows me to iteratively sum up the average values of three elements of a list, starting with the third element and its two predecessors. Let me give you an example:
list = [1, 2, 3, 4, 5, 6, 7]
I want to calculate the following:
sum_of_average_values = sum(1, 2, 3)/3 + sum(2, 3, 4)/3 + sum(3, 4, 5)/3 + sum(4, 5, 6)/3 + sum(5, 6, 7)/3
Since I'm quite new to programming I couldn't find an effective way of putting this into a function.
You can do in this way:
a = [1,2,3,4,5,6,7]
sum_of_average_values = 0
for i in range(0,len(a)-2):
sum_of_average_values += sum(a[i:i+2])/3
print(sum_of_average_values)
You could use rolling from pandas.
import pandas as pd
num_list = [1, 2, 3, 4, 5, 6, 7]
average_sum = sum(pd.Series(num_list).rolling(3).mean().dropna())
print(average_sum)
Many ways to achieve this, one way is recursively.
The function averages the last three elements of a list and adds the result to the result generated by the function with a list lacking the last element. Continues like this until the list is shorter than 3.
def fn(l):
if len(l) < 3:
return 0
return sum(l[-3:])/3 + fn(l[:-1])
print(fn([1, 2, 3, 4, 5, 6, 7]))
Another solution where you can specify the amount of elements you want to sum up and average:
l = [1, 2, 3, 4, 5, 6, 7]
def sum_avg(l, n):
res = 0
for i in range(n-1, len(l)):
res += sum([l[j] for j in range(i, i-n, -1)])/n
return res
print(sum_avg(l, 3))
--> 20.0
Mathematically, this would could be obtain by averaging the sums of 3 sublists:
L = [1, 2, 3, 4, 5, 6, 7]
r = (sum(L) + sum(L[1:-1]) + sum(L[2:-2]))/3 # 20.0
and can be generalized to a window size of w:
w = 3
r = sum(sum(L[p:-p or None]) for p in range(w)) / w
It can also be implemented without the overhead of generating sublists by using item positions to determine the number of times they are added to the total:
r = sum(n*min(i+1,len(L)-i,w) for i,n in enumerate(L)) / w
This would be the most memory-efficient of the 3 methods because it use an iterator to feed data to the sum function and only goes through the data once.
Detailed explanation:
Since all the averages that are added together are a division by 3, we can produce the total sum and divide by 3 at the end
the number at the first and last positions are added once
the number at the second and penultimate positions are added twice
The numbers from the third position up to the antepenultimate will be added 3 times
visually:
(1 + 2 + 3) / 3
(2 + 3 + 4) / 3
(3 + 4 + 5) / 3
(4 + 5 + 6) / 3
(5 + 6 + 7) / 3
(1x1 + 2x2 + 3x3 + 4x3 + 5x3 + 6x2 + 7x1) / 3 = 20.0
n = 1 2 3 4 5 6 7 # value
* = 1 2 3 3 3 2 1 # multiplier (times added)
-------------------------
(2, 4, 9, 12, 15, 12, 7) / 3 = 20.0
i = 0 1 2 3 4 5 6 # index
1 2 3 3 3 2 1 # min(i+1,len(L)-i,w) = multiplier
You can do in one line using list comprehension as:
n = 3
avg = sum( [ sum(lst[i:i+n])/n for i in range(0, len(lst) - (n - 1)) ] )
print(avg) # 20.0
I am total newbie in python who is practising right now with little 'algorithms'.
So here is my exercise:
N-number integers are given (user have to input). The task is to find out if this sequence is one in which the same numbers are in pairs, but there is one other number between the same numbers.
For example, for a sequence of 11 numbers 3 3 5 10 10 1 12 12 3 6 6, the answer is "yes" and for the sequence 2 2 3 15 15 4 4 8 4 4 1 the answer is "no".
Here's what I tried. But this gypsy-code is not working well:
n = int(input())
right_sequence = True
for i in range(n):
current = int(input())
if i > 0:
if current == previous:
if previous != current:
right_sequence = True
else:
right_sequence = False
previous = current
if right_sequence == True:
print('Yes')
else:
print('No')
I tried to use your own code as much as possible.
Basically the number of inputs should be at least 5. (The shortest correct answer would be in this format : A A B A A which has 5 input.
If we replace the i's with their remainder to 3. (i.e i % 3) Then the indexes for 8 input values would be:
0 1 2 0 1 2 0 1 ...
For which a correct answer would look like bellow:
A A B A A B A A ...
A correct list (The one that outputs "Yes") is the one that:
all the 0 indexes are different from their previous value (Except the first 0 which deosn't have previous value)
all the 1 indexes are equal to their previous value
all the 2 indexes are different from their previous value
The list ends with a 1 index
These 4 points are summarized into 4 if conditions in the bellow code. (The ones that have the value 'k' which carries the remainder of i'th to 3)
n = int(input())
right_sequence = True
k = 0
if n < 5:
right_sequence = False
for i in range(n):
current = int(input())
if i > 0:
k = i % 3
if k == 0:
if current == previous:
right_sequence = False # Print (No)
if k == 1:
if current != previous:
right_sequence = False # Print (No)
if k == 2:
if current == previous:
right_sequence = False # Print (No)
previous = current
if k != 1:
print('No')
elif right_sequence == True:
print('Yes')
elif right_sequence == False:
print('No')
You could slices and zip:
def f(l):
all(a == b != c for a, b, c in zip(x[::3], x[1::3], x[2::3]))
f([3, 3, 5, 10, 10, 1, 12, 12, 3, 6, 6])
# True
f([2, 2, 3, 15, 15, 4, 4, 8, 4, 4, 1])
# False
This will work only if the sequence starts with a pair and you might have to check special cases at the end, but it should hint in the right direction.
I have solved the issue the following way:
x = [2, 2, 3, 15, 15, 4, 4, 8, 4, 4, 1]
y = [3, 3, 5, 10, 10, 1, 12, 12, 6, 6]
def check_order(x):
for i in range(len(x)):
only_equal_in_row = True # all previous checked j index elements were equal to i
for j in range(i+1, len(x)):
if x[i] == x[j]:
if only_equal_in_row is False: # check if there was j not equal to i elements before
return False
else:
only_equal_in_row = False # found j element not equal to i
return True
if __name__ == "__main__":
print(check_order(x))
print(check_order(y))
Edit: Without functions due to OP request:
x = [2, 2, 3, 15, 15, 4, 4, 8, 4, 4, 1]
is_right = True
stop = False # need to stop outer for loop
for i in range(len(x)):
if stop:
break
only_equal_in_row = True # all previous checked j index elements were equal to i
for j in range(i+1, len(x)):
if x[i] == x[j]:
if only_equal_in_row is False: # check if there was j not equal to i elements before
is_right = False
stop = True
break
else:
only_equal_in_row = False # found j element not equal to i
print(is_right)
SUMMER OF '69: Return the sum of the numbers in the array, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.
summer_69([1, 3, 5]) --> 9
summer_69([4, 5, 6, 7, 8, 9]) --> 9
summer_69([2, 1, 6, 9, 11]) --> 14
This is the problem. I have been trying to solve this using list slicing but have been unable to. Note: 9 can only be trailing 6, not before 6.
Here’s what my logic is- I found out the index of 6 and assigned it to a variable and I found the variable of 9 and assigned a variable to it too. The other two conditions are satisfied but the condition with 9 doesn’t get satisfied no matter what I try.
Here is some code from my side. Please excuse my bad programming skills.
def summer_69(arr):
if 6 not in arr:
return sum(arr)
elif 6 and 9 in arr:
i = arr.index(6)
y = arr.index(9)
sxy = sum(arr[i:y])
return sum(arr) - sxy
else:
i = arr.index(6)
return sum(arr[:i])
For an array [4, 5, 6, 7, 8, 9] I am getting the output 18.
Done without slicing.
def summer_69(l):
sign, count = False, 0
for num in l:
if num == 6:
sign = True
if not sign:
count += num
if num == 9:
sign = False
return count
my solution is:
def sum67(nums):
add = True
sum1 =0
for i in range(len(nums)):
if add:
if nums[i] == 6:
add = False
else:
sum1 += nums[i]
else:
if nums[i] == 7:
add= True
return sum1
Suppose we need to transform an array of integers and then compute the sum.
The transformation is the following:
For each integer in the array, subtract the first subsequent integer that is equal or less than its value.
For example, the array:
[6, 1, 3, 4, 6, 2]
becomes
[5, 1, 1, 2, 4, 2]
because
6 > 1 so 6 - 1 = 5
nothing <= to 1 so 1 remains 1
3 > 2 so 3 - 2 = 1
4 > 2 so 4 - 2 = 2
6 > 2 so 6 - 2 = 4
nothing <= to 2 so 2 remains 2
so we sum [5, 1, 1, 2, 4, 2] = 15
I already have the answer below but apparently there is a more optimal method. My answer runs in quadratic time complexity (nested for loop) and I can't figure out how to optimize it.
prices = [6, 1, 3, 4, 6, 2]
results = []
counter = 0
num_prices = len(prices)
for each_item in prices:
flag = True
counter += 1
for each_num in range(counter, num_prices):
if each_item >= prices[each_num] and flag == True:
cost = each_item - prices[each_num]
results.append(cost)
flag = False
if flag == True:
results.append(each_item)
print(sum(results))
Can someone figure out how to answer this question faster than quadratic time complexity? I'm pretty sure this can be done only using 1 for loop but I don't know the data structure to use.
EDIT:
I might be mistaken... I just realized I could have added a break statement after flag = False and that would have saved me from a few unnecessary iterations. I took this question on a quiz and half the test cases said there was a more optimal method. They could have been referring to the break statement so maybe there isn't a faster method than using nested for loop
You can use a stack (implemented using a Python list). The algorithm is linear since each element is compared at most twice (one time with the next element, one time with the next number smaller or equals to it).
def adjusted_total(prices):
stack = []
total_substract = i = 0
n = len(prices)
while i < n:
if not stack or stack[-1] < prices[i]:
stack.append(prices[i])
i += 1
else:
stack.pop()
total_substract += prices[i]
return sum(prices) - total_substract
print(adjusted_total([6, 1, 3, 4, 6, 2]))
Output:
15
a simple way to do it with lists, albeit still quadratic..
p = [6, 1, 3, 4, 6, 2]
out= []
for i,val in zip(range(len(p)),p):
try:
out.append(val - p[[x <= val for x in p[i+1:]].index(True)+(i+1)])
except:
out.append(val)
sum(out) # equals 15
NUMPY APPROACH - honestly don't have alot of programming background so I'm not sure if its linear or not (depending on how the conditional masking works in the background) but still interesting
p = np.array([6, 1, 3, 4, 6, 2])
out = np.array([])
for i,val in zip(range(len(p)),p):
pp = p[i+1:]
try:
new = val - pp[pp<=val][0]
out = np.append(out,new)
except:
out = np.append(out,p[i])
out.sum() #equals 15