Why no index out of range error? - python

lst = [
8,2,22,97,38,15,0,40,0,75,4,5,7,78,52,12,50,77,91,8, #0-19
49,49,99,40,17,81,18,57,60,87,17,40,98,43,69,48,4,56,62,0, #20-39
81,49,31,73,55,79,14,29,93,71,40,67,53,88,30,3,49,13,36,65, #40-59
52,70,95,23,4,60,11,42,69,24,68,56,1,32,56,71,37,2,36,91,
22,31,16,71,51,67,63,89,41,92,36,54,22,40,40,28,66,33,13,80,
24,47,32,60,99,3,45,2,44,75,33,53,78,36,84,20,35,17,12,50,
32,98,81,28,64,23,67,10,26,38,40,67,59,54,70,66,18,38,64,70,
67,26,20,68,2,62,12,20,95,63,94,39,63,8,40,91,66,49,94,21,
24,55,58,5,66,73,99,26,97,17,78,78,96,83,14,88,34,89,63,72,
21,36,23,9,75,0,76,44,20,45,35,14,0,61,33,97,34,31,33,95,
78,17,53,28,22,75,31,67,15,94,3,80,4,62,16,14,9,53,56,92,
16,39,5,42,96,35,31,47,55,58,88,24,0,17,54,24,36,29,85,57,
86,56,0,48,35,71,89,7,5,44,44,37,44,60,21,58,51,54,17,58,
19,80,81,68,5,94,47,69,28,73,92,13,86,52,17,77,4,89,55,40,
4,52,8,83,97,35,99,16,7,97,57,32,16,26,26,79,33,27,98,66,
88,36,68,87,57,62,20,72,3,46,33,67,46,55,12,32,63,93,53,69,
4,42,16,73,38,25,39,11,24,94,72,18,8,46,29,32,40,62,76,36, #320-339
20,69,36,41,72,30,23,88,34,62,99,69,82,67,59,85,74,4,36,16, #340-359
20,73,35,29,78,31,90,1,74,31,49,71,48,86,81,16,23,57,5,54, #360-379
1,70,54,71,83,51,54,69,16,92,33,48,61,43,52,1,89,19,67,48] #380-399
prodsum = 1
def prod(iter):
p = 1
for n in iter:
p *= n
return p
for n in range(0,5000,20): #NOT OUT OF RANGE???
for i in range(0,17):
if prod(lst[n+i:n+i+4]) > prodsum:
prodsum = prod(lst[n+i:n+i+4])
I'm trying to learn/improve my very rudimentary skills in Python so I've been going through Project Euler challenges. The challenge question is more complex but I basically have a 20x20 grid and have the find 4 adjacent numbers with the largest product.
I basically turned the grid into a list (with 400 values) and was gonna scan row indices. I accidentally entered in a large number for my for loop and noticed I didn't get a out of range error. Why is this?

You would get an out-of-range error with plain indexing. Eg, if you had an array of 10 elements, and you asked for my_list[20]. However, with slicing my_array[a: b] you either get elements from a to b-1, or to the end of the list. That's just a design decision of the language.

You don't get a out-of-range as you never directly access your list based on your index (n).
You use lst[n+i:n+i+4] to get a slice of lst ... which just is empty if your indices are out of range so prod(...) is called with [] and returns 1.

Slicing outside the bounds of a sequence doesn't cause an error. If you try to index single item, you'll got an error.

Related

Asymmetric Swaps - minimising max/min difference in list through swaps

Was doing some exercises in CodeChef and came across the Asymmetric Swaps problem:
Problem
Chef has two arrays 𝐴 and 𝐵 of the same size 𝑁.
In one operation, Chef can:
Choose two integers 𝑖 and 𝑗 (1 ≤ 𝑖,𝑗 ≤ 𝑁) and swap the elements 𝐴𝑖 and 𝐵𝑗.
​
Chef came up with a task to find the minimum possible value of (𝐴𝑚𝑎𝑥 − 𝐴𝑚𝑖𝑛) after performing the swap operation any (possibly zero) number of times.
Since Chef is busy, can you help him solve this task?
Note that 𝐴𝑚𝑎𝑥 and 𝐴𝑚𝑖𝑛 denote the maximum and minimum elements of the array 𝐴 respectively.
I have tried the below logic for the solution. But the logic fails for some test cases and I have no access to the failed test cases and where exactly the below code failed to meet the required output.
T = int(input())
for _ in range(T):
arraySize = int(input())
A = list(map(int, input().split()))
B = list(map(int, input().split()))
sortedList = sorted(A+B)
minLower = sortedList[arraySize-1] - sortedList[0] # First half of the sortedList
minUpper = sortedList[(arraySize*2)-1] - sortedList[arraySize] # Second half of the sortedList
print(min(minLower,minUpper))
I saw some submitted answers and didn't get the reason or logic why they are doing so. Can someone guide where am I missing?
The approach to sort the input into one list is the right one. But it is not enough to look at the left and the right half of that sorted list.
It could well be that there is another sublist of length 𝑁 that has its extreme values closer to each other.
Take for instance this input:
A = [1,4,5]
B = [6,11,12]
Then the sorted list is [1,4,5,6,11,12] and [4,5,6] is actually the sublist which minimises the difference between its maximum and minimum value.
So implement a loop where you select the minimum among A[i+N-1] - A[i].

Analyzing dynamic programming solutions to different maximum subarray problems

I was trying out some dynamic programming problems. I came across the following problems:
1. Maximum (consecutive) subset-sum
Finding the maximum sum of any consecutive set of elements in the given input array.
One possible solution is as follows:
def max_subarray_sum(arr):
curr_sum = arr[0]
max_so_far = arr[0]
for num in arr[1:]:
curr_sum = max(num, curr_sum + num)
max_so_far = max(curr_sum, max_so_far)
return max_so_far
2. Maximum non-adjacent elements subset-sum
Given an array of integers, find the subset of non-adjacent elements with the maximum sum. Calculate the sum of that subset. hackerrank link
One possible solution in python is as follows:
def maxSubsetSum(arr):
second_last_max_sum = arr[0]
last_max_sum = max(arr[0], arr[1])
for num in arr[2:]:
curr_max_sum = max(num, last_max_sum, second_last_max_sum + num)
second_last_max_sum = last_max_sum
last_max_sum = curr_max_sum
return last_max_sum
The solution to the first problem involves two max(), while that for the second involves single max(). So, I was guessing if I can somehow build logic with just single max() for the first problem, say by changing arguments to that single max() like for the second problem.
Q1. After considerable pondering, I came to the conclusion that I cannot because of the constraint in the first problem: sub-array need to be formed by consecutive numbers. Am I right with this?
Q2. Also, can I generalize this further, that is, what "kinds" of problems can be solved with just single max() and which kinds of problems require more than one max()? Or in other words, what are the "characteristics" of constraints on subarray that can be solved in single max() and of those that need at least two max()?

Assign values to different index positions as the actual in a loop python

I have the next variables which are List, floats and a numpy array.
dt=list(range(1,12))
c=18
limit=2.75
Energy=np.zeros(len(dt))
I want to assign the value c=18 in the Numpy array Energy. However, there is a condition. The value in the Energy vector can not be greater than limit=2.75, so as c=18 is greater than limit=2.75, it should be cut to 2.5 and assigned in the actual index position of the loop and in the next index positions of the vector Energy until the value 18 is reached. I made this code but it does not really work efficiently.
for i in range(0,1):
if c>limit:
tmp2=c-(limit)
if tmp2>(limit):
tmp3=tmp2-(limit)
if tmp3>limit:
tmp4=tmp3-(limit)
if tmp4>(limit):
tmp5=tmp4-(limit)
if tmp5>(limit):
tmp6=tmp5-(limit)
if tmp6>limit:
tmp7=tmp6-(limit)
if tmp7>(limit):
tmp8=tmp7-(limit)
else:
Energy[i]=limit
Energy[i+1]=limit
Energy[i+2]=limit
Energy[i+3]=limit
Energy[i+4]=limit
Energy[i+5]=limit
Energy[i+6]=tmp7
Do you have an idea of how to make it better? Thank you!
Welcome to stackoverflow!
Your code presently uses a loop where it doesn't need one and doesn't use a loop where it could be used.
Stepping into your code:
for i in range(0,1):
If we change this to:
for i in range(0,1):
print (i)
We will get the result 0 - it only runs once so there is no need to loop it - i isn't referred to in your code so there is no need to loop through it.
You could use a loop to allocate your c to an array but it isn't needed and I'll leave that as an exercise for yourself.
It can be approached in a different, more efficient way.
First of all when you're assigning variables try and make them descriptive and readable - you'll spend a lot more time coming back to code than you do reading it.
I don't know what system you're describing so I've just given generic names:
import numpy as np
length_arrary=12
limit=2.75
value_to_be_assigned=18
energy_result=np.zeros(length_arrary)
Now what we are really asking is two things, how many times does value_to_be_assigned divide into the limit (an integer) and what is the remainder.
Python has two operations for this floor division (//) and modulus which give:
11//5 = 2.0
1%5 = 1.0
So we know the first (value_to_be_assigned//limit elements - 1) of the array need to be equal to the limit and the final element needs to be equal to value_to_be_assigned % limit
Finally Python has an easy way to access elements of a list - we can set the first x elements to be equal to a value with:
array[:x]=value
x just needs to be an integer.
Putting it together we get:
filled_values=int(value_to_be_assigned//limit)
energy_result[:filled_values]=limit
energy_result[filled_values] = value_to_be_assigned % limit
and we can check with
energy_result.sum() # gives us 18

Avoiding an indexing error in Python while looping

Regardless of whether this is the most efficient way to structure this sorting algorithm in Python (it's not), my understandings of indexing requirements/the nature of the built-in 'min' function are failing to account for the following error in the following code:
Error:
builtins.IndexError: list index out of range
Here's the code:
#Create function to sort arrays with numeric entries in increasing order
def selection_sort(arr):
arruns = arr #pool of unsorted array values, initially the same as 'arr'
indmin = 0 #initialize arbitrary value for indmin.
#indmin is the index of the minimum value of the entries in arruns
for i in range(0,len(arr)):
if i > 0: #after the first looping cycle
del arruns[indmin] #remove the entry that has been properly sorted
#from the pool of unsorted values.
while arr[i] != min(arruns):
indmin = arruns.index(min(arruns)) #get index of min value in arruns
arr[i] = arruns[indmin]
#example case
x = [1,0,5,4] #simple array to be sorted
selection_sort(x)
print(x) #The expectation is: [0,1,4,5]
I've looked at a couple other index error examples and have not been able to attribute my problem to anything occurring while entering/exiting my while loop. I thought that my mapping of the sorting process was sound, but my code even fails on the simple array assigned to x above. Please help if able.
arr and arruns are the same lists. You are removing items from the list, decreasing its size, but leaving max value of i variable untouched.
Fix:
arruns = [] + arr
This will create new array for arruns

4-sum algorithm in Python [duplicate]

This question already has answers here:
Quadratic algorithm for 4-SUM
(3 answers)
Closed 9 years ago.
I am trying to find whether a list has 4 elements that sum to 0 (and later find what those elements are). I'm trying to make a solution based off the even k algorithm described at https://cs.stackexchange.com/questions/2973/generalised-3sum-k-sum-problem.
I get this code in Python using combinations from the standard library
def foursum(arr):
seen = {sum(subset) for subset in combinations(arr,2)}
return any(-x in seen for x in seen)
But this fails for input like [-1, 1, 2, 3]. It fails because it matches the sum (-1+1) with itself. I think this problem will get even worse when I want to find the elements because you can separate a set of 4 distinct items into 2 sets of 2 items in 6 ways: {1,4}+{-2,-3}, {1,-2}+{4,-3} etc etc.
How can I make an algorithm that correctly returns all solutions avoiding this problem?
EDIT: I should have added that I want to use as efficient algorithm as possible. O(len(arr)^4) is too slow for my task...
This works.
import itertools
def foursum(arr):
seen = {}
for i in xrange(len(arr)):
for j in xrange(i+1,len(arr)):
if arr[i]+arr[j] in seen: seen[arr[i]+arr[j]].add((i,j))
else: seen[arr[i]+arr[j]] = {(i,j)}
for key in seen:
if -key in seen:
for (i,j) in seen[key]:
for (p,q) in seen[-key]:
if i != p and i != q and j != p and j != q:
return True
return False
EDIT
This can be made more pythonic i think, I don't know enough python.
It is normal for the 4SUM problem to permit input elements to be used multiple times. For instance, given the input (2 3 1 0 -4 -1), valid solutions are (3 1 0 -4) and (0 0 0 0).
The basic algorithm is O(n^2): Use two nested loops, each running over all the items in the input, to form all sums of pairs, storing the sums and their components in some kind of dictionary (hash table, AVL tree). Then scan the pair-sums, reporting any quadruple for which the negative of the pair-sum is also present in the dictionary.
If you insist on not duplicating input elements, you can modify the algorithm slightly. When computing the two nested loops, start the second loop beyond the current index of the first loop, so no input elements are taken twice. Then, when scanning the dictionary, reject any quadruples that include duplicates.
I discuss this problem at my blog, where you will see solutions in multiple languages, including Python.
First note that the problem is O(n^4) in worst case, since the output size might be of O(n^4) (you are looking for finding all solutions, not only the binary problem).
Proof:
Take an example of [-1]*(n/2).extend([1]*(n/2)). you need to "choose" two instances of -1 w/o repeats - (n/2)*(n/2-1)/2 possibilities, and 2 instances of 1 w/o repeats - (n/2)*(n/2-1)/2 possibilities. This totals in (n/2)*(n/2-1)*(n/2)*(n/2-1)/4 which is in Theta(n^4)
Now, that we understood we cannot achieve O(n^2logn) worst case, we can get to the following algorithm (pseudo-code), that should scale closer to O(n^2logn) for "good" cases (few identical sums), and get O(n^4) worst case (as expected).
Pseudo-code:
subsets <- all subsets of size of indices (not values!)
l <- empty list
for each s in subsets:
#appending a triplet of (sum,idx1,idx2):
l.append(( arr[s[0]] + arr[s[1]], s[0],s[1]))
sort l by first element (sum) in each tupple
for each x in l:
binary search l for -x[0] #for the sum
for each element y that satisfies the above:
if x[1] != y[1] and x[2] != y[1] and x[1] != y[2] and x[2] != y[2]:
yield arr[x[1]], arr[x[2]], arr[y[1]], arr[y[2]]
Probably a pythonic way to do the above will be more elegant and readable, but I am not a python expert I am afraid.
EDIT: Ofcourse the algorithm shall be atleast as time complex as per the solution size!
If the number of possible solutions is not 'large' as compared to n, then
A suggested solution in O(N^3):
Find pair-wise sums of all elements and build a NxN matrix of the sums.
For each element in this matrix, build a struct that would have sumValue, row and column as it fields.
Sort all these N^2 struct elements in a 1D array. (in O(N^2 logN) time).
For each element x in this array, conduct a binary search for its partner y such that x + y = 0 (O(logn) per search).
Now if you find a partner y, check if its row or column field matches with the element x. If so, iterate sequentially in both directions until either there is no more such y.
If you find some y's that do not have a common row or column with x, then increment the count (or print the solution).
This iteration can at most take 2N steps because the length of rows and columns is N.
Hence the total order of complexity for this algorithm shall be O(N^2 * N) = O(N^3)

Categories