数据结构与算法——第一弹

题目来自牛客网

NC78 反转单向链表

日期:2021.8.29

方法:定义pre存储新链表的头,cur用于反转方向,nex用于遍历旧链表,然后不断遍历

nex = cur.next 旧链表向前移动

cur.next = pre 改变当前节点的方向

pre = cur 新链表的头向前移动

cur = nex 当前节点向前移动

失误: list.reverse()返回None,直接将list反向

自己的解法:遍历原链表,并用列表暂存链表的值,反转列表后,生成新的链表

时间复杂度:O(n),

空间复杂度:O(n)

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead is None:#判断是否为空
            return None
        tem_list = []  #存储链表的所有值
        tem_pHead = pHead # 保存输入链表的头
        while(True):# 遍历输入链表
            tem_list.append(tem_pHead.val)
            if tem_pHead.next is None:
                break
            else:
                tem_pHead = tem_pHead.next
        tem_list.reverse() # 反转链表的值
        new_list = ListNode(tem_list[0]) # 新链表的头
        tem_list2 = new_list # 用于生成反转链表
        for i in range(len(tem_list))[1:]: # 生成反转链表
            tem_list2.next = ListNode(tem_list[i])
            tem_list2 = tem_list2.next
        return new_list

标准解法: 直接改变原链表方向,把头变成尾,然后把下个节点指向头,直至遇到None

时间复杂度:O(n),

空间复杂度:O(1)

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead is None or pHead.next is None:#判断是否为空 或只有一个值
            return pHead
        pre = ListNode(None) # 存储新链表的头
        cur = pHead 
        nex = ListNode(None) # 与cur一起遍历整个链表
        while cur is not None:
            nex = cur.next
            if cur == pHead:#判断是否是头
                cur.next = None # 生成新链表的尾
            else:
                cur.next = pre # 反转节点的方向,指向新链表
            pre = cur #将新链表的头指向新节点
            cur = nex #将cur指向下个节点
            # 当遍历到最后一个节点时,nex会变成None,从而cur会变成None,退出循环
        return pre 

NC93 设计LRU缓存结构

日期:2021.8.30

思路:把一个字典当作双向链表,来存储键值对,当每次读取一个值时,将该值移动到字典最右端,并删除原值

缺点:再内置dict中,是没有顺序的,可能出现错误

#
# lru design
# @param operators int整型二维数组 the ops
# @param k int整型 the k
# @return int整型一维数组
#
class Solution:
    def __init__(self):
        self.lru = {} #双向链表作为缓存,左侧作为最不常用的,右侧作为最常用的
    def set(self,dic,k):
        '''
        将dic(key,value)插入缓存
        '''
        if len(self.lru) == k:    #当满的时候,删除最不常用的
            key = list(self.lru.keys())[0]
            self.lru.pop(key)
        #若没满,则添加当前元素
        key = dic[0]
        value = dic[1]
        self.lru[key] = value
    def get(self,key):
        '''
        从缓存中读取并更新缓存
        '''
        if key in self.lru:
            value = self.lru[key]
            # 更新顺序
            self.lru.pop(key) # 删除
            self.lru[key] = value #移动到最右段
            return value
        else:
            return -1
    def LRU(self , operators , k ):
        # write code here 
        l_return = []
        for opt in operators:
            if opt[0] == 1 :
                self.set([opt[1],opt[2]],k)
            if opt[0] == 2:
                key = opt[1]
                l_return.append(self.get(key))
        return l_return

改进:将dict更换为OrderedDict(底层直接使用了哈希表和双链表)

from collections import OrderedDict

class Solution:
    def __init__(self):
        self.cache = OrderedDict()
 
    def get(self, key):
        if key not in self.cache:
            return -1
        self.cache.move_to_end(key)# 移动到末尾
        return self.cache[key]
 
    def set(self, key, value, k):
        if key in self.cache: #若已存在key,更新当前值
            self.cache.move_to_end(key)
            self.cache[key] = value
            return None
        if len(self.cache) == k:# 若达到容量,则弹出头部节点
            self.cache.popitem(last=False)
        self.cache[key] = value
            
    def LRU(self, operators, k):
        res = []
        for opt in operators:
            if opt[0] == 1:
                self.set(opt[1], opt[2], k)
            elif opt[0] == 2:
                res.append(self.get(opt[1]))
        return res

大佬解法:双向链表+哈希表

class DListNode:
    def __init__(self, x=0, y=0):
        self.key = x
        self.value = y
        self.pre = None
        self.next = None
 
class Solution:
    def __init__(self):
        self.head = DListNode()
        self.tail = DListNode()
        self.head.next = self.tail
        self.tail.pre = self.head
        self.cache = dict()
 
    def get(self, key):
        if key not in self.cache:
            return -1
        node = self.cache[key]
        self.move_to_end(node)
        return node.value
 
    def set(self, key, value, k):
        if key in self.cache:
            node = self.cache[key]
            node.value = value
            self.move_to_end(node)
        else:
            node = DListNode(key, value)
            self.cache[key] = node
            self.add_to_end(node)
            if len(self.cache) > k:
                removed = self.head.next
                self.remove(removed)
                del self.cache[removed.key]
 
    def remove(self, node):
        node.pre.next = node.next
        node.next.pre = node.pre
 
    def add_to_end(self, node):
        node.pre = self.tail.pre
        node.next = self.tail
        self.tail.pre.next = node
        self.tail.pre = node
 
    def move_to_end(self, node):
        self.remove(node)
        self.add_to_end(node)
 
    def LRU(self, operators, k):
        res = []
        for opt in operators:
            if opt[0] == 1:
                self.set(opt[1], opt[2], k)
            elif opt[0] == 2:
                res.append(self.get(opt[1]))
        return res

NC4 判断链表中是否有环

日期:2021.8.31

难点:如何让空间复杂度为O(1)

思路:用一个哈希表复制链表中所有的节点,当出现重复节点时,证明有环

时间复杂度:O(N),空间复杂度O(N)

缺点:占用空间太大

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

#
# 
# @param head ListNode类 
# @return bool布尔型
#
class Solution:
    def hasCycle(self , head ):
        # write code here
        tem = [] #存储链表中所有的节点
        if head is None or head.next is None:#判断链表是否为空或长度只有1
            return False
        while (head.next is not None):
            tem.append(head)# 将当前节点添加到列表中
            head = head.next # 向前移动一步
            if head in tem: # 如果该节点在以前已经出现过,则证明有环出现
                return True
        return False

改进,使用快指针(每次走两步),慢指针(每次走一步),如果存在环,两者最终将相遇,空间复杂度降低为O(1)

class Solution:
    def hasCycle(self , head ):
        # write code here
        if head is None or head.next is None:
            return False
        low = head
        fast = head
        while((low is not None) and (fast is not None)):#两者任何一个走到尽头,则停止循环
            low = low.next
            if fast.next is not None:
                fast = fast.next.next
            else:					#当链表长度是奇数时,直接返回False
                return False
            if low == fast: # 判断两者是否相遇
                return True
        return False

NC76 用两个栈实现队列

日期:2021.9.1

知识点:python中的List就相当于一个栈,只使用append和pop的时候

初步解法:

不足:使用复制后反转的方式,来将stack1中的数据复制到stack2中,不太妥当

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = [] # 压入栈(右侧压入)
        self.stack2 = [] # 弹出栈(右侧弹出)
    def push(self, node):
        # write code here
        self.stack1.append(node) #将数据压入栈
    def pop(self):
        # return xx
        if len(self.stack2) > 0 :  #当弹出栈不为空时,弹出最右侧值
            return self.stack2.pop()
        elif len(self.stack1) == 0: # 当弹出栈和压入栈都为空时,返回None
            return None
        else:						# 当弹出栈为空,压入栈不为空时,将压入栈中的值反向后复制到弹出栈中,并删除原来的值
            self.stack2 = self.stack1.copy()
            self.stack2.reverse()
            self.stack1 = []
            return self.stack2.pop()

改进:逐个将stack1中的数据复制到stack2中

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = [] # 压入栈(右侧压入)
        self.stack2 = [] # 弹出栈(右侧弹出)
    def push(self, node):
        # write code here
        self.stack1.append(node)
    def pop(self):
        # return xx
        if len(self.stack2) > 0 :  
            return self.stack2.pop()
        elif len(self.stack1) == 0: 
            return None
        else:						
            while self.stack1:
                self.stack2.append(self.stack1.pop()) #逐个弹出并添加到stack2z
            return self.stack2.pop()

NC105 二分查找-II

日期:2021.9.1

难点:返回从左往右第一个相等的值的索引

初步思路:首先判断数组为空或数组长度为一的情况,然后用start和end,middle进行二分查找,若middle处的值=target,需要继续向前寻找,最终会出现start=end-1的情况,判断首尾后,跳出循环

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 如果目标值存在返回下标,否则返回 -1
# @param nums int整型一维数组 
# @param target int整型 
# @return int整型
#
class Solution:
    def search(self , nums , target ):
        # write code here
        length = len(nums) #数组的长度
        if length == 0: #数组为空
            return -1
        elif length ==1: #数组长度为1
            return -1 if nums[0] != target else 0
        start = 0 #首
        end = length-1 #尾
        index = -1 #存储返回的索引
        while (True):
            middle = int((start+end)/2)
            value = nums[middle]
            if value == target: #若middle处遇到target,则赋值给index,并继续向前查找
                index = middle
                end = middle
            elif value>target:
                end = middle
            else:
                start = middle 
            if start == end -1: # 当start=end-1的情况,判断首尾后,跳出循环
                if nums[start] == target:
                    index = start
                    break
                if nums[end] == target:
                    index = end
                    break
                break 
        return index

NC15 求二叉树的层序遍历

日期:2021.9.2

二叉树的三种遍历方法:python 二叉树 前序中序后序层序 递归与非递归遍历_Mario的博客-CSDN博客

前序遍历:中左右(先读当前节点的值,然后跳到左边,和右边)

中序遍历:左中右

后序遍历:左右中

层序遍历:一层一层读取

初步思路:使用一个队列来存储每一层的所有树节点,然后遍历队列中节点的所有值,并用一个临时队列,遍历原队列中节点的所有子节点,将原队列更新为临时队列

时间复杂度:O (N) 空间复杂度O(N)

缺点:使用了一个临时队列,可以优化后将其去掉

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

#
# 
# @param root TreeNode类 
# @return int整型二维数组
#
class Solution:
    def levelOrder(self , root ):
        # write code here
        if root is None:
            return []
        queue = [root] #遍历存储某一层的所有节点
        res = [] #返回结果
        while len(queue)>0:#当某一层节点数量为零时,跳出循环
            res.append([node.val for node in queue])#遍历所有值
            temp = [] #临时列表存储下一层节点
            for node in queue: #注意从左向右添加节点
                if node.left is not None:
                    temp.append(node.left)
                if node.right is not None:
                    temp.append(node.right)
            queue = temp
        return res

参考:递归解法:

class Solution:
    def levelOrder(self , root ):
        # write code here
        if root is None:
            return []
        res = [] # 返回值
        level = 0 #保存层数
        def get_level(level,node):
            if level == len(res):#当遍历到下一层时,添加一层
                res.append([])
            res[level].append(node.val) #将值添加到对应的层
            if node.left:
                get_level(level+1,node.left) #进入下一层的左侧
            if node.right:
                get_level(level+1,node.right)#进入下一层的右侧
        get_level(level,root)
        return res

WC142 排序算法

日期:2021.9.3

方法:快速排序

参考:快速排序

  • 解法:
    1. 选择左侧第一个值作为基准point
    2. 从右边开始,找到第一个小于point的索引right
    3. 从左边开始,找到第一个大于point的索引left
    4. 交换两者
    5. 重复1-3,知道left=right
    6. 交换point 和right的值
    7. 此时,right左侧的值都小于right,右侧的值都大于right,然后递归即可
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
# 将给定数组排序
# @param arr int整型一维数组 待排序的数组
# @return int整型一维数组
#
class Solution:
    def MySort(self , arr ):
        # write code here
        # write code here
        return self.QuickSort(arr,0,len(arr)-1)
    
    def QuickSort(self,arr,left,right):
        '''
        快速排序
        '''
        if left>=right:
            return 
        point = arr[left]
        low = left
        high = right
        while(left < right):
            while left <right and point <= arr[right]:
                right -= 1
            while left < right and point >= arr[left]:
                left += 1
            self.swap(arr,left,right)
        self.swap(arr,low,right)
        self.QuickSort(arr, low, right-1)
        self.QuickSort(arr, right+1, high)
        return arr 
    def swap(self,arr,i,j):
        temp = arr[i]
        arr[i] = arr[j]
        arr[j] = temp

NC45 实现二叉树先序,中序和后序遍历

日期:2021.9.4

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

#
# 
# @param root TreeNode类 the root of binary tree
# @return int整型二维数组
#
class Solution:
    def threeOrders(self , root ):
        # write code here
        if root is None:
            return [None,None,None]
        def first(root):
            '''
            前序遍历,先读中节点,然后读左子树,最后右子树
            '''
            stack = [] #存储扫过的节点
            res = [] #存储值
            while root or stack:
                while root is not None: #一直读到当前子树的最底层的最左侧
                    stack.append(root)
                    res.append(root.val)#添加父节点的值
                    root = root.left # 走向左子树
                if stack:
                    node = stack.pop() #读取最后加入的节点
                    if node.right is not None:
                        root = node.right #走向右子树
            return res
        def middle(root):
            '''
            中序遍历,先读左子树,然后读父节点,最后右子树
            '''
            stack = []
            res = []
            while root or stack:
                while root is not None:
                    stack.append(root)
                    root = root.left # 一直走到左子树的尽头
                if stack:
                    node = stack.pop()
                    res.append(node.val) #读取最后一个加入节点的值(左子树为none的父节点的值)
                    if node.right is not None:
                        root = node.right #走向右子树
            return res
        def last(root):
            '''
            后序遍历,先读左子树,然后读右子树,最后父节点
            【父节点的值、右节点、左节点】
            【父节点的值、右节点、左节点的值、左—右节点、左-左节点】
            【父节点的值、右节点、左节点的值、左—右节点、左-左节点的值】
            实现后序遍历
            '''
            stack = []
            res = []
            stack.append(root) #压入父节点
            while stack:
                node = stack.pop()
                if type(node) is TreeNode: #如果当前节点是父节点,将当前节点替换成节点值,并压入右节点、左节点
                    stack.append(node.val)
                    if node.right:
                        stack.append(node.right)
                    if node.left:
                        stack.append(node.left)
                else:
                    res.append(node) #当栈的头部是数字时,说明左侧走到了尽头,将父节点的值添加到列表中
            return res
        return [first(root),middle(root),last(root)]

递归解法

class Solution:
    def threeOrders(self , root ):
        # write code here
        if root is None:
            return [None,None,None]
        def first(root,res = []):
            if not root:
                return
            res.append(root.val)
            first(root.left,res)
            first(root.right,res)
            return res
        def middle(root,res):
            if not root:
                return
            middle(root.left, res)
            res.append(root.val)
            middle(root.right, res)
            return res
        def last(root,res=[]):
            if not root:
                return
            last(root.left,res)
            last(root.right,res)
            res.append(root.val)
            return res
        return [first(root,[]),middle(root,[]),last(root,[])]
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值