leetcode小白笔记02|链表(203、206)、队列(933)、栈(20、496)

目录

一、链表

(一)基本概念

(二)链表的的四种操作

(三)链表常用操作

 (四)leetcode练习题

二、队列

(一)基本概念

(二)队列的四种操作

(三)队列常用操作

(五)python的deque与list的区别

(六)leetcode练习题

三、栈

(一)基本概念

(二)栈的四种操作

(三)栈的常用操作

(四)leetcode练习题


一、链表

(一)基本概念

1、链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。

2、结点包括两个部分:(1)存储数据元素的数据域(内存空间),(2)存储指向下一个结点地址的指针域。

3.链表分为 (1)单链表(leetcode刷题使用最多) (2)双链表 (3)单向循环链表 (4)双向循环链表

特点:适合写、不适合读

适用场景:读少写多

(二)链表的的四种操作

1、访问 Access  O(n) (没有索引了,要从头开始遍历)

2、搜索 Search  O(n)

3、插入 Insert    O(1)  (仅仅指删除这个操作,不包含遍历找到这个元素的过程)

4、删除 Delete   O(1)  (同上)

(三)链表常用操作

1、创建链表

使用deque包来创建

 2、添加元素

两种方法:append(末尾)、insert(特定索引位置)

3、访问元素

4、查找元素

找到特定元素的索引

5、更新元素

6、删除元素

两种方法:del linkedlist[i]是删除索引位置的元素,linkedlist.remove(i)括号中是元素,不是索引

7、链表的长度

 (四)leetcode练习题

203移除链表元素:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

 解法1:不设头结点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        cur=pre=head
        if (head!=None):# 考虑了[]
            while (head!=None and pre==head and cur==head ):# head!=None条件考虑了[7,7,7,7]这种情况到最后head是None的情况
                if (head.val!=val):
                    cur=head.next
                    pre=head
                else:
                    head=head.next
                    pre=cur=head
            while cur:
                if (cur.val==val):
                    pre.next=cur.next
                    cur=cur.next
                else:
                    cur=cur.next
                    pre=pre.next
            return head
        else:
            return head

解法2(简单解法):在头结点前新建一个结点。next指向头结点。


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        prehead = ListNode()
        prehead.next = head
        cur=head
        pre=prehead
        while cur:
            if cur.val==val:
                pre.next = cur.next
                cur=cur.next
            else:
                pre=pre.next
                cur=cur.next
        return prehead.next

206反转链表:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur=head
        pre=None
        while cur:
            nnext = cur.next
            cur.next = pre
            pre = cur
            cur = nnext
        return pre

二、队列

(一)基本概念

特点:先入先出。

分类:

1、单端队列:只有一个扣可以进,一个口可以出

2、双端队列(用的不多):两个口都可以进,两个口都可以出

(二)队列的四种操作

1、访问 Access  O(n) (从队列头开始遍历)

2、搜索 Search  O(n)    

3、插入 Insert    O(1)  (只能在末尾插入)

4、删除 Delete   O(1)  (只能删除第一个)

(三)队列常用操作

左边为队头,右边为队尾

1、创建队列

默认用deque创建的是一个双端队列,但大部分时候只用单端就可以

2、添加元素

3、获取即将出队的元素

4、删除即将出队的元素

popleft不仅可以删除元素,还同时可以返还元素

5、判断队列是否为空、队列长度

6、遍历队列(边删除边遍历队列)

(五)python的deque与list的区别
  • 根据index读list,时间复杂度为O(1),deque是O(n)
  • 在两头插入数据,deque的时间复杂度为O(1), list为O(n)
  • deque是一个双向链表,所以操作头尾非常简单。
  • 随机往中间插入数据,deque与list的时间复杂度都是O(n)
(六)leetcode练习题

933最近的请求次数

写一个 RecentCounter 类来计算特定时间范围内最近的请求。

请你实现 RecentCounter 类:

  • RecentCounter() 初始化计数器,请求数为 0 。
  • int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。

保证 每次对 ping 的调用都使用比之前更大的 t 值。

class RecentCounter:

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

    def ping(self, t: int) -> int:
        self.q.append(t)
        while len(self.q)!=0 and (t-self.q[0])>3000:
            self.q.popleft()
        return len(self.q)



# Your RecentCounter object will be instantiated and called as such:
# obj = RecentCounter()
# param_1 = obj.ping(t)

三、栈

(一)基本概念

特点:先进后出

应用:浏览器的后退功能

(二)栈的四种操作

1、访问 Access  O(1)  (栈顶元素)

2、搜索 Search  O(n)    

3、插入 Insert    O(1)  (只能在栈顶插入)

4、删除 Delete   O(1)  (只能删除栈顶元素)

(三)栈的常用操作

1、创建栈

直接用列表实现栈常用的操作

2、添加元素

3、查看栈顶元素

4、删除栈顶元素

5、栈的长度 O(1)

列表里其实有一个变量,进出元素随时加减,所以len的时间复杂度是O(1)

6、栈是否为空

7、遍历栈(便删除栈顶边遍历)

(四)leetcode练习题

20有效的括号

解法一:自己写的

class Solution:
    def isValid(self, s: str) -> bool:
        stack=[0]
        for char in s:
            if stack[-1]=='(' and char==')':
                stack.pop()
            elif stack[-1]=='[' and char==']':
                stack.pop()
            elif stack[-1]=='{' and char=='}':
                stack.pop()
            else:
                stack.append(char)
        
        if len(stack)==1:
            return True
        else:
            return False

解法二:大佬写的(和上面思路一致,但写法非常简洁)

class Solution:
    def isValid(self, s: str) -> bool:
        dic = {')':'(',']':'[','}':'{'}
        stack = []
        for i in s:
            if stack and i in dic: # stack不为空 且 是dic中的key(遇到右括号才进入这个if)
                if stack[-1] == dic[i]: stack.pop()
                else: return False # 已经遇到右括号了,但是栈顶不是和右括号对应的左括号,无效
            else: stack.append(i) # 栈空 或 左括号进栈
            
        return not stack

496下一个更大元素

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。

给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1

解法一:自己写的

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        stack = []
        for n1 in nums1:
            for i,n2 in enumerate(nums2):
                if n2 == n1:
                    max = n2
                    stack.append(-1)
                    for j in range(i+1,len(nums2)):
                        if nums2[j]>n2:
                            max=nums2[j]
                            stack[-1] = max
                            break
                        else:
                            pass
                else:
                    pass
        return stack

 break:结束本循环,也就是说,即使循环次数没有结束,只要碰到break,这个循环就结束了。如果是循环嵌套,内循环里边有break,则结束内循环,外循环不受影响;如果是外循环有break,则结束外循环。

解法二:大佬写的

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        m, n = len(nums1), len(nums2)
        res = [0] * m
        for i in range(m):
            j = nums2.index(nums1[i])
            k = j + 1
            while k < n and nums2[k] < nums2[j]:
                k += 1
            res[i] = nums2[k] if k < n else -1
        return res

注:

c = a if a >b else b

如果a>b为真,则输出a,否则输出b

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值