-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathLesson5_PrefixSumAndTwoPointers.py
180 lines (150 loc) · 6.46 KB
/
Lesson5_PrefixSumAndTwoPointers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
"""RSQ Solution"""
def makeprefixsum(nums):
prefixsum = [0] * (len(nums) + 1)
for i in range(1, len(nums) + 1):
prefixsum[i] = prefixsum[i-1] + nums[i-1]
return prefixsum
print(makeprefixsum([2,3,6,8,9]))
def rsq(prefixsum, l, r):
return prefixsum[r] - prefixsum[l]
print(rsq(makeprefixsum([2,3,6,8,9]),3,5))
"""Task1"""
"""Here is a sequence with len N and M-number of queries"""
"""Queries are - How many zeroes(0) on half-interval [L,R)"""
"""Solution 1 O(NM) difficulty"""
"""For each query run through numbers from L to R(not inclusive) and count a number of zeroes"""
def countzeroes(nums, l, r):
cnt = 0
for i in range(l,r):
if nums[i] == 0:
cnt += 1
return cnt
"""Solution 2 O(N+M) difficulty"""
"""For each prefix we count number of zeroes on it(prefixzeroes)"""
"""That way, an answer for half-interval [L,R) will be: prefixzeroes[R] - prefixzeroes[L]"""
def makeprefixzeroes(nums):
prefixzeroes =[0] * (len(nums) +1)
for i in range(2, len(nums) +1):
if nums[i-1] == 0:
prefixzeroes[i] = prefixzeroes[i-1] + 1
else:
prefixzeroes[i] = prefixzeroes[i-1]
return prefixzeroes
def countzeroes1(prefixzeroes, l, r):
return prefixzeroes[r] - prefixzeroes[l]
"""Task2"""
"""Here is a sequence with len N. We need to find a number of intervals with 0-sum"""
"""Solution 1 O(N^3) difficulty"""
"""Search for all of the Beginnings and Endings for an interval and count a sum of it's elements"""
def countzerosumranges(nums):
cntranges = 0
for i in range(len(nums)):
for j in range(i+1, len(nums) +1):
rangesum = 0
for k in range(i,j):
rangesum += nums[k]
if rangesum == 0:
cntranges += 1
return cntranges
"""Solution 2 O(N^2) difficulty"""
"""Search for all of the Beginnings and will move and Ending for an inteval and count a sum of it's elements"""
def countzerosumranges2(nums):
cntranges = 0
for i in range(len(nums)):
rangesum = 0
for j in range(i, len(nums)):
rangesum += nums[j]
if rangesum == 0:
cntranges += 1
return cntranges
"""Solution 3 O(N) difficulty"""
"""Lets count a prefixsums. Same prefixsums means that the sum of the elements on interval with beginning and ending
on positions where prefixsums are the same will be equal to zero"""
def countprefixsums(nums):
prefixsumbyvalue = {0 : 1} # it means that sequence with sum 0 we met 1 time
nowsum = 0
for now in nums:
nowsum += now
if nowsum not in prefixsumbyvalue:
prefixsumbyvalue[nowsum] = 0
prefixsumbyvalue[nowsum] += 1 # for an element in our dict with current prefixsum we raise a number of appearances by 1
return prefixsumbyvalue
def countzerosumranges3(prefixsumbyvalue):
cntranges = 0
for nowsum in prefixsumbyvalue: # run through all of the prefixsums
cntsum = prefixsumbyvalue[nowsum]
cntranges += cntsum * (cntsum -1) // 2 # count a number of pairs with formula
return cntranges
"""Task3"""
"""Here are sorted sequence with len N and number K. We need to find a number of pairs A,B. B-A > K"""
"""Solution 1 O(N^2) difficulty"""
"""Run through all of the pairs of numbers and check the condition"""
def cntpairswithdiffgtk(sortednums, k):
cntpairs = 0
for first in range(len(sortednums)):
for last in range(first, len(sortednums)):
if sortednums[last] - sortednums[first] > k:
cntpairs += 1
return cntpairs
"""Solution 2 O(N) difficulty"""
"""Take a min number and find a first suitable greater one. All of the numbers which are greater than the first suitable are suitable too.
Take as a min number the next number, and lets move a pointer of the first suitable greater one from the position where it is"""
def cntpairswithdiffgtk2(sortednums, k):
cntpairs = 0
last = 0
for first in range(len(sortednums)):
while last < len(sortednums) and sortednums[last] - sortednums[first] <= k: # conditions check goes from left to right, so if the first statement isn't true the second one won't be called
last += 1
cntpairs += len(sortednums) - last
return cntpairs
"""Task4"""
"""Football player has one numerical characteristic - professionalism. A team called solid if the professionalism of one player is not greater than the sum of
professionalism of any two other players. A team consists of any number of players.
We have a sorted sequence with len N - professionalism of players. We need to find a maximum sum of professionalism for solid team"""
"""Solution 1"""
def bestteamsum(players):
bestsum = 0
nowsum = 0
last = 0
for first in range(len(players)):
while last < len(players) and (last == first or players[first] + players [first + 1] >= players[last]):
nowsum += players[last]
last += 1
bestsum = max(bestsum, nowsum)
nowsum -= players[first]
return bestsum
"""Task5, Merge!"""
"""Here are two sorted sequences with len N and len M"""
"""We need to make one sorted sequence of these two"""
"""Solution 1"""
"""Lets set a pointers to the beginning of each of the sequences. Choose the one which pointed on the lower number, put this number to the result and move the pointer"""
def merge(nums1, nums2):
merged = [0] * (len(nums1) + len(nums2))
first1 = first2 = 0
inf = max(nums1[-1], nums2[-1] +1)
nums1.append(inf)
nums2.append(inf)
for k in range(len(nums1) + len(nums2) -2):
if nums1[first1] <= nums2[first2]:
merged[k] = nums1[first1]
first1 += 1
else:
merged[k] = nums2[first2]
first2 += 1
nums1.pop()
nums2.pop()
return merged
print(merge([2,3,15,99,100,101,102,102],[66,77,78,78,79,200]))
"""Solution 2 O(N+M) difficulty"""
def merge2(nums1, nums2):
merged = [0] * (len(nums1) + len(nums2))
first1 = first2 = 0
for k in range(len(nums1) + len(nums2)):
if first1 != len(nums1) and (first2 == len(nums2) or nums1[first1] <= nums2[first2]):
merged[k] = nums1[first1]
first1 += 1
else:
merged[k] = nums2[first2]
first2 += 1
return merged
print(merge2([2,3,15,99,100,101,102,102],[66,77,78,78,79,200]))