题目如下
给定N,和一个黑名单数组,要求每次从[0,N)中选出一个随机数,这个随机数不能存在于黑名单中
思路:
最终结果中随机数的个数肯定是N-len(blacklist),所以我们要一是要选择出最后的随机值,一个是要将黑名单的中的值映射到白名单中
结果中的随机数的个数为N-len(blacklist),那么我们肯定先取数组[0,N]的前N-len(blacklist)个元素,但是这前N-len(blacklist)如果有黑名单中的元素怎么办呢。我们用一个指针从后往前扫描这个数组,如果后面的值不在黑名单中而前面的值在黑名单中,则用后面的值替换前面的即可。
在上述操作后,我们就将random的范围从N缩小到了N- len(blacklist)大小的范围中,用一个map存起来,键为1~N-len(blacklist),值为白名单中的数
第一次提交代码如下
class Solution:
def __init__(self, N, blacklist):
"""
:type N: int
:type blacklist: List[int]
"""
self.map = {}
for i in blacklist:
self.map[i] = 1
self.M = N - len(blacklist)
for i in blacklist:
if i < self.M:
N = N-1
while N in self.map:
N -= 1
self.map[i] = N
for i in range(self.M):
if i not in self.map:
self.map[i] = i
def pick(self):
"""
:rtype: int
"""
import random
return self.map[random.randint(0,self.M-1)]
过了 47个例子,然后报了如下的超出内存的错误
还是第一次遇到超出内存的error
review了一下代码,发现了可以优化的地方
for i in range(self.M):
if i not in self.map:
self.map[i] = i
这段代码其实是没必要的,没必要将所有白名单的映射都记录下来,只要记录下来那些在0~N-len(blacklist)中需要重新映射的数即可,因为大部分数字都是不变的,比如随机到1它范围的就是1,随机到黑名单中数时才需要查表
AC代码:
class Solution:
def __init__(self, N, blacklist):
"""
:type N: int
:type blacklist: List[int]
"""
self.map = {}
for i in blacklist:
self.map[i] = 1
self.M = N - len(blacklist)
for i in blacklist:
if i < self.M:
N = N-1
while N in self.map:
N -= 1
self.map[i] = N
# print(self.map)
# print(self.M)
def pick(self):
"""
:rtype: int
"""
import random
res =random.randint(0,self.M-1)
return self.map[res] if res in self.map else res