Related
I have attempted google's kickstart 2020 challenge. Round C problem 1 has me stumped for some. I have tried many different ways of completing the challenge. The problem looks easy but I can't complete it. The problem is that I do not understand what I am doing wrong. Please point me in the right direction or point the issue in with my code.
Problem
Google Kickstart 2020 - Round C | Problem 1
https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ff43/00000000003380d2
Avery has an array of N positive integers. The i-th integer of the array is Ai.
A contiguous subarray is an m-countdown if it is of length m and contains the integers m, m-1, m-2, ..., 2, 1 in that order. For example, [3, 2, 1] is a 3-countdown.
Can you help Avery count the number of K-countdowns in her array?
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case begins with a line containing the integers N and K. The second line contains N integers. The i-th integer is Ai.
Output
For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the number of K-countdowns in her array.
Pseudocode
get the number of cases
Loop in range(number of cases):
get the N (number of elements), K(initial countdown value)
get the array of values
generate an array of the countdown sequence [K ... 1] - signature
counter = 0
Loop elem in range(Number of elements):
if elem == K:
if there is space to slice the array (length of signature) - possible signature
if possible signature == signature:
counter += 1
print(counter)
Python 3 Code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
noc = int(input('')) # getting the number of cases # NOC- number of cases
# Loop over the # of cases
for c in range(noc):
(N, K) = [int(i) for i in input('').split(' ')] # getting N, K
# N - number of elements given
# K - initial countdown value
# getting the elements
caseList = [int(i) for i in input('').split(' ')]
# generating a 'signature' or list of factorial for the countdown
steps = [i for i in range(1, K + 1)][::-1]
# counter for number of matches
countdown = 0 # init value
# loop over each element i n list
for i in range(N):
# if element == K(init countdown number)
if caseList[i] == K:
# make sure there is space to get the sliced array
if i <= len(caseList) - len(steps):
# get the next m numbers if
if caseList[i:i + len(steps)] == steps:
countdown += 1 # increment
print countdown # print the number of matches
Your solution seems fine, except that the output isn't as specified and not for Python 3, but 2, simply change it to:
print(f'Case {c}: {countdown}')
Apart from that, you're doing a bit more work than is needed. You really only need to go through the entire list once to count K-countdowns.
For example:
import sys
from io import StringIO
sys.stdin = StringIO('3\n2 2\n2 1\n8 2\n0 2 1 2 2 1 2 1 0\n0 2\n\n')
t = int(input())
for c in range(t):
(n, k) = [int(i) for i in input().split()]
a = [int(i) for i in input().split()]
# initialise goal, position in array and count
goal, i, count = k, 0, 0
while i < n:
# if item in current position matches current goal
if a[i] == goal:
# then next goal item is one less
goal -= 1
# until all in K-countdown were found
if goal == 0:
# then start over and increase count
goal = k
count += 1
# look at the next position
i += 1
# else (current item doesn't match goal), if already looking for start of K-countdown
elif goal == k:
# look at the next position
i += 1
# else (current item doesn't match goal, goal wasn't start of K-countdown)
else:
# look for start of K-countdown
goal = k
print(f'Case #{c}: {count}')
I don't find any issue with your solution. Might be something your output format.
You are supposed to output in the form of Case #x: y, where x is the test case number (starting from 1) and y is the number of K-countdowns in her array.
Example:
Case #1: 2
Case #2: 0
Case #3: 1
Note: Make sure you are using Python 2.x if you are using print x instead of print(x)
I was wondering the same as well.
Lets look at the constraint given:
1 ≤ T ≤ 100. # Testcases
2 ≤ K ≤ N. # Value of K
1 ≤ Ai ≤ 2 × 105, for all i. # Index- i
# Test Set 1
2 ≤ N ≤ 1000.
# Test Set 2
2 ≤ N ≤ 2 × 105 for at most 10 test cases.
For the remaining cases, 2 ≤ N ≤ 1000.
Now suppose we have a testcase
nums = [1]
k = 1
One might think for K=1 the countdown= 1 right ? Actually No.
Read carefully, 2<=N, which means,
Array length must be of minimum length=2.
Expected result,
nums = [1]
K = 1
coutdown = 0
when the constraint already says 2<=N
doesn't it mean that there will be no test case with array length = 0 or 1
There is no issue in #MFK34 except print() requires brackets in python 3 and he prints the answer immediately at end of loop and solution is not as expected. below is my revised solution.
#!/usr/bin/python
# -*- coding: utf-8 -*-
noc = int(input('')) # getting the number of cases # NOC- number of cases
op = []
# Loop over the # of cases
for c in range(noc):
(N, K) = [int(i) for i in input('').split(' ')] # getting N, K
caseList = [int(i) for i in input('').split(' ')]
steps = [i for i in range(1, K + 1)][::-1]
# counter for number of matches
countdown = 0 # init value
# loop over each element i n list
for i in range(N):
# if element == K(init countdown number)
if caseList[i] == K:
# make sure there is space to get the sliced array
if i <= len(caseList) - len(steps):
# get the next m numbers if
if caseList[i:i + len(steps)] == steps:
countdown += 1 # increment
op.append(countdown)
for i,d in enumerate(op):
print("Case #"+str(i+1)+":",d)
I have just stored the results in an array and later printed at end of inputs in order expected.
I found this exercise to study matrices or 2d vectors in Python (I'm beginner)
'''
start row index - k
end row index - m
start column index - l
end column index - n
iterator - i
array or list - a
'''
# Python3 program to print
# given matrix in spiral form
def spiralPrint(m, n, a) :
k = 0; l = 0
''' k - starting row index
m - ending row index
l - starting column index
n - ending column index
i - iterator '''
while (k < m and l < n) :
# Print the first row from
# the remaining rows
for i in range(l, n) :
print(a[k][i], end = " ")
k += 1
# Print the last column from
# the remaining columns
for i in range(k, m) :
print(a[i][n - 1], end = " ")
n -= 1
# Print the last row from
# the remaining rows
if ( k < m) :
for i in range(n - 1, (l - 1), -1) :
print(a[m - 1][i], end = " ")
m -= 1
# Print the first column from
# the remaining columns
if (l < n) :
for i in range(m - 1, k - 1, -1) :
print(a[i][l], end = " ")
l += 1
a =[[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20]]
R = 4
C = 5
spiralPrint(R,C,a)
I wanted to understand the logic behind it, I mean why they were used 4 loops to iterate and why they assigned indices as rows and columns?
Also, how does the function know exactly that at the end of the element it has to go under the second list and go around?
There are four for-loops, one for each side of the spiral.
Each iteration of the while-loop writes out one ring of the matrix. k and m control how much of each side column needs to be printed. k starts at 0 and m at the height of the matrix. Each time a top row is printed, k gets incremented by 1, so the subsequent columns to be printed start one row lower. Each time a bottom row is printed, m gets decremented by 1, so the subsequent columns to be printed stop one row higher.
Similarly, l and n control how much of each row needs to be printed, and get adjusted every time a column is printed.
Everything is easier to follow if you draw the matrix on a sheet of paper and write out k, m, l and n while you mark the parts that are being printed.
The exercise is a good illustration of how ranges work in Python.
I am trying an algorithm for a bubble sort and there is a part I don't understand
nums = [1,4,3,2,10,6,8,5]
for i in range (len(nums)-1,0,-1):
for j in range(i):
if nums[j] > nums[j+1]:
temp = nums[j]
nums[j] = nums[j+1]
nums[j+1] = temp
print(nums)
what does the numbers (-1,0,-1) mean in this part of the code (it dosent sort properly without it) v v v
for i in range (len(nums)-1,0,-1):
Syntax for range in python is -
range(start, end, step)
In your case, the looping is essentially starting from the last element(Index n-1) & moving towards the first element(Index 0) one step at a time.
Okey:
first one is starting point, second tells python where to stop, last one is step.
len(nums) - it gives you (durms..) length of this list, in our case it's 8,
len(nums)-1 - it's 8-1, we are doing this because when going through list python will start on number 0 and end at number 7(still 8 elements, but last one has index 7 not 8),
We will stop at 0, with step -1. So iteration will look like:
num[len(nums)-1] = num[7]
num[len(nums)-1-1] = num[6]
num[len(nums)-1-1-1] = num[5]
.....
num[len(nums)-1-1-1-1-1-1-1] = num[0]
the problem is to find total number of sub-lists from a given list that doesn't contain numbers greater than a specified upper bound number say right and sub lists max number should be greater than a lower bound say left .Suppose my list is: x=[2, 0, 11, 3, 0] and upper bound for sub-list elements is 10 and lower bound is 1 then my sub-lists can be [[2],[2,0],[3],[3,0]] as sub lists are always continuous .My script runs well and produces correct output but needs some optimization
def query(sliced,left,right):
end_index=0
count=0
leng=len(sliced)
for i in range(leng):
stack=[]
end_index=i
while(end_index<leng and sliced[end_index]<=right):
stack.append(sliced[end_index])
if max(stack)>=left:
count+=1
end_index+=1
print (count)
origin=[2,0,11,3,0]
left=1
right=10
query(origin,left,right)
output:4
for a list say x=[2,0,0,1,11,14,3,5] valid sub-lists can be [[2],[2,0],[2,0,0],[2,0,0,1],[0,0,1],[0,1],[1],[3],[5],[3,5]] total being 10
Brute force
Generate every possible sub-list and check if the given criteria hold for each sub-list.
Worst case scenario: For every element e in the array, left < e < right.
Time complexity: O(n^3)
Optimized brute force (OP's code)
For every index in the array, incrementally build a temporary list (not really needed though) which is valid.
Worst case scenario: For every element e in the array, left < e < right.
Time complexity: O(n^2)
A more optimized solution
If the array has n elements, then the number of sub-lists in the array is 1 + 2 + 3 + ... + n = (n * (n + 1)) / 2 = O(n^2). We can use this formula strategically.
First, as #Tim mentioned, we can just consider the sum of the sub-lists that do not contain any numbers greater than right by partitioning the list about those numbers greater than right. This reduces the task to only considering sub-lists that have all elements less than or equal to right then summing the answers.
Next, break apart the reduced sub-list (yes, the sub-list of the sub-list) by partitioning the reduced sub-list about the numbers greater than or equal to left. For each of those sub-lists, compute the number of possible sub-lists of that sub-list of sub-lists (which is k * (k + 1) / 2 if the sub-list has length k). Once that is done for all the the sub-lists of sub-lists, add them together (store them in, say, w) then compute the number of possible sub-lists of that sub-list and subtract w.
Then aggregate your results by sum.
Worst case scenario: For every element e in the array, e < left.
Time Complexity: O(n)
I know this is very difficult to understand, so I have included working code:
def compute(sliced, lo, hi, left):
num_invalid = 0
start = 0
search_for_start = True
for end in range(lo, hi):
if search_for_start and sliced[end] < left:
start = end
search_for_start = False
elif not search_for_start and sliced[end] >= left:
num_invalid += (end - start) * (end - start + 1) // 2
search_for_start = True
if not search_for_start:
num_invalid += (hi - start) * (hi - start + 1) // 2
return ((hi - lo) * (hi - lo + 1)) // 2 - num_invalid
def query(sliced, left, right):
ans = 0
start = 0
search_for_start = True
for end in range(len(sliced)):
if search_for_start and sliced[end] <= right:
start = end
search_for_start = False
elif not search_for_start and sliced[end] > right:
ans += compute(sliced, start, end, left)
search_for_start = True
if not search_for_start:
ans += compute(sliced, start, len(sliced), left)
return ans
Categorise the numbers as small, valid and large (S,V and L) and further index the valid numbers: V_1, V_2, V_3 etc. Let us start off by assuming there are no large numbers.
Consider the list A = [S,S,…,S,V_1, X,X,X,X,…X] .If V_1 has index n, there are n+1, subsets of the form [V_1], [S,V_1], [S,S,V_1] and so on. And for each of these n+1 subsets, we can append the len(A)-n-1 sequences: [X], [XX], [XXX] and so on. Giving a total of (n+1)(len(A)-n) subsets containing V_1.
But we can partition the set of all subsets by those containing V_k but no V_n for n less than k. Hence we must then, simply perform the same calculation on the remaining XXX…X part of the list using V_2 and itterate. This would require something like this:
def query(sliced,left,right,total):
index=0
while index<len(sliced):
if sliced[index]>=left:
total+=(index+1)*(len(sliced)-index)
return total+query(sliced[index+1:],left,right,0)
else:
index+=1
return total
To incorporate the large numbers, we can just partition the whole set according to where the large numbers occur and add the total number of sequence for each. If we call our first function, sub_query, then we arrive at the following:
def sub_query(sliced,left,right,total):
index=0
while index<len(sliced):
if sliced[index]>=left:
total+=(index+1)*(len(sliced)-index)
return total+sub_query(sliced[index+1:],left,right,0)
else:
index+=1
return total
def query(sliced,left,right):
index=0
count=0
while index<len(sliced):
if sliced[index]>right:
count+=sub_query(sliced[:index],left,right,0)
sliced=sliced[index+1:]
index=0
else:
index+=1
count+=sub_query(sliced,left,right,0)
print (count)
This seems to run through the list and check for max/min values fewer times. Note it doesn’t distinguish between sub-lists that are the same but from different positions in the original list (as would arise from a list such as [0,1,0,0,1,0]. But the code from the original post wouldn’t do that either, so I am guessing this is not a requirement.
I was solving a programming puzzle involving combinations. It led me to a wonderful itertools.combinations function and I'd like to know how it works under the hood. Documentation says that the algorithm is roughly equivalent to the following:
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = list(range(r))
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)
I got the idea: we start with the most obvious combination (r first consecutive elements). Then we change one (last) item to get each subsequent combination.
The thing I'm struggling with is a conditional inside for loop.
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
This experession is very terse, and I suspect it's where all the magic happens. Please, give me a hint so I could figure it out.
The loop has two purposes:
Terminating if the last index-list has been reached
Determining the right-most position in the index-list that can be legally increased. This position is then the starting point for resetting all indeces to the right.
Let us say you have an iterable over 5 elements, and want combinations of length 3. What you essentially need for this is to generate lists of indexes. The juicy part of the above algorithm generates the next such index-list from the current one:
# obvious
index-pool: [0,1,2,3,4]
first index-list: [0,1,2]
[0,1,3]
...
[1,3,4]
last index-list: [2,3,4]
i + n - r is the max value for index i in the index-list:
index 0: i + n - r = 0 + 5 - 3 = 2
index 1: i + n - r = 1 + 5 - 3 = 3
index 2: i + n - r = 2 + 5 - 3 = 4
# compare last index-list above
=>
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
break
This loops backwards through the current index-list and stops at the first position that doesn't hold its maximum index-value. If all positions hold their maximum index-value, there is no further index-list, thus return.
In the general case of [0,1,4] one can verify that the next list should be [0,2,3]. The loop stops at position 1, the subsequent code
indices[i] += 1
increments the value for indeces[i] (1 -> 2). Finally
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
resets all positions > i to the smallest legal index-values, each 1 larger than its predecessor.
This for loop does a simple thing: it checks whether the algorithm should terminate.
The algorithm start with the first r items and increases until it reaches the last r items in the iterable, which are [Sn-r+1 ... Sn-1, Sn] (if we let S be the iterable).
Now, the algorithm scans every item in the indices, and make sure they still have where to go - so it verifies the ith indice is not the index n - r + i, which by the previous paragraph is the (we ignore the 1 here because lists are 0-based).
If all of these indices are equal to the last r positions - then it goes into the else, commiting the return and terminating the algorithm.
We could create the same functionality by using
if indices == list(range(n-r, n)): return
but the main reason for this "mess" (using reverse and break) is that the first index from the end that doesn't match is saved inside i and is used for the next level of the algorithm which increments this index and takes care of re-setting the rest.
You could check this by replacing the yields with
print('Combination: {} Indices: {}'.format(tuple(pool[i] for i in indices), indices))
Source code has some additional information about what is going on.
The yeild statement before while loop returns a trivial combination of elements (which is simply first r elements of A, (A[0], ..., A[r-1])) and prepares indices for future work.
Let's say that we have A='ABCDE' and r=3. Then, after the first step the value of indices is [0, 1, 2], which points to ('A', 'B', 'C').
Let's look at the source code of the loop in question:
2160 /* Scan indices right-to-left until finding one that is not
2161 at its maximum (i + n - r). */
2162 for (i=r-1 ; i >= 0 && indices[i] == i+n-r ; i--)
2163 ;
This loop searches for the rightmost element of indices that hasn't reached its maximum value yet. After the very first yield statement the value of indices is [0, 1, 2]. Therefore, for loop terminates at indices[2].
Next, the following code increments the ith element of indices:
2170 /* Increment the current index which we know is not at its
2171 maximum. Then move back to the right setting each index
2172 to its lowest possible value (one higher than the index
2173 to its left -- this maintains the sort order invariant). */
2174 indices[i]++;
As a result, we get index combination [0, 1, 3], which points to ('A', 'B', 'D').
Then we roll back the subsequent indices if they are too big:
2175 for (j=i+1 ; j<r ; j++)
2176 indices[j] = indices[j-1] + 1;
Indices increase step by step:
step indices
(0, 1, 2)
(0, 1, 3)
(0, 1, 4)
(0, 2, 3)
(0, 2, 4)
(0, 3, 4)
(1, 2, 3)
...