inc,dec,getMin,getMax均为O(1)——一个有趣的数据结构

【栈和队列】getMin功能的栈(返回栈中最小元素的操作) 功能需求:         实现一个具有特殊功能的栈,首先要具有栈所要具备的功能,再实现此栈执行后能够返回栈中最小值的操作。其中pop、push、getMin的操作复杂度都是O(l)。有必要时可以使用现成的站结构操作来设计栈类型。(pop:弹出栈顶元素、push:压栈、getMin获取最小栈元素) 详细解析:         由于要操作一组数据,并且存入栈中,那么我们首先考虑到的是栈就需要分... 阅读详情

做leetcode题时遇到这样一道题,挺有趣的数据结构,所以记下来:)

1. All O`one Data Structure –leetcode 432

Implement a data structure supporting the following operations:

  • Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty string.
  • Dec(Key) - If Key’s value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string.
  • GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string “”.
  • GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string “”.

Challenge: Perform all these in O(1) time complexity.

2. 想法

我们知道hashmap 插入,删除,更改是O(1)的,为了得到最值也是O(1),关键是实现一个双向链表,同时利用到增减都为单位量。下面详细解释各部分

2.1. node

双向链表的结点,每个结点记录一个val,以及值为val的键的字典,val>0
* pre: 双向链表,指向前一结点
* next:双向链表,指向后一结点
* val: 关键字对应的值,可以看作频率,通过这个将不同值的关键值分组,类似分块查找,
* keys: 一个dict, 用来容纳val相同的键值,查找插入删除都为O(1)

2.2. 双向链表

有头指针,尾指针。有一个val=0的结点,初始化时头尾指针指向此头结点。
还有一个dict,键为val,值为对应val的结点,以便在O(1)内找到结点。

如果结点中不含任何关键字,则去掉此结点。如果还存在key,头指针指向val最小的除0的结点(必有关键字),尾指针则指向最大的结点,这样getMin,getMax都为O(1)。如果没有任何key,则只有一个不含关键字的头节点node(0),初始化时也是这样,则头尾指针都指向它

在增减时,需更新头尾指针(最值),可以发现,只有在增加结点或删除结点时才需更新

  • incTo(self,key,val):

    1. 判断val结点是否存在,若不,则创建此结点
    2. 使node(val)包含关键字key
    3. 如果前一结点(可以保证一定存在)含此关键字,则删除此关键字
    4. 由上一步,如果删除了前一结点的关键字后,前一结点不再含任何关键字,则删除此结点
  • dccTo(self,key,val):

    1. 判断val结点是否存在,若不,则创建此结点
    2. 使node(val)包含关键字key
    3. 后一结点(可以保证一定存在)一定含此关键字,删除此关键字
    4. 由上一步,如果删除了后一结点的关键字后,后一结点不再含任何关键字,则删除此结点
  • addNode(self,val):
    注意inc,dec时代码不一样,但思路是一样的

    1. 将结点注册到双向链表的access_mp,既给此dict,增加键值对val:node(val)
    2. 修改链连接
    3. 更新头尾指针指向的结点(由于inc,dec改变的是单位量,所以可以直接找到前一结点或后一节点,这是O(1)的
  • delNode(self,val):

    1. 修改链连接
    2. 更新头尾指针指向的结点(由于inc,dec改变的是单位量,所以可以直接找到此次dec后的最大值或最小值,即若上次最小值是val的话,则新的最小值为node(val).next,即下一节点(循环链表,如果为空时会自动指向头节点node(0),代码很简洁,同理可得上次最大值为val更新尾指针)
    3. 在access_mp中删除此结点

2.3. AllOne:

这个结构包含一个上述的双向链表和一个(key:val)键值对字典,通过此字典来增减关键字的val,同时在双向链表中找到对应结点,再找到对应的key

3. 总结

这有点像chain_map了,不过python中的chain_map只是简单的连接起来,方便操作多个map(dict),而这个数据结构通过双向链表将相同的val的key字典连接。由于增减的是单位量,所以更新时,更新最值可以通过链表在O(1)时间找到。
所以此结构可以用在更新关键字频繁且最好是单位量的地方,而且数据量很大时,查找最值也更有效。(不然创建删除结点费时间)

4. 测试

做了测试,与hashmap比较了一下(这里设定hashmap 当值<=0则删除该键,然后找最大值,最小值用O(n)时间)
测试是随机产生一些字符串,然后随机产生操作,inc,dec,getMin,getMax,以及对应的数据(参数),默认产生1000个操作,然后重复1000次,取总时间

-allOnehashMapratio
增减区间: [1,10]
增减与取最值操作的比例:1:1
2.83s1.67s1.69
增减区间: [1,5]
增减与取最值操作的比例:1:1
4.06s1.65s2.44
增减区间: [1,5]
增减与取最值操作的比例:1:5
1.59s2.21s0.72

4.1. 测试代码

from allOoneDS import AllOne
from time import time
from  random import choice,sample,randint

class hashMap:
    def __init__(self):
        self.op = {"inc":self.inc,"dec":self.dec,"getMaxKey":self.getMaxKey,"getMinKey":self.getMinKey}
        self.mp={'':0}
    def inc(self,key,n=1):
        if key in self.mp:self.mp[key]+=n
        else:self.mp[key]=n
    def dec(self,key,n=1):
        if key not in self.mp:return
        if self.mp[key]<=n:del self.mp[key]
        else: self.mp[key]-=n
    def getMinKey(self):
        return min(list(self.mp.keys()),key=lambda key:self.mp[key])
    def getMaxKey(self):
        return max(list(self.mp.keys()),key=lambda key:self.mp[key])


op_origin = ['inc','dec','getMinKey','getMaxKey','getMinKey','getMaxKey','getMinKey','getMaxKey','getMinKey','getMaxKey','getMinKey','getMaxKey']
ch=list('qwertyuiopasdfghjklzxcvbnm')
keys =[ ''.join(sample(ch,i)) for j in range(10) for i in range(1,20,5)]

def testCase(n=1000):
    ops=[]
    data=[]
    for i in range(n):
        p = randint(0,len(op_origin)-1)
        ops.append(op_origin[p])
        if p<2:
            data.append([randint(1,10)])
        else:data.append([])
    return ops,data

def test(repeat=1000):
    t1,t2=0,0
    for i in range(repeat):
        allOne = AllOne()
        hsmp = hashMap()
        ops,data = testCase()
        t1-=time()
        for op,datum in zip(ops,data):
            allOne.op[op](*datum)
        t1+=time()

        t2-=time()
        for op,datum in zip(ops,data):
            hsmp.op[op](*datum)
        t2+=time()
    return t1,t2


if __name__=='__main__':
    t1,t2= test()
    print(t1,t2)

5. allOne代码

class node:
    def __init__(self,val=None,data_mp=None,pre=None,next=None):
        self.val=val
        self.data_mp = {} if data_mp is None else data_mp
        self.pre=pre
        self.next=next
    def __lt__(self,nd):
        return  self.val<nd.val
    def getOne(self):
        if not self.data_mp:
            return ''
        else:return list(self.data_mp.items())[0][0]
    def __getitem__(self,key):
        return self.data_mp[key]
    def __iter__(self):
        return iter(self.data_mp)
    def __delitem__(self,key):
        del self.data_mp[key]
    def __setitem__(self,key,val):
        self.data_mp[key]= val
    def isEmpty(self):
        return self.data_mp=={}
    def __repr__(self):
        return 'node({},{})'.format(self.val,self.data_mp)
class doubleLinkedList:
    def __init__(self):
        self.head=  self.tail = node(0)
        self.head.next = self.head
        self.head.pre = self.head
        self.chain_mp={0:self.head}
    def __str__(self):
        li = list(self.chain_mp.values())
        li = [str(i) for i in li]
        return  'min:{}, max:{}\n'.format(self.head.val,self.tail.val)   \
               + '\n'.join(li)
    def getMax(self):
        return self.tail.getOne()
    def getMin(self):
        return self.head.getOne()
    def addIncNode(self,val):
        # when adding a node,inc 1, so it's guranted that node(val-1)  exists
        self.chain_mp[val].pre= self.chain_mp[val-1]   
        self.chain_mp[val].next= self.chain_mp[val-1].next
        self.chain_mp[val-1].next.pre = self.chain_mp[val-1].next = self.chain_mp[val]
    def addDecNode(self,val):
        # when adding a node,dec 1, so it's guranted that node(val+1)  exists
        self.chain_mp[val].next= self.chain_mp[val+1]   
        self.chain_mp[val].pre= self.chain_mp[val+1].pre
        self.chain_mp[val+1].pre.next = self.chain_mp[val+1].pre = self.chain_mp[val]
    def addNode(self,val,dec=False):
        self.chain_mp[val] = node(val)
        if dec:self.addDecNode(val)
        else:self.addIncNode(val)
        if self.tail.val<val:self.tail = self.chain_mp[val]
        if self.head.val>val or self.head.val==0:self.head= self.chain_mp[val]
    def delNode(self,val):
        self.chain_mp[val].next.pre = self.chain_mp[val].pre
        self.chain_mp[val].pre.next = self.chain_mp[val].next
        if self.tail.val==val:self.tail = self.chain_mp[val].pre
        if self.head.val==val:self.head = self.chain_mp[val].next
        del self.chain_mp[val]
    def incTo(self,key,val):  
        if val not in self.chain_mp: 
            self.addNode(val)
        self.chain_mp[val][key] = val
        if val!=1 :  # key in the pre node
            del self.chain_mp[val-1][key]
            #print(self.chain_mp[val-1])
            if self.chain_mp[val-1].isEmpty():
                #print('*'*20)
                self.delNode(val-1)
    def decTo(self,key,val):
        if val not in self.chain_mp:
            self.addNode(val,dec=True)
        # notice that the headnode(0) shouldn't add key
        if val!=0: self.chain_mp[val][key] = val  
        del self.chain_mp[val+1][key]
        if self.chain_mp[val+1].isEmpty():
            self.delNode(val+1)        

class AllOne:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.op = {"inc":self.inc,"dec":self.dec,"getMaxKey":self.getMaxKey,"getMinKey":self.getMinKey}
        self.mp = {}
        self.dll = doubleLinkedList()
    def __str__(self):
        return str(self.dll)
    def __getitem__(self,key):
        return self.mp[key]
    def __delitem__(self,key):
        del self.mp[key]
    def __setitem__(self,key,val):
        self.mp[key]= val
    def __iter__(self):
        return iter(self.mp)
    def inc(self, key,n=1):
        """
        Inserts a new key <Key> with value 1. Or increments an existing key by 1.
        :type key: str
        :rtype: void
        """
        if key in self:
            self[key]+=n
        else:self[key]=n
        for i in range(n): self.dll.incTo(key, self[key])
    def dec(self, key,n=1):
        """
        Decrements an existing key by 1. If Key's value is 1, remove it from the data structure.
        :type key: str
        :rtype: void
        """
        if key in self.mp:
            mn = min( self[key],n)
            for i in range(mn): self.dll.decTo(key, self[key]-i-1)
            if self[key] == n:
                del self[key]
            else:
                self[key] = self[key]-n
    def getMaxKey(self):
        """
        Returns one of the keys with maximal value.
        :rtype: str
        """
        return self.dll.getMax()

    def getMinKey(self):
        """
        Returns one of the keys with Minimal value.
        :rtype: str
        """
        return self.dll.getMin()
RealSense D455启动教程 RealSense D455启动教程 修改rs_camera.launch 阅读详情

相关推荐

信创改造实战:SpringBoot项目迁移到宝兰德BES 9.5.5的完整避坑指南(附依赖配置)

本文详细介绍了将SpringBoot项目迁移到宝兰德BES 9.5.5中间件的完整流程,包括环境准备、依赖调整、Web.xml版本适配、部署配置优化及常见问题解决方案。特别针对信创改造需求,提供了排除Tomcat依赖、处理BES专用starter等实用技巧,帮助开发者顺利完成国产中间件迁移。

weixin_30825581的博客 1095

JavaSE/day3函数与数组

1       函数 1.1   数的概述 发现不断进行加法运算,为了提高代码的复用性,就把该功能独立封装成一段独立的小程序,当下次需要执行加法运算的时候,就可以直接调用这个段小程序即可,那么这种封装形形式的具体表现形式则称作函数。 练习:把两个整数相加: public classFunctionDemo1{        public static void main(String

树上的小桥 的专栏 886

【密码学】生成8位26个字母和数字的全排列(密码字典,密钥)c++代码(非递归高效直接)

生成8位26个字母和数字的全排列(密钥)代码(非递归高效直接) 用C语言或C++,生成一个8位的26个字母和数字的全排列的原代码,例如从:00000000到ZZZZZZZZ。 说明:生成的这个字典会非常大,有36^8条记录,估计要3T的硬盘,跑一个晚上看看         这个方法比递归更高效,更直接。                                                ...

Wu_Being 的优快云 博客 1万+

【算法】最小栈的实现(getMin)

最小栈的实现

笨鸟学飞的博客 647

十五天学会Autodesk Inventor,看完这一系列就够了(七),工程图纸

不管哪种绘图软件,二维或三维绘图,最终均需要转换成工程图纸,才能交给现场人员进行制作,这是任一产品图都要经历的过程。那本章开始,我们一起看一下Inventor是如何实现工程图纸?

Crazydoubao的博客 4906

Node-Red系列教程——NodeRed通过OPC UA读取数据并写入mysql

NodeRed通opcua读取西门子数据并存入mysql

鲸鱼姐的专栏 1万+

inc和dec指令

inc 加1指令 dec 减1指令 一、加一指令inc inc a 相当于 add a,1 //i++ 优点 速度比add指令快,占用空间小 这条指令执行结果影响AF、OF、PF、SF、ZF标志位,但不影响CF进位标志位. 二、减一指令dec dec a 相当于 sub a,1 004012D7 > 83E8 01 SUB EAX,1 004012DA 836D FC 01 SUB DWORD PTR SS:[EBP-4],1 004012DE .

wyyy2088511的博客 1万+

修勾逃生巨人危机v10.9.9修改版:免广告无限内购与GM工具详解

游戏修改技术是通过对原版游戏程序进行代码层面的调整,实现特定功能的增强或限制解除。其核心原理涉及内存修改、资源替换和API拦截等技术手段,能够有效提升用户体验和测试效率。在移动游戏领域,免广告和无限内购是常见的技术实现方向,通过屏蔽广告SDK调用和修改内购验证逻辑,为用户提供更流畅的游戏体验。这类技术特别适合游戏开发者进行功能测试,以及玩家希望完整体验游戏内容而不受商业模式限制的场景。以修勾逃生巨人危机v10.9.9版本为例,该修改版集成了GM工具开启功能,通过特定操作路径即可激活调试面板,实现了广告去除和

weixin_30855099的博客 2588

栈实现getMin

题目 实现一个特殊的栈,在实现栈的基本功能的基础上,在实现返回栈中最小元素的操作。 要求 pop、push、getMin操作的时间复杂度都是O(1). 设计的栈类型可以使用现成的栈结构。 解答 在设计上我们使用两个栈,一个栈用来保存当前栈中的元素,其功能和一个正常的栈没有区别,这个栈记为stackData;另一个栈用于保存每一步的最小值,这个栈记为stackMin。具体实现的方式有两...

weixin_30662849的博客 205

一种导弹追踪算法的MATLAB仿真实现

以下是一个用于模拟机动变轨导弹和防空导弹追踪过程的 MATLAB 代码,同时会提供 3D 效果展示。你可以运行这段代码,从而观察机动变轨导弹和防空导弹的速度与位置变化。

SmartGridequation的博客 933

原理之(〇)3D Gaussian Splatting 数学原理与推导

3D Gaussian Splatting源于EWA的理论基础,本文重点从EWA模型出发,详细推导3D GS中的数学原理,加深对鱼眼相机畸变场景下的理解。

scott198512的博客 4157

包含min函数的栈 python_《剑指 Offer (第 2 版)》第 30 题:包含 min 函数的栈

第 30 题:定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的 min 函数设计一个支持 push,pop,top 等操作并且可以在 O(1) 时间内检索出最小元素的堆栈。push(x)–将元素x插入栈中pop()–移除栈顶元素top()–得到栈顶元素getMin()–得到栈中最小元素样例:MinStack minStack = new MinStack();minStack.push(...

weixin_39764603的博客 163

mindie部署qwen3-8b

2. 确认目录文件权限是否如下所示,若存在不匹配项,则参考以下命令修改权限。否则要stop容器之后重新start,重新从《以下是在容器中的操作》开始操作。ctrl +d 让命令停止之后,需要等待一段事件让其释放,否则还会有占用。1. 若安装路径为默认路径,执行如下命令,进入MindIE安装目录。# 配置CANN环境,默认安装在/usr/local目录下。3. 运行以下命令初始化各组件环境变量,并开启日志打印。如果报错,可能有些线程没法去除,删除容器重新操作。# 配置模型仓环境变量。以下是在容器中的操作。

andeyeluguo的博客 1035

增、删、最大最小O(1)数据结构-算法题

我的博客 359

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

初学C语言系列之函数

{statement;}return_value 返回值fun_name 函数名para 参数statement 语句项(函数体)函数的声明是向编译器指出有这个函数,说明函数的参数类型,返回类型,但是并不是函数具体存在。函数的声明一般会出现在函数之前,函数的使用是满足先声明后使用。函数的声明一般要放在头文件中。函数定义是向编译器指出函数的具体实现方式。//函数声明,说明了print函数返回类型是void,不需要参数。...

zhangsankuangtu的博客 995

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

实现GetMin功能的栈

【题目】 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的栈。 【要求】 1、pop、push、getMin操作的时间复杂度都为O(1) 2、设计的站类型可以使用现成的栈结构 栈的一些基本定义模板: //头文件 #include <stack> //模板<类型名> template <t...

暖心~的博客 623

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

函数<小罗爱c语言>

#include <stdio.h> #include <string.h> int a = 10; int b = 20; int max = 0; int getmax(int a,int b) { return(a>b)?(a):(b); } int main() { max=getmax(a,b); printf("%d\n",max); return 0; } 在c语言中一般分为两种库函数和自定义函数 #include <...

weixin_54718885的博客 527

C语言 函数

0718 第六章 一、函数的概念 函数:能够实现某种功能的代码模块 二、函数的定义 函数返回值类型 函数名(参数列表)//函数头 {语句;}//函数体 //参数用”,”分隔开。 返回值类型:void 数据类型。 //求两个整数的最大值。 int getmax(int a,int b) { int max=a>b?a:b; return max; } 函数声明时的参数:

qq_35575464的博客 804

加法和减法指令

根据目标操作数的值,溢出标志位,符号标志位,零标志位,辅助进位标志位,进位标志位和奇偶标志位会发生变化 1.INC 和 DEC 指令 INC(增加) DEC(减少)指令分别表示寄存器/内存当中的操作数+1/-1 INC mem/reg DEC mem/reg 二者不会影响进位标志位 2.ADD指令 将长度相同的源操作数和目的操作数相加,存放在目的操作数当中 ADD dest , source 3.SUB指令 长度相同的源操作数和目的操作数,从目的操作数中减去源操作数 SUB dest, source

ZZHinclude的博客 2710

asm:常见指令大全

常见指令大全 算数指令 INC 指令 DEC 指令 ADD 指令 SUB指令 MUL指令 IMUL指令 DIV指令 IDIV指令 逻辑指令 AND指令 OR指令 XOR 指令 TEST指令 NOT指令 跳转指令 条件跳转指令 无条件跳转指令

李白 3590

python习题

1、 定义一个getMax函数,返回三个数(键盘输入)中最大的值 def getMax(): a=int(input("请输入第一个数字")) b = int(input("请输入第二个数字")) c = int(input("请输入第三个数字")) if a>b and a>c: print("最大的数是",a) elif b>a and b>c: print("最大的数是",b) elif c>a and c&

`whyYa的博客 2234

Java~两种方案设计一个有getMin功能的栈

题目 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作. 要求 1.pop、push、getMin操作的时间复杂度都是O(1). 2.设计的栈类型可以使用现成的栈结构. 解题思路 在解决问题时,两种方案其实都是利用两个栈来实现,一个栈用来保存当前栈中的元素,其功能是一个正常的栈,将这个栈称为stackData;另一个栈用来保存每一步的最小值,这个栈称为stackMin。具体实现方式有两种.两种方案的其他方法均相同,只是压入数据和出栈的规则不同. 目录 初

qq_58284486的博客 1236

INC 和 DEC

<br />inc自增函数<br />1.inc(i,n);//i,n:integer;n为自增量<br />相当于i:=i+n;<br />2.inc(i);//i:integer;<br />相当于i:=i+1;<br /> <br />dec自减函数<br />1.dec(i,n);//i,n:integer;n为自减量<br />相当于i:=i-n;<br />2.dec(i);//i:integer;<br />相当于i:=i-1;

Eric For Study 2008

getMax

/*获取数组的中的最大值的方法 1.定义一个变量,存放初始值,初始值定为数组中的一个元素 2.用数组的元素和变量比,大的留下 3.输出最大值 */   class Max {  public static void main(String[] args)  {   int [] ar={1,5,596,85,65};   int max=getMax(ar);

ailiandeziwei的专栏 1462

【算法】设计一个getMin功能的栈

这个栈需要支持常规栈的操作, 并且还能支持当前栈中的最小元素操作。大小的数组, 实测可以开更小的数组, 足以应付测试用例。如果先前采用java内置栈的话, 效率肯定不如数组。既然是做算法题, 反正也是单线程, 直接开静态数组。说明了, 不过时间复杂度还是慢啊。本题只需要想好压入逻辑就非常简单。顺便优化以下push方法的逻辑。上面的栈是手动写的数组, 在。: 击败100%的人。

博客网站地址: https://arsenova.xyz 我会将优快云上的博客重修一部分迁移到网站上。 文章会做同步更新,但我不会在这个糟糕的平台多待1秒。下面是我要说的话,save your time. keep going 708

设计getMin功能的栈

描述 实现一个特殊功能的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。 输入描述: 第一行输入一个整数N,表示对栈进行的操作总数。 下面N行每行输入一个字符串S,表示操作的种类。 如果S为"push",则后面还有一个整数X表示向栈里压入整数X。 如果S为"pop",则表示弹出栈顶操作。 如果S为"getMin",则表示询问当前栈中的最小元素是多少。 输出描述: 对于每个getMin操作,输出一行表示当前栈中的最小元素是多少。 ...

Whynotwu的博客 314
下一篇: 用python从网易云音乐缓存文件中得到MP3
mbinary
博客等级 码龄9年 39粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值