【LeetCode】005——最长回文子串(详解)

题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

  • 输入: “babad”
  • 输出: “bab”

注意: “aba” 也是一个有效答案。

示例 2:

  • 输入: “cbbd”
  • 输出: “bb”

解题思路

1、暴力解

  最容易想到的就是暴力解,求出原字符串s的每一个子串,然后再判断是不是回文,找到最长的那个即可。

class Solution {
	//判断字符串是否为回文
    public static boolean judge(String s){
        StringBuffer sb = new StringBuffer(s);
        sb.reverse();
        String str = new String(sb);
        if(s.equals(str)){
            return true;
        }
        return false;
    }
    public String longestPalindrome(String s){
        int l = s.length();
        //如果字符串长度小于2,即返回该字符串
        if(l < 2){
            return s;
        }
        //通过两个for循环获取每个子串并判断是否为回文
        //这里由最长子串到最短子串,因此当遇到第一个子串为回文,即是最长回文子串
        for(int i = l; i > 0; i--){
            for(int j = 0; j <= l - i; j++){
                String str = s.substring(j, j + i);
                if(judge(str)){
                    return str;
                }
            }
        }
        return s;
    }
}

求每一个子串通过两个for循环实现,时间复杂度为 O ( N 2 ) O(N^2) O(N2),判断子串是否为回文的时间复杂度为 O ( N ) O(N) O(N),因此暴力解的时间复杂度为 O ( N 3 ) O(N^3) O(N3),此算法的复杂度太高,很显然不会让面试官满意

2、动态规划

在这里插入图片描述
  对于字符串 S S S ,假设 f [ i ] [ j ] f[i][j] f[i][j] 表示字符串 S S S 下标从 i i i j j j 的子串是否是回文子串

  • 如果 f [ i ] [ j ] f[i][j] f[i][j] 是回文,那么 f [ i + 1 ] [ j − 1 ] f[i+1][j-1] f[i+1][j1] 一定是回文子串
  • 如果 f [ i + 1 ] [ j − 1 ] f[i+1][j-1] f[i+1][j1] 不是回文,那么 f [ i ] [ j ] f[i][j] f[i][j] 一定不是回文子串

  那么最长回文子串就能分解成一系列子问题,可以利用动态规划求解了。由此我们可以得到动态规划的递归方程:

f [ i ] [ j ] = { f [ i + 1 ] [ j − 1 ] , S [ i ] = S [ j ] f a l s e , S [ i ] 不 等 于 S [ j ] f[i][j]=\begin{cases} f[i+1][j-1] &amp;,S[i]=S[j] \\ false &amp;,S[i] 不等于 S[j] \\ \end{cases} f[i][j]={f[i+1][j1]false,S[i]=S[j],S[i]S[j]

初始状态

{ f [ i ] [ i ] = t r u e f [ i ] [ i + 1 ] = t r u e   i f   S [ i ] = = S [ i + 1 ] \begin{cases} f[i][i]=true \\ f[i][i+1]=true \ if \ S[i]==S[i+1]\\ \end{cases} {f[i][i]=truef[i][i+1]=true if S[i]==S[i+1]

  • f [ i ] [ i ] = t r u e f[i][i]=true f[i][i]=true 表示单个字符为回文
  • f [ i ] [ i + 1 ] = t r u e   i f   S [ i ] = = S [ i + 1 ] f[i][i+1]=true \ if \ S[i]==S[i+1] f[i][i+1]=true if S[i]==S[i+1] 表示两个相连字符为回文

C++代码:

class Solution {
public:
    string longestPalindrome(string s)
    {
        //如果字符串为空,那么返回空
        if (s.empty()) return "";
        //字符串长度
        int len = s.size();
        //单个字符
        if (len == 1) return s;
        //保存最长回文子串长度
        int longest = 1;
        //保存最长回文子串起点
        int start=0;
        //定义了一个vector容器,元素类型为vector<int>,初始化为包含len个vector<int>对象,
        //每个对象都是一个新创立的vector<int>对象的拷贝,而这个新创立的vector<int>对象被初始化为包含len个0。
        //类似于创建了一个lenxlen的二维数组,可以通过dp[i][j]的方式来访问元素
        vector<vector<int>> dp(len,vector<int>(len));
        //初始条件
        for (int i = 0; i < len; i++)
        {
            //二维数组对角线为单个字符,都为1
            dp[i][i] = 1;
            if(i<len-1)
            {
                if (s[i] == s[i + 1])//两个相连字符相同
                {
                    dp[i][i + 1] = 1;//为回文,标为1
                    start=i;//变更起始位置
                    longest=2;//最长回文子串长度为2
                }
            }
        }
        //字符串长度>=3
        for (int l = 3; l <= len; l++)//遍历每种子串长度
        {
            for (int i = 0; i+l-1 < len; i++)//枚举子串的起始点
            {
                int j=l+i-1;//终点
                if (s[i] == s[j] && dp[i+1][j-1]==1) //如果子串两端字符相同,并且去掉两端字符的子串是回文子串
                {
                    dp[i][j] = 1;//此时该子串为回文,标为1
                    start=i;//更新开始位置
                    longest = l;//更新最长长度
                }
            }
        }
        return s.substr(start,longest);//截取字符串中有start开始,截取longest个字符
    }
};

Java代码:

class Solution {
    public String longestPalindrome(String s) {
        if("".equals(s)){
            return "";
        }
        
        int len = s.length();
        if(len == 1){
            return s;
        }
        int sLength = 1;
        int start = 0;
        int[][] dp = new int[len][len];
        for(int i = 0; i < len; i++){
            dp[i][i] = 1;
            if(i < len - 1 && s.charAt(i) == s.charAt(i+1)){
                dp[i][i+1] = 1;
                sLength = 2;
                start = i;
            }
        }
        for(int l = 3; l <= len; l++){
            for(int i = 0; i + l -1 < len; i++){
                int j = i + l - 1;
                if(s.charAt(i) == s.charAt(j) && dp[i+1][j-1] == 1){
                    dp[i][j] = 1;
                    start = i;
                    sLength = l;
                }
            }
        }
        return s.substring(start,start+sLength);
    }
}

Python3代码:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)  # 计算字符串长度
        if length == 0:
            return ""
        if length == 1:
            return s
        
        sLength = 1
        start = 0
        dp = [[0 for i in range(length)] for j in range(length)]  # 创建二维数组,初始化为0
        for i in range(0, length):
            dp[i][i] = 1
            if i < length - 1 and s[i] == s[i+1]:
                dp[i][i+1] = 1
                sLength = 2
                start = i

        for l in range(3, length+1):
            for i in range(0, length-l+1):
                j = i + l - 1
                if s[i] == s[j] and dp[i+1][j-1] == 1:
                    dp[i][j] = 1
                    start = i
                    sLength = l
                    
        return s[start : start+sLength]
3、中心扩展法

  中心扩展法的思想是,遍历到数组的某一个元素时,以这个元素为中心,向两边进行扩展,如果两边的元素相同则继续扩展,否则停止扩展。算法复杂度为 O ( N 2 ) O(N^2) O(N2)

如下图:当遍历到3时

在这里插入图片描述

但是单个字符扩展存在缺陷,当字符串长度为偶数时,例如:1221

1,2,2,1是一个回文串,然而找不到对称中心,这样以一个元素为中心向两边扩展就不好用了

  • 1、分别以单个字符和相邻两个字符为中心扩展(下面代码使用的是此方法)
  • 2、对1,2,2,1进行填充,比如说用#进行填充得到:#,1,#,2,#,2,#,1,#

Java代码:

class Solution {
    public String longestPalindrome(String s) {
        
        if(s == null || s.length() < 1)
            return "";
        int start = 0;
        int end = 0;
        //中心扩展法,依次遍历中心点
        for(int i = 0; i < s.length(); i++){
            //求扩展中心的长度
            int len1 = expandLen(s, i, i);  //以每个字符为中心
            int len2 = expandLen(s, i, i+1);  //以每相邻两字符作为中心
            int len = Math.max(len1, len2);
            if(len > end - start){
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end+1);
        
    }
    
    public int expandLen(String s, int L, int R){
        int left = L;
        int right = R;
        while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        return right - left - 1;
    }
}

在这里插入图片描述
C++代码:

class Solution {
public:
    string longestPalindrome(string s) {
        int len=s.size();
        if(len==0||len==1)
            return s;
        int start=0;//记录回文子串起始位置
        int end=0;//记录回文子串终止位置
        int mlen=0;//记录最大回文子串的长度
        for(int i=0;i<len;i++)
        {
            int len1=expendaroundcenter(s,i,i);
            int len2=expendaroundcenter(s,i,i+1);
            mlen=max(max(len1,len2),mlen);
            if(mlen>end-start+1)
            {
                start=i-(mlen-1)/2;
                end=i+mlen/2;
            }
        }
        return s.substr(start,mlen);
        //该函数的意思是获取从start开始长度为mlen长度的字符串
    }
private:
    int expendaroundcenter(string s,int left,int right)
    //计算以left和right为中心的回文串长度
    {
        int L=left;
        int R=right;
        while(L>=0 && R<s.length() && s[R]==s[L])
        {
            L--;
            R++;
        }
        return R-L-1;
    }
};

Python3代码:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        def expand(s, left, right):
            while left >= 0 and right < len(s) and s[left] == s[right]:
                left -= 1
                right += 1
            return right - left - 1
        
        start = 0
        end = 0
        for i in range(len(s)):
            len1 = expand(s, i, i)
            len2 = expand(s, i, i+1)
            max_len = max(len1, len2)
            if max_len > end - start:
                start = i - int((max_len-1)/2)
                end = i + int(max_len/2)
        return s[start : end+1]

Manacher算法

直接通过例子来说明:

在这里插入图片描述

Manacher算法的核心思想,就是利用前面遍历的时候产生的回文子串

1、原理

在这里插入图片描述

如上图:

  • i d x idx idx 表示为蓝色回文子串的对称轴(已知)
  • 现在求以 c u r cur cur 为对称轴的回文子串(未知)
  • p r e pre pre 为以 i d x idx idx 为对称轴, c u r cur cur 的对称位置(遍历到 c u r cur cur p r e pre pre就已知了)

情况一: i ′ i&#x27; i 的回文子串超出 i d x idx idx 的回文子串的左边界

在这里插入图片描述

已知 i d x idx idx 为蓝色块子串的中心轴,现在求以i为中心轴的回文子串

  • i i i 处于以 i d x idx idx 为中心轴的回文子串中, i ′ i&#x27; i i i i 关于 i d x idx idx 的对称点,且以 i ′ i&#x27; i 为中心轴的回文子串已知(橘黄色块)
  • 其中 i i i 指向 c c c i ′ i&#x27; i 指向 b b b i d x idx idx 指向 e e e(小写字符为变量,大写字母为具体字符)
  • 那么由 e e e 为中心的回文子串中得知, b = c b=c b=c
  • 又因为 i d x idx idx 的回文不包括 a a a d d d,所以 a ! = d a !=d a!=d a = d a=d a=d 时,以 i d x idx idx 的回文子串还要扩展下去)
  • 又因为 i d x idx idx 左到 b b b i d x idx idx右到 c c c 相等的,且 a ! = d a!=d a!=d,所以以 c c c 为中心轴的回文半径只有 i d x 右 − l o c a t i o n ( c ) idx右-location(c) idxlocation(c)
  • a a a 关于以 b b b 为中心的回文的对称点为 a ′ a&#x27; a a ′ a&#x27; a e e e 为中心轴的回文的对称点为 a ′ ′ a&#x27;&#x27; a,那么 a = a ′ = a ′ ′ ! = d a=a&#x27;=a&#x27;&#x27;!=d a=a=a!=d

举例说明:

由于存在字符串长度为偶数和奇数,我们使用#填充,如下:
在这里插入图片描述

  • 当遍历到13号B时,以9号D为中心轴的回文子串从2号到16号(由于前面已经遍历过,已知),长度为 16 − 2 + 1 = 15 16-2+1=15 162+1=15
  • 以5号B为中心轴的回文子串从0号到10号(已知),长度为 10 − 0 + 1 = 11 10-0+1=11 100+1=11
  • 13号B关于9号D的对称点为5号B,现在要求以13号B为对称轴的回文子串


1号D和17号E不相等,现在只要盘判定以13号B为中心轴的回文子串是否包含17号

  • 如果包括17号E,那么它关于13号B对称的点就是9号D,而9号D关于5号B的对称点就是1号D
  • 根据对称性可知,17号E应该等于9号D等于1号D,很显然不相等


所以以13号B为中心轴的回文子串不包括17号E,又根据以5号B和9号D为中心轴的回文子串可知:

  • 2号#到5号B等于8号#到5号B
  • 10号#到13号B等于16号#到13号B

情况二: i ′ i&#x27; i 的回文子串 i d x idx idx 的回文子串包含

在这里插入图片描述

已知 i i i 关于 i d x idx idx 为中心轴的对称点 i ′ i&#x27; i 的最大回文子串如上图

  • 因为 i ′ i&#x27; i 的回文子串不包括 a , b a,b a,b a ! = b a!=b a!=b
  • 又因为 a , d a,d a,d b , c b,c b,c 分别关于 i d x idx idx对称,记 b = c , a = d b=c,a=d b=c,a=d ,所以 c ! = d c!=d c!=d
  • 又因为在 c c c d d d 之间是回文,原因在于 c c c d d d 之间的字符关于 i d x idx idx a a a b b b 之间对称,且 a a a b b b 之间是回文串,所以, c c c d d d 之间也是回文串。所以 i i i 的回文子串的长度和 i ′ i&#x27; i 相同

举例说明:
在这里插入图片描述

情况三: i ′ i&#x27; i 的回文子串的左边界与 i d x idx idx 的回文子串的左边界重合

在这里插入图片描述

i d x idx idx 为中心轴的回文子串可知, b = c , a ! = d b=c,a!=d b=c,a!=d,且 i ′ i&#x27; i 的回文长度在 a a a b b b 之间(不包括 a , b a,b a,b

那么 i i i 的回文子串的长度至少如上图所示

  • c = d c=d c=d 时,关于 i i i 为中心轴的回文还是可以扩展的
  • c ! = d c!=d c!=d 则刚好是上图所示的。

举例说明(c=d时):

在这里插入图片描述

i i i 关于 i d x idx idx 的对称点 i ′ i&#x27; i 的最长回文子串如上图,且 i ′ i&#x27; i 的回文左边界与 i d x idx idx 重合,所以 i i i 为中心的回文需要从蓝色框边界开始在往左右两边试着扩展

情况四: i ′ i&#x27; i 的回文子串没有被 i d x idx idx 的回文子串包含

在这里插入图片描述

此时,我们没有任何信息可以利用,只能以 i i i 为中心轴,向左右两边扩展。找出它的最长回文子串。

2、C++代码
class Solution {
public:
    string longestPalindrome(string s) {
        //计算字符串长度
        int n = s.size();
        if(n <= 1) return s;
        //生成一个字符串str包含2*n+1个字符0
        string str(2*n+1,'0');
        bool flag = 1;
        int j = 0;
        int maxIdx = 0;
        //填充字符,得到形如:#1#2#3#2#1# 的字符串
        for(int i=0; i<2*n+1; i++){
           if(flag){
               str[i]='#';
               flag = false;
           }else{
               str[i] = s[j++];
               flag = true;
           }
        }
        //表示以i为中心轴的回文子串的半径,不包含对称轴
        //如abcdcba,d的下标为4,radius[4] = 3,radius[0] = 0
        vector<int> radius(2*n+1,0); 
        int idx = 0; //表示上一次回文子串的中心轴下标
        int rad = 1; //idx能够包含最大的范围的下一个字符下标
        for(int i=1; i<2*n+1; i++){
            //情况四
            if(i >= rad){
                forceExtend(str, radius, idx, rad, i);
                maxIdx = (radius[i] > radius[maxIdx] ? i : maxIdx);
            }else if(i < rad){
                int j = 2*idx - i; //i关于idx的对称点j
                int idx_radius = idx - radius[idx]; //idx回文子串的左边界下标
                int j_radius = j - radius[j];//j的回文子串的左边界下标
                if(j_radius > idx_radius){ //情况二
                    radius[i] = radius[j];  //i的回文子串和其关于idx对称点的回文子串长度一样
                }else if(j_radius < idx_radius){//情况一
                    radius[i] = idx + radius[idx] - i;//idx的右边界下标-i下标
                }else{ //情况三
                    radius[i] = idx + radius[idx] - i;//至少
                    int count = 1;
                    //相等时,继续扩展
                    while((i + radius[i] + count) <= str.size()
                          && (i - radius[i] - count) >= 0
                          && str[i + radius[i] + count] == str[i - radius[i] - count]){
                        count++;
                    }
                    //不等时
                    radius[i] += (count - 1);
                    //更新最长回文子串中心和右边界下一个字符下标
                    if(i + radius[i] >= rad){
                        idx = i;
                        rad = i + count;
                    }
                }
                //更新最长回文子串的中心
                maxIdx = (radius[i] > radius[maxIdx] ? i : maxIdx);
            }
            
        }
        
        string ret = getMaxSubString(str, maxIdx, radius[maxIdx]);
        return ret;
    }
    //情况四
    void forceExtend(const string& str, vector<int>& radius, int &idx, int &rad, const int k){
        int count = 1;
        while((k - count) >=0 
              && (k + count) < str.size() 
              && str[k - count] == str[k + count]){
            count++;
        }
        radius[k] = count - 1;
        if((k + radius[k]) >= rad){
            idx = k;
            rad = k + count;
        }
    }
    //求出最长回文子串
    string getMaxSubString(const string &str,const int k,const int r){
        string ret(r, '0');
        int j = 0;
        for(int i = k-r+1; i <= k+r; i+=2){
            ret[j++] = str[i];
        }
        return ret;
    }
    
};
3、Java代码
public class Solution {
    public static String longestPalindrome(String s) {
        int n = s.length();
        if (n <= 1) return s ;
        
        StringBuilder strb = new StringBuilder();
        strb.append("#");
        for (int i = 0; i < s.length(); i++) {
            strb.append(s.charAt(i));
            strb.append("#");
        }
        
        int len = strb.length();
        int[] radius = new int[len];
        int idx = 0; //表示上一次回文子串的中心轴下标
        int rad = 1; //idx能够包含最大的范围的下一个字符下标
        int j = 0;
        int maxIdx = 0;
        for (int i = 1; i < len; i++) {
            //情况四
            if(i >= rad){
                int count = 1;
                while((i - count) >=0 
                      && (i + count) < strb.length()
                      && strb.charAt(i - count) == strb.charAt(i + count)){
                    count++;
                }
                radius[i] = count - 1;
                if((i + radius[i]) >= rad){
                    idx = i;
                    rad = i + count;
                }
                maxIdx = (radius[i] > radius[maxIdx] ? i : maxIdx);
            }else if(i < rad){
                j = 2*idx - i; //i关于idx的对称点j
                int idx_radius = idx - radius[idx]; //idx回文子串的左边界下标
                int j_radius = j - radius[j];//j的回文子串的左边界下标
                if(j_radius > idx_radius){ //情况二
                    radius[i] = radius[j];  //i的回文子串和其关于idx对称点的回文子串长度一样
                }else if(j_radius < idx_radius){//情况一
                    radius[i] = idx + radius[idx] - i;//idx的右边界下标-i下标
                }else{ //情况三
                    radius[i] = idx + radius[idx] - i;//至少
                    int count2 = 1;
                    //相等时,继续扩展
                    while((i + radius[i] + count2) < len
                          && (i - radius[i] - count2) >= 0
                          && strb.charAt(i + radius[i] + count2) == strb.charAt(i - radius[i] - count2)){
                        count2++;
                    }
                    //不等时
                    radius[i] += (count2 - 1);
                    //更新最长回文子串中心和右边界下一个字符下标
                    if(i + radius[i] >= rad){
                        idx = i;
                        rad = i + count2;
                    }
                }
                //更新最长回文子串的中心
                maxIdx = (radius[i] > radius[maxIdx] ? i : maxIdx);
            }
        }        
        StringBuilder ret = new StringBuilder();
        for(int i = maxIdx-radius[maxIdx]+1; i <= maxIdx + radius[maxIdx]; i+=2){
            ret.append(strb.charAt(i));
        }
        return ret.toString();
    }
}
4、Python3代码
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n <= 1:
            return s
        st = '#' + '#'.join(s) + '#'
        sLen = len(st)
        radius = [0] * sLen
        idx = 0
        rad = 1
        maxIdx = 0
        for i in range(1, sLen):
            if i >= rad:
                count = 1
                while (i - count) >= 0 and (i + count) < sLen and st[i - count] == st[i + count]:
                    count += 1
                radius[i] = count - 1
                if (i + radius[i]) >= rad:
                    idx = i
                    rad = i + count
                maxIdx = i if (radius[i] > radius[maxIdx]) else maxIdx
            elif i < rad:
                j = 2 * idx - i
                idx_radius = idx - radius[idx]
                j_radius = j - radius[j]
                if j_radius > idx_radius:
                    radius[i] = radius[j]
                elif j_radius < idx_radius:
                    radius[i] = idx + radius[idx] - i
                else:
                    radius[i] = idx + radius[idx] - i
                    count2 = 1
                    while (i + radius[i] + count2) < sLen and (i - radius[i] - count2) >= 0 and st[i + radius[i] + count2] == st[i - radius[i] - count2]:
                        count2 += 1
                    radius[i] += (count2 - 1)
                    if (i + radius[i]) >= rad:
                        idx = i
                        rad = i + count2
                maxIdx = i if (radius[i] > radius[maxIdx]) else maxIdx

        ret = []
        for i in range(maxIdx-radius[maxIdx]+1, maxIdx + radius[maxIdx]+1, 2):
            ret.append(st[i])
        return ''.join(ret)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,有三种方法可以解决LeetCode上的最长回文子串问题。 方法一是使用扩展中心法优化,即从左向右遍历字符串,找到连续相同字符组成的子串作为扩展中心,然后从该中心向左右扩展,找到最长的回文子串。这个方法的时间复杂度为O(n²)。\[1\] 方法二是直接循环字符串,判断子串是否是回文子串,然后得到最长回文子串。这个方法的时间复杂度为O(n³),效率较低。\[2\] 方法三是双层for循环遍历所有子串可能,然后再对比是否反向和正向是一样的。这个方法的时间复杂度也为O(n³),效率较低。\[3\] 综上所述,方法一是解决LeetCode最长回文子串问题的最优解法。 #### 引用[.reference_title] - *1* [LeetCode_5_最长回文子串](https://blog.csdn.net/qq_38975553/article/details/109222153)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode-最长回文子串](https://blog.csdn.net/duffon_ze/article/details/86691293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [LeetCode 第5题:最长回文子串(Python3解法)](https://blog.csdn.net/weixin_43490422/article/details/126479629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值