Why is there a KeyError - python

The following is a LeetCode question:
Given an integer array nums which is sorted in ascending order and all
of its elements are unique and given also an integer k, return the kth
missing number starting from the leftmost number of the array.
I wrote a solution (not the best one), and am getting a KeyError. This is being run on the Leetcode platform. Here is my solution:
class Solution:
def missingElement(self, nums: List[int], k: int) -> int:
missing_dict = {}
c = 0
min_nums = nums[0]
max_nums = nums[len(nums)-1]
for num in range(min_nums, max_nums):
num += 1
if num not in nums:
c += 1
missing_dict[c] = num
return missing_dict[k]
Some examples:
Input: nums = [4,7,9,10], k = 1
Output: 5
Explanation: The first missing number is 5.
Input: nums = [4,7,9,10], k = 3
Output: 8
Explanation: The missing numbers are [5,6,8,...], hence the third missing number is 8.
I get the following error: KeyError: 3. I don't understand why I am getting this error? The last executed input was nums = [1,2,4] and k=3 and the expected value was 6.
Added. Since we know the array is sorted in ascending order, I am looping through the array, adding 1 to each element and checking to see if it is in the array. If it is not, then I set the first missing element to that value (missing_dict[1] = value). If the next element aka value+1 is in the array then k is still 1. Otherwise we increment k by 1 and missing_dict[2] = value+1 etc..
Added I just realized the kth missing number doesn't have to be in [min_nums, max_nums]. That wasn't clear before.
Added
1 <= nums.length <= 5 * 10^4
1 <= nums[i] <= 10^7
nums is sorted in ascending order, and all the elements are unique.
1 <= k <= 10^8
Partial Solution
Here is a partial solution using binary search:
class Solution:
def missingElement(self, nums: List[int], k: int) -> int:
def count_missing(x: int) -> int:
return x-min(nums)-1
def binary_search_recursive(nums, k, start, end):
if start > end:
return -1
mid = (start + end) // 2
if(count_missing(nums[mid]) > 0):
if count_missing(nums[mid]) >= k:
return nums[start]+k
else:
return nums[mid]+(k-count_missing(nums[mid]))
if count_missing(nums[mid]) >= k:
return binary_search_recursive(nums, k, start, mid-1)
else:
return binary_search_recursive(nums, k, mid+1, end)
return binary_search_recursive(nums, k, 0, len(nums)-1)
It fails for nums = [2,3,5,7] and k =1 where the output is
6 when it should be 4.

Cause of the key error:
You are getting the key error because the max limit is set to the maximum element of nums. For the given test case nums = [1, 2, 4], k = 3, the missing element is 6 but the dictionary does not contain any key of 3.
From OP comment,
I just realized the kth missing number doesn't have to be in
[min_nums, max_nums]. That wasn't clear in the question.
Solution:
We can use a dictionary to store the given nums list. Then start checking which numbers are not present in the dictionary from the first number on the list.
from typing import List
class Solution:
def missingElement(self, nums: List[int], k: int) -> int:
data = {}
for i in nums:
data[i] = 1
i = nums[0]
while k != 0:
if i not in data:
k -= 1
i += 1
return i - 1
if __name__ == "__main__":
solution = Solution()
nums = [4, 7, 9, 10]
k = 1
print(solution.missingElement(nums, k))
nums = [4, 7, 9, 10]
k = 3
print(solution.missingElement(nums, k))
nums = [1, 2, 4]
k = 3
print(solution.missingElement(nums, k))
Output:
5
8
6

Related

LCS: Why is my count variable not performing erroneously

LeetCode: longest consecutive sequence
Question:Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.
You must write an algorithm that runs in O(n) time.
Example 1:
Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
Example 2:
Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
nums = [0,3,7,2,5,8,4,6,0,1]
nums = list(set(nums)) # O(n) operation
res = 0
count = 1
if len(nums)==1: # edge case
res = 1
for i in range(len(nums)-1):
if abs(nums[i] - nums[i+1]) == 1:
count+=1
print(count)
else:
res = max(res, count)
count = 1
print(res)```
this prints as follows (print(count)) adds an unneccessary
2
3
4
5
6
7
8
9
0
And when input is nums = [100,4,200,1,3,2]
Output is for print(count):
2
3
3
Count variable is misbehaving
This one should work efficiently enough (for each element,the set is accessed about 3 times so, including the creation of the set, that would make the complexity O(4n), which is still O(n)):
def longest_seq(a: list) -> int :
a = set(a)
max_seq = 0
for i in a:
if i-1 in a:
continue
else:
j= i+1
while j in a:
j += 1
max_seq = max(max_seq, j-i)
return max_seq
You could also do something like this, without using sets. Just create an array of zeros and assign the values of the given array variables as one and calculate the max_seq.
def longest_seq(a: list) -> int :
bit = [0 for i in range(max(a)+2)]
for i in a:
bit[i] = 1
max_seq = count = 1
for i in range(1,len(bit)):
if bit[i] == bit[i-1] == 1:
count+=1
else:
max_seq = max(max_seq, count)
count = 1
return max_seq
print(longest_seq([5,4,7,8,1,2,3,4,9,10,11,12,13])) # ans = 7

Ineffecient algorithm of finding the sum of even numbers after queries

I decided to complete some tasks on Leetcode to improve my algorithm skills.
And I ran into a problem with LeetCode's problem 985. Sum of Even Numbers After Queries
Here is the description of that task:
You are given an integer array nums and an array queries where queries[i] = [valᵢ, indexᵢ].
For each query i, first, apply nums[indexᵢ] = nums[indexᵢ] + valᵢ, then print the sum of the even values of nums.
Return an integer array answer where answer[i] is the answer to the ith query.
Some samples of input and output:
# input1: nums = [1,2,3,4], queries = [[1,0],[-3,1],[-4,0],[2,3]]
# output1: [8, 6, 2, 4]
# input2: nums = [1], queries = [[4,0]]
# output2: [0]
So I found the solution, but as it has some huge samples of inputs, I found that my code is not efficient enough.
Here is my code:
class Solution:
def sumEvenAfterQueries(self, nums: list[int], queries: list[list[int]]) -> list[int]:
ans = []
integer_ans = 0
for i in range(len(queries)):
nums[queries[i][1]] = nums[queries[i][1]] + queries[i][0]
for j in nums:
if j % 2 == 0:
integer_ans += j
ans.append(integer_ans)
integer_ans = 0
return ans
So it does not solve problem because of the Time limit exceeded.
How can I improve my code to make it more efficient?
Try this solution. This will initially build up even_nums which are sum of even numbers in list, then incrementally update it with each value in queries.
It's probably not the most efficient, but it works for me. I submit on leetcode just now.
class Solution:
def sumEvenAfterQueries(self, nums: List[int], queries: List[List[int]]) -> List[int]:
even_sum = sum(x for x in nums if not x % 2)
result = []
for (add, i) in queries:
n = nums[i]
if add % 2: # odd
if n % 2: # both odd, result is even
even_sum += n + add
else: # even, add odd, result is odd
even_sum -= n
# odd, add even, result is still odd
# so, both must be even
elif not n % 2: # both even
even_sum += add
# remember updating nums at index #i
# and then adding to ours result
nums[i] = n + add
result.append(even_sum)
return result
Not so optimised solution, but you need to keep update of the sum of even values first and then for every query you run, you need to make the changes for the index of that value and see if sum for that index is calcualed or not. if not then add it to total sum and update the nums and if it is calculate then add the new sum value to it and modify the nums accordingly.
below is a simple way to achive this.
class Solution:
def sumEvenAfterQueries(self, nums: List[int], queries: List[List[int]]) -> List[int]:
dic = {i:v for i, v in enumerate(nums) if v%2==0}
sum_ = sum(dic.values())
res = []
for v, i in queries:
val = nums[i]
new_val = nums[i] + v
if i not in dic:
if new_val%2==0:
dic[i] = new_val
sum_ += new_val
res.append(sum_)
else:
res.append(sum_)
else:
if new_val%2==0:
sum_ -= val
sum_ += new_val
dic[i] = new_val
res.append(sum_)
else:
sum_-= val
del dic[i]
res.append(sum_)
nums[i] = new_val
return res
This is an addition to rv.kvetch answer
Your code is giving TLE because it has the worst case time complexity of O(n2). I hope you know about the it.
Coming to the solution, we can do in in O(n) i.e. linear time.
Algorithm
Initially we will store sum of all even numbers present in nums to all_sum
Adding value to any item of nums list can make nums[index] + value even or odd, we will check these conditions
Based on these conditions checks, we either add (value or nums[index] + value) or subtract nums[index] from all_sum
After all these condition checks we will modify nums[index] to be nums[index] = nums[index] + value and add all_sum to the array that we want to return as answer
Code
def sumEvenAfterQueries(self, nums: List[int], queries: List[List[int]]) -> List[int]:
all_sum = 0
for e in nums:
if e%2 == 0:
all_sum += e
sum_arr = []
for val, index in queries:
if nums[index] % 2 == 0: # nums item is already added to all_sum
if (nums[index] + val) % 2 == 0:
all_sum += val
else:
all_sum -= nums[index]
else: # nums item is odd so it wasn't added to all_sum before
if (nums[index] + val) % 2 == 0:
all_sum += (nums[index] + val)
else:
pass
nums[index] += val
sum_arr.append(all_sum)
return sum_arr

Given an array of N integers, and an integer K, find the number of pairs of elements in the array whose sum is equal to K

Problem Statement:- Given an array of N integers, and an integer K, find the number of pairs of elements in the array whose sum is equal to K.
**def countpairs(x,length,sum):
count = 0
for i in range(0,length):
for j in range(i+1,length):
print(x[i],x[j])
if(x[i]+x[j]==sum):
count+=1
print(count)
x = [1, 1, 1, 1]
sum = 2
length=len(x)
countpairs(x,length,sum)
Output:= 6**
This is My solution used in VS code.
My Question:- whenever I am running the same code in gfg it is not accepting the code giving me this error. I even have tried the same code in the online compiler there also it is running correctly.
This Is the gfg code which i have written
class Solution:
def getPairsCount(self, arr, K, N):
count = 0
for i in range(0,N):
for j in range(i+1,N):
if(arr[i]+arr[j]==K):
count+=1
return count
#Initial Template for Python 3
if __name__ == '__main__':
tc = int(input())
while tc > 0:
n, k = list(map(int, input().strip().split()))
arr = list(map(int, input().strip().split()))
ob = Solution()
ans = ob.getPairsCount(arr, n, k)
print(ans)
tc -= 1
Error
if(arr[i]+arr[j]==K):
IndexError: list index out of range
There's no added value in using a class for this. You just need:-
def getPairsCount(arr, K):
count = 0
for i in range(len(arr)-1):
if arr[i] + arr[i+1] == K:
count += 1
return count
EDIT:
Previous answer assumed that only adjacent elements were to be considered. If that's not the case then try this:-
import itertools
def getPairsCount(arr, K):
count = 0
for c in itertools.combinations(sorted(arr), 2):
if c[0] + c[1] == K:
count += 1
return count
data = [1, 2, 1, 4, -1]
print(getPairsCount(data, 3))
We do not need two loops for this question. Here is something that runs in O(n):
def countpairs(list_,K):
count = 0
set_ = set(list_)
pairs_ = []
for val in list_:
if K - val in set_:
# we ensure that pairs are unordered by using min and max
pairs_.append ( (min(val, K-val), max(val, K-val)) )
count+=1
set_pairs = set(pairs_)
print ("Pairs which sum up to ",K," are: ", set_pairs)
return len(set_pairs)
x = [1,4,5,8,2,0,24,7,6]
sum_ = 13
print ("Total count of pairs summming up to ", sum_, " = ", countpairs(x, sum_))
Output:
Pairs which sum up to 13 are: {(6, 7), (5, 8)}
Total count of pairs summming up to 13 = 2
The idea is that if two values should sum to a value K, we can iterate through the array and check if there is another element in the array which when paired with the current element, sums up to K. The inner loop in your solution can be replaced with a search using the in. Now, we need this search to be fast (O(1) per element), so we create a set out of our input array (set_ in my example).
def solve(a,K):
freq = {}
for v in a:
if v in freq:
freq[v] += 1
else:
freq[v] = 1
for i in range(len(set(a))):
res += freq[a[i]] * freq[K - a[i]]
return res
a = [int(v) for v in input().split()]
K = int(input())
print(solve(a,K))
# Time Complexity : O(N)
# Space Complexity : O(1)
def solve(a,K):
freq = {}
for v in a:
if v in freq:
freq[v] += 1
else:
freq[v] = 1
for i in range(len(set(a))):
res += freq[a[i]] * freq[K - a[i]]
return res
a = [int(v) for v in input().split()]
K = int(input())
print(solve(a,K))

Find n integers in list that after multiplying equal to m

I need to print out n indexes of elements of list that after multiplying equal to some given integer. It's guaranteed that the combination exists in a list. For example, for the following input(number of elements in array, multiplication wanted number, number of elements in wanted sublist and given array):
7 60 4
30 1 1 3 10 6 4
I should get in any order
1 2 4 5
Because 1*1*10*6==60. If there are more than 1 solution I need to print any of them.
My solution works but pretty slow, how can I make it work faster?
from itertools import chain, combinations
arr = list(map(int, input().split()))
numbers = list(map(int, input().split()))
s = sorted(numbers)
def filtered_sublists(input_list, length):
return (
l for l in all_sublists(input_list)
if len(l) == length
)
def all_sublists(l):
return chain(*(combinations(l, i) for i in range(len(l) + 1)))
def multiply(arr):
result = 1
for x in arr:
result = result * x
return result
def get_indexes(data):
indexes = []
for i in range(len(data)):
if arr[1] == multiply(data[i]):
for el in data[i]:
if numbers.index(el) in indexes:
all_ind = [i for i, x in enumerate(numbers) if x == el]
for ind in all_ind:
if ind not in indexes:
indexes.append(ind)
break
else:
indexes.append(numbers.index(el))
break
return indexes
sublists = list(filtered_sublists(numbers, arr[2]))
print(*get_indexes(sublists))
The key is don't test every combination.
def combo(l, n=4, target=60, current_indices=[], current_mul=1):
if current_mul > target and target > 0:
return
elif len(current_indices) == n and current_mul == target:
yield current_indices
return
for i, val in enumerate(l):
if (not current_indices) or (i > current_indices[-1] and val * current_mul <= target):
yield from combo(l, n, target, current_indices + [i], val * current_mul)
l = [30,1,1,3,10,6,4]
for indices in combo(l, n=4, target=60):
print(*indices)
Prints:
1 2 4 5
More testcases:
l = [1,1,1,2,3,3,9]
for c, indices in combo(l, n=4, target=9):
print(*indices)
Prints:
0 1 2 6
0 1 4 5
0 2 4 5
1 2 4 5
We can use a memoized recursion for an O(n * k * num_factors), solution, where num_factors depends on how many factors of the target product we can create. The recurrence should be fairly clear from the code. (Zeros aren't handled but those should be pretty simple to add extra handling for.)
Pythonesque JavaScript code:
function f(A, prod, k, i=0, map={}){
if (i == A.length || k == 0)
return []
if (map[[prod, k]])
return map[[prod, k]]
if (prod == A[i] && k == 1)
return [i]
if (prod % A[i] == 0){
const factors = f(A, prod / A[i], k - 1, i + 1, map)
if (factors.length){
map[[prod, k]] = [i].concat(factors)
return map[[prod, k]]
}
}
return f(A, prod, k, i + 1, map)
}
var A = [30, 1, 1, 3, 10, 6, 4]
console.log(JSON.stringify(f(A, 60, 4)))
console.log(JSON.stringify(f(A, 60, 3)))
console.log(JSON.stringify(f(A, 60, 1)))
You could start from the target product and recursively divide by factors in the remaining list until you get down to 1 and after using the specified number of factors. This has the advantage of quickly eliminating whole branches of recursion under numbers that are not a factor of the target product.
Handling zero values in the list and a target product of zero requires a couple of special conditions at the start and while traversing factors.
For example:
def findFactors(product, count, factors, offset=0):
if product == 0: return sorted((factors.index(0)+i)%len(factors) for i in range(count))
if not count: return [] if product == 1 else None
if not factors: return None
for i,factor in enumerate(factors,1):
if factor == 0 or product%factor != 0: continue
subProd = findFactors(product//factor,count-1,factors[i:],i+offset)
if subProd is not None: return [i+offset-1]+subProd
r = findFactors(60, 4, [30,1,1,3,10,6,4])
print(r) # [1, 2, 4, 5]
r = findFactors(60, 4, [30,1,1,0,3,10,6,4])
print(r) # [1, 2, 5, 6]
r = findFactors(0, 4, [30,1,1,3,10,6,0,4])
print(r) # [0, 1, 6, 7]

Python given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A in O(n) time complexity

For example:
input: A = [ 6 4 3 -5 0 2 -7 1 ]
output: 5
Since 5 is the smallest positive integer that does not occur in the array.
I have written two solutions to that problem. The first one is good but I don't want to use any external libraries + its O(n)*log(n) complexity. The second solution "In which I need your help to optimize it" gives an error when the input is chaotic sequences length=10005 (with minus).
Solution 1:
from itertools import count, filterfalse
def minpositive(a):
return(next(filterfalse(set(a).__contains__, count(1))))
Solution 2:
def minpositive(a):
count = 0
b = list(set([i for i in a if i>0]))
if min(b, default = 0) > 1 or min(b, default = 0) == 0 :
min_val = 1
else:
min_val = min([b[i-1]+1 for i, x in enumerate(b) if x - b[i - 1] >1], default=b[-1]+1)
return min_val
Note: This was a demo test in codility, solution 1 got 100% and
solution 2 got 77 %.
Error in "solution2" was due to:
Performance tests ->
medium chaotic sequences length=10005 (with minus) got 3 expected
10000
Performance tests -> large chaotic + many -1, 1, 2, 3 (with
minus) got 5 expected 10000
Testing for the presence of a number in a set is fast in Python so you could try something like this:
def minpositive(a):
A = set(a)
ans = 1
while ans in A:
ans += 1
return ans
Fast for large arrays.
def minpositive(arr):
if 1 not in arr: # protection from error if ( max(arr) < 0 )
return 1
else:
maxArr = max(arr) # find max element in 'arr'
c1 = set(range(2, maxArr+2)) # create array from 2 to max
c2 = c1 - set(arr) # find all positive elements outside the array
return min(c2)
I have an easy solution. No need to sort.
def solution(A):
s = set(A)
m = max(A) + 2
for N in range(1, m):
if N not in s:
return N
return 1
Note: It is 100% total score (Correctness & Performance)
def minpositive(A):
"""Given an list A of N integers,
returns the smallest positive integer (greater than 0)
that does not occur in A in O(n) time complexity
Args:
A: list of integers
Returns:
integer: smallest positive integer
e.g:
A = [1,2,3]
smallest_positive_int = 4
"""
len_nrs_list = len(A)
N = set(range(1, len_nrs_list+2))
return min(N-set(A)) #gets the min value using the N integers
This solution passes the performance test with a score of 100%
def solution(A):
n = sorted(i for i in set(A) if i > 0) # Remove duplicates and negative numbers
if not n:
return 1
ln = len(n)
for i in range(1, ln + 1):
if i != n[i - 1]:
return i
return ln + 1
def solution(A):
B = set(sorted(A))
m = 1
for x in B:
if x == m:
m+=1
return m
Continuing on from Niroj Shrestha and najeeb-jebreel, added an initial portion to avoid iteration in case of a complete set. Especially important if the array is very large.
def smallest_positive_int(A):
sorted_A = sorted(A)
last_in_sorted_A = sorted_A[-1]
#check if straight continuous list
if len(sorted_A) == last_in_sorted_A:
return last_in_sorted_A + 1
else:
#incomplete list, iterate to find the smallest missing number
sol=1
for x in sorted_A:
if x == sol:
sol += 1
else:
break
return sol
A = [1,2,7,4,5,6]
print(smallest_positive_int(A))
This question doesn't really need another answer, but there is a solution that has not been proposed yet, that I believe to be faster than what's been presented so far.
As others have pointed out, we know the answer lies in the range [1, len(A)+1], inclusively. We can turn that into a set and take the minimum element in the set difference with A. That's a good O(N) solution since set operations are O(1).
However, we don't need to use a Python set to store [1, len(A)+1], because we're starting with a dense set. We can use an array instead, which will replace set hashing by list indexing and give us another O(N) solution with a lower constant.
def minpositive(a):
# the "set" of possible answer - values_found[i-1] will tell us whether i is in a
values_found = [False] * (len(a)+1)
# note any values in a in the range [1, len(a)+1] as found
for i in a:
if i > 0 and i <= len(a)+1:
values_found[i-1] = True
# extract the smallest value not found
for i, found in enumerate(values_found):
if not found:
return i+1
We know the final for loop always finds a value that was not marked, because it has one more element than a, so at least one of its cells was not set to True.
def check_min(a):
x= max(a)
if x-1 in a:
return x+1
elif x <= 0:
return 1
else:
return x-1
Correct me if i'm wrong but this works for me.
def solution(A):
clone = 1
A.sort()
for itr in range(max(A) + 2):
if itr not in A and itr >= 1:
clone = itr
break
return clone
print(solution([2,1,4,7]))
#returns 3
def solution(A):
n = 1
for i in A:
if n in A:
n = n+1
else:
return n
return n
def not_in_A(a):
a=sorted(a)
if max(a)<1:
return(1)
for i in range(0,len(a)-1):
if a[i+1]-a[i]>1:
out=a[i]+1
if out==0 or out<1:
continue
return(out)
return(max(a)+1)
mark and then find the first one that didn't find
nums = [ 6, 4, 3, -5, 0, 2, -7, 1 ]
def check_min(nums):
marks = [-1] * len(nums)
for idx, num in enumerate(nums):
if num >= 0:
marks[num] = idx
for idx, mark in enumerate(marks):
if mark == -1:
return idx
return idx + 1
I just modified the answer by #najeeb-jebreel and now the function gives an optimal solution.
def solution(A):
sorted_set = set(sorted(A))
sol = 1
for x in sorted_set:
if x == sol:
sol += 1
else:
break
return sol
I reduced the length of set before comparing
a=[1,222,3,4,24,5,6,7,8,9,10,15,2,3,3,11,-1]
#a=[1,2,3,6,3]
def sol(a_array):
a_set=set()
b_set=set()
cnt=1
for i in a_array:
#In order to get the greater performance
#Checking if element is greater than length+1
#then it can't be output( our result in solution)
if i<=len(a) and i >=1:
a_set.add(i) # Adding array element in set
b_set.add(cnt) # Adding iterator in set
cnt=cnt+1
b_set=b_set.difference(a_set)
if((len(b_set)) > 1):
return(min(b_set))
else:
return max(a_set)+1
sol(a)
def solution(A):
nw_A = sorted(set(A))
if all(i < 0 for i in nw_A):
return 1
else:
ans = 1
while ans in nw_A:
ans += 1
if ans not in nw_A:
return ans
For better performance if there is a possibility to import numpy package.
def solution(A):
import numpy as np
nw_A = np.unique(np.array(A))
if np.all((nw_A < 0)):
return 1
else:
ans = 1
while ans in nw_A:
ans += 1
if ans not in nw_A:
return ans
def solution(A):
# write your code in Python 3.6
min_num = float("inf")
set_A = set(A)
# finding the smallest number
for num in set_A:
if num < min_num:
min_num = num
# print(min_num)
#if negative make positive
if min_num < 0 or min_num == 0:
min_num = 1
# print(min_num)
# if in set add 1 until not
while min_num in set_A:
min_num += 1
return min_num
Not sure why this is not 100% in correctness. It is 100% performance
def solution(A):
arr = set(A)
N = set(range(1, 100001))
while N in arr:
N += 1
return min(N - arr)
solution([1, 2, 6, 4])
#returns 3

Categories

Resources