日常系列LeetCode《20·数据结构设计》

Posted 常某某的好奇心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常系列LeetCode《20·数据结构设计》相关的知识,希望对你有一定的参考价值。

数据规模->时间复杂度

<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)

内容

lc 155 【剑指 30】【top100】:最小栈
https://leetcode.cn/problems/min-stack/
提示:
-2^31 <= val <= 2^31 - 1
pop、top 和 getMin 操作总是在 非空栈 上调用
push, pop, top, and getMin最多被调用 3 * 104 次


#方案一:两个栈(辅助栈)
class MinStack:

    def __init__(self):
        self.datastack=[]
        self.minstack=[]

    def push(self, val: int) -> None:
        self.datastack.append(val)
        #key:<=
        if not self.minstack or val<=self.minstack[-1]:
            self.minstack.append(val) 

    def pop(self) -> None:
        top=self.datastack.pop()
        #key
        if top==self.minstack[-1]:
            self.minstack.pop()

    def top(self) -> int:
        return self.datastack[-1]


    def getMin(self) -> int:
        return self.minstack[-1]

# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

#方案二:一个栈-存储节点
class Node:
    def __init__(self,val=0,minn=0):
        self.val=val
        self.min=minn

class MinStack:

    def __init__(self):
        self.datastack=[]

    def push(self, val: int) -> None:
        #key:
        newnode=Node()
        newnode.val=val
        if not self.datastack:
            newnode.min=val
        else:
            newnode.min=min(self.datastack[-1].min,val)
        #
        self.datastack.append(newnode)
        
    def pop(self) -> None:
        self.datastack.pop()


    def top(self) -> int:
        return self.datastack[-1].val
    def getMin(self) -> int:
        return self.datastack[-1].min
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

#方案三:自定义栈-链表结构
class ListNode:
    def __init__(self,val=0,minn=0,next=None):
        self.val=val
        self.min=minn
        self.next=next

class MinStack:

    def __init__(self):
        self.dummynode=ListNode()

    def push(self, val: int) -> None:
        #key:
        newnode=ListNode()
        newnode.val=val
        if not self.dummynode.next:
            newnode.min=val
        else:
            newnode.min=min(self.dummynode.next.min,val)
        #key
        newnode.next=self.dummynode.next
        self.dummynode.next=newnode
        
    def pop(self) -> None:
        firstnode=self.dummynode.next
        if firstnode:
	        self.dummynode.next=firstnode.next
	        firstnode.next=None

    def top(self) -> int:
        return self.dummynode.next.val
        
    def getMin(self) -> int:
        return self.dummynode.next.min
       
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

lc 225 :用队列实现栈
https://leetcode.cn/problems/implement-stack-using-queues/
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
提示:
1 <= x <= 9
最多调用100 次 push、pop、top 和 empty
每次调用 pop 和 top 都保证栈不为空
进阶:
你能否仅用一个队列来实现栈。


#方案一:两个队列(使用push的调用次数多)
class MyStack:

    def __init__(self):
        self.queue1=deque()
        self.queue2=deque()
        

    def push(self, x: int) -> None:
        self.queue1.append(x)

	#o(n)
    def pop(self) -> int:
        #key-key-key:while
        if self.queue1:
            while(self.queue1):
                x=self.queue1.popleft()
                if not self.queue1:
                    return x
                self.queue2.append(x)#key位置(最后无head元素)
        #
        elif self.queue2:
            while(self.queue2):
                x=self.queue2.popleft()
                if not self.queue2:
                    return x
                self.queue1.append(x)#key位置(最后无head元素)

	#o(n)
    def top(self) -> int:
        if self.queue1:
            while(self.queue1):
                x=self.queue1.popleft()
                self.queue2.append(x)#key位置(最后有head元素)
                if not self.queue1:
                    return x           
        #
        elif self.queue2:
            while(self.queue2):
                x=self.queue2.popleft()
                self.queue1.append(x)#key位置(最后有head元素)
                if not self.queue2:
                    return x
            
    def empty(self) -> bool:
        return len(self.queue1)==0 and len(self.queue2)==0

# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()

#方案二:两个队列(优化:适用pop与top的调用次数多)
class MyStack:

    def __init__(self):
        self.queue1=deque()
        self.queue2=deque()
        
    def push(self, x: int) -> None:
        #key-key-key:while
        self.queue2.append(x)
        while(self.queue1):
            self.queue2.append(self.queue1.popleft())
        self.queue1,self.queue2=self.queue2,self.queue1

    def pop(self) -> int:
        return self.queue1.popleft()
                
    def top(self) -> int:
        return self.queue1[0]
                      
    def empty(self) -> bool:
        return not self.queue1 and not self.queue2

# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()

#方案三:一个队列
class MyStack:

    def __init__(self):
        self.queue1=deque()   

    def push(self, x: int) -> None:
        #key-key-key:123->321
        size=len(self.queue1)
        self.queue1.append(x)
        for i in range(size):
            self.queue1.append(self.queue1.popleft())

    def pop(self) -> int:
        return self.queue1.popleft()
             
    def top(self) -> int:
        return self.queue1[0]    
            
    def empty(self) -> bool:
        return not self.queue1 

# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()

【剑指 09】: 用两个栈实现队列
https://leetcode.cn/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/
提示:
1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用

#方案一:
class CQueue:

    def __init__(self):
        self.stack1=[]
        self.stack2=[]

    def appendTail(self, value: int) -> None:
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        self.stack1.append(value)

    def deleteHead(self) -> int:
        while self.stack1:
            self.stack2.append(self.stack1.pop())
        if not self.stack2:
            return -1
        return self.stack2.pop()

# Your CQueue object will be instantiated and called as such:
# obj = CQueue()
# obj.appendTail(value)
# param_2 = obj.deleteHead()

#方案二:优化
class CQueue:

    def __init__(self):
        self.stack1=[]
        self.stack2=[]

    def appendTail(self, value: int) -> None:
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        self.stack1.append(value)

    def deleteHead(self) -> int:
        #key-key-key:stack2已经把stack1的前入元素变成前出元素
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        #
        if not self.stack2:
            return -1
        return self.stack2.pop()

# Your CQueue object will be instantiated and called as such:
# obj = CQueue()
# obj.appendTail(value)
# param_2 = obj.deleteHead()

lc 622 :设计循环队列
提示:
-2^31 <= val <= 2^31 - 1
最多调用 insert、remove 和 getRandom 函数 2 * 105 次
在调用 getRandom 方法时,数据结构中 至少存在一个 元素。
注意:你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1)

class MyCircularQueue:

    def __init__(self, k: int):
        self.k=k
        self.data=[None]*(k+1)#k=2,5-None-1为满
        self.head=0
        self.tail=0#队尾元素下一位

    def enQueue(self, value: int) -> bool:
        #
        if self.isFull():return False
        #
        self.data[self.tail]=value
        self.tail=(self.tail+1)%(self.k+1)
        return True

    def deQueue(self) -> bool:
        #
        if self.isEmpty():return False
        #
        self.data[self.head]=None   #可以略去这一行
        self.head=(self.head+1)%(self.k+1)
        return True

    def Front(self) -> int:
        if self.isEmpty(): return -1
        return self.data[self.head]

    def Rear(self) -> int:
        if self.isEmpty(): return -1
        return self.data[self.tail-1]

    def isEmpty(self) -> bool:#key
        return self.head==self.tail

    def isFull(self) -> bool: #key
        return (self.tail+1)%(self.k+1)==self.head

# Your MyCircularQueue object will be instantiated and called as such:
# obj = MyCircularQueue(k)
# param_1 = obj.enQueue(value)
# param_2 = obj.deQueue()
# param_3 = obj.Front()
# param_4 = obj.Rear()
# param_5 = obj.isEmpty()
# param_6 = obj.isFull()

lc 380【剑指 030】:O(1) 时间插入、删除和获取随机元素
https://leetcode.cn/problems/insert-delete-getrandom-o1/
提示:
-2^31 <= val <= 2^31 - 1
最多调用 insert、remove 和 getRandom 函数 2 * 105 次
在调用 getRandom 方法时,数据结构中 至少存在一个 元素。
注意:您必须实现类的函数,使每个函数的 平均 时间复杂度为 O(1) ;

class RandomizedSet:

    def __init__(self):
        self.idxmap=
        self.data=[]

    def insert(self, val: int) -> bool:
        if val in self.idxmap:return False #self.idxmap也对
        #
        self.idxmap[val]=len(self.data)
        self.data.append(val)
        return True

    def remove(self, val: int) -> bool:
        #hashset/map:指定data/key->o(1)
        #数组:根据随机索引->o(1)
        if val not in self.idxmap:return False
        #
        idx=self.idxmap[val]
        lastnum=self.data[-1]
        self.data[idx]=lastnum
        self.data.pop()
        #
        self.idxmap[lastnum]=idx
        del self.idxmap[val]
        return True 

    def getRandom(self) -> int:
        #randint(0,9):0-9
        return self.data[random.randint(0,len(self.data)-1)]#choice(self.data)   
# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param_1 = obj.insert(val)
# param_2 = obj.remove(val)
# param_3 = obj.getRandom()

lc 381 :O(1) 时间插入、删除和获取随机元素 - 允许重复
https://leetcode.cn/problems/insert-delete-getrandom-o1-duplicates-allowed/
提示:
-2^31 <= val <= 2^31 - 1
insert, remove 和 getRandom 最多 总共 被调用 2 * 10^5 次
当调用 getRandom 时,数据结构中 至少有一个 元素
注意:您必须实现类的函数,使每个函数的 平均 时间复杂度为 O(1) ;
生成测试用例时,只有在 RandomizedCollection 中 至少有一项 时,才会调用 getRandom

class RandomizedCollection:
    def __init__(self):
        self.idsmap=defaultdict(set) #for remove o(1) #list也可以
        self.data=[]

    def insert(self, val: int) -> bool:
        self.idsmap[val].add(len(self.data)) #允许重复插入
        self.data.append(val)
        return len(self.idsmap[val])==1 #但,重复插入返回False

    def remove(self, val: int) -> bool:
        if val not in self.idsmap:return False
        #
        idx=self.idsmap[val].pop()
        lastnum=self.data[-1]
        self.data[idx]=lastnum
        self.data.pop() #注意:此时k->k-1
        #key
        #idx已经被pop
        if len(self.idsmap[val])==0:
            del self.idsmap[val]
        
        if idx日常系列LeetCode《7·排序篇》

日常系列LeetCode《15·链表2》

日常系列LeetCode《14·链表1》

日常系列LeetCode《2·一维数组篇》

日常系列LeetCode《5·数学篇》

日常系列LeetCode《9·哈希查找篇》