# 【LeetCode】代码模板，刷题必会

1033 篇文章 85 订阅
901 篇文章 196 订阅

## 二分查找

def binary_search(l, r):
while l < r:
m = l + (r - l) // 2
if f(m):    # 判断找了没有，optional
return m
if g(m):
r = m   # new range [l, m)
else:
l = m + 1 # new range [m+1, r)


lower bound: find index of i, such that A[i] >= x

def lowwer_bound(self, nums, target):
# find in range [left, right)
left, right = 0, len(nums)
while left < right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
else:
right = mid
return left


upper bound: find index of i, such that A[i] > x

def higher_bound(self, nums, target):
# find in range [left, right)
left, right = 0, len(nums)
while left < right:
mid = left + (right - left) // 2
if nums[mid] <= target:
left = mid + 1
else:
right = mid
return left


class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
left, right = 0, x + 1
# [left, right)
while left < right:
mid = left + (right - left) // 2
if mid ** 2 == x:
return mid
if mid ** 2 < x:
left = mid + 1
else:
right = mid
return left - 1


## 排序的写法

C++的排序方法，使用sort并且重写comparator，如果需要使用外部变量，需要在中括号中放入&。

class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> m;
for (char c : s) ++m[c];
sort(s.begin(), s.end(), [&](char& a, char& b){
return m[a] > m[b] || (m[a] == m[b] && a < b);
});
return s;
}
};


## BFS的写法

# BFS
bfs = [target.val]
visited = set([target.val])
for k in range(K):
bfs = [y for x in bfs for y in conn[x] if y not in visited]
visited |= set(bfs)
return bfs


class Solution(object):
"""
:type beginWord: str
:type endWord: str
:type wordList: List[str]
:rtype: int
"""
wordset = set(wordList)
bfs = collections.deque()
bfs.append((beginWord, 1))
while bfs:
word, length = bfs.popleft()
if word == endWord:
return length
for i in range(len(word)):
for c in "abcdefghijklmnopqrstuvwxyz":
newWord = word[:i] + c + word[i + 1:]
if newWord in wordset and newWord != word:
wordset.remove(newWord)
bfs.append((newWord, length + 1))
return 0


778. Swim in Rising Water

class Solution(object):
def swimInWater(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
n = len(grid)
visited, pq = set((0, 0)), [(grid[0][0], 0, 0)]
res = 0
while pq:
T, i, j = heapq.heappop(pq)
res = max(res, T)
directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]
if i == j == n - 1:
break
for dir in directions:
x, y = i + dir[0], j + dir[1]
if x < 0 or x >= n or y < 0 or y >= n or (x, y) in visited:
continue
heapq.heappush(pq, (grid[x][y], x, y))
return res


847. Shortest Path Visiting All Nodes

class Solution(object):
def shortestPathLength(self, graph):
"""
:type graph: List[List[int]]
:rtype: int
"""
N = len(graph)
que = collections.deque()
step = 0
goal = (1 << N) - 1
visited = [[0 for j in range(1 << N)] for i in range(N)]
for i in range(N):
que.append((i, 1 << i))
while que:
s = len(que)
for i in range(s):
node, state = que.popleft()
if state == goal:
return step
if visited[node][state]:
continue
visited[node][state] = 1
for nextNode in graph[node]:
que.append((nextNode, state | (1 << nextNode)))
step += 1
return step


429. N-ary Tree Level Order Traversal多叉树的层次遍历，这个BFS写法我觉得很经典。适合记忆。

"""
# Definition for a Node.
class Node(object):
def __init__(self, val, children):
self.val = val
self.children = children
"""
class Solution(object):
def levelOrder(self, root):
"""
:type root: Node
:rtype: List[List[int]]
"""
res = []
que = collections.deque()
que.append(root)
while que:
level = []
size = len(que)
for _ in range(size):
node = que.popleft()
if not node:
continue
level.append(node.val)
for child in node.children:
que.append(child)
if level:
res.append(level)
return res


## DFS的写法

329. Longest Increasing Path in a Matrix

417. Pacific Atlantic Water Flow

778. Swim in Rising Water

class Solution(object):
def swimInWater(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
n = len(grid)
left, right = 0, n * n - 1
while left <= right:
mid = left + (right - left) / 2
if self.dfs([[False] * n for _ in range(n)], grid, mid, n, 0, 0):
right = mid - 1
else:
left = mid + 1
return left

def dfs(self, visited, grid, mid, n, i, j):
visited[i][j] = True
if i == n - 1 and j == n - 1:
return True
directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]
for dir in directions:
x, y = i + dir[0], j + dir[1]
if x < 0 or x >= n or y < 0 or y >= n or visited[x][y] or max(mid, grid[i][j]) != max(mid, grid[x][y]):
continue
if self.dfs(visited, grid, mid, n, x, y):
return True
return False


## 回溯法

753. Cracking the Safe

class Solution(object):
def crackSafe(self, n, k):
"""
:type n: int
:type k: int
:rtype: str
"""
res = ["0"] * n
size = k ** n
visited = set()
if self.dfs(res, visited, size, n, k):
return "".join(res)
return ""

def dfs(self, res, visited, size, n, k):
if len(visited) == size:
return True
node = "".join(res[len(res) - n + 1:])
for i in range(k):
node = node + str(i)
if node not in visited:
res.append(str(i))
if self.dfs(res, visited, size, n, k):
return True
res.pop()
visited.remove(node)
node = node[:-1]


312. Burst Balloons

class Solution(object):
def maxCoins(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
nums.insert(0, 1)
nums.append(1)
c = [[0] * (n + 2) for _ in range(n + 2)]
return self.dfs(nums, c, 1, n)

def dfs(self, nums, c, i, j):
if i > j: return 0
if c[i][j] > 0: return c[i][j]
if i == j: return nums[i - 1] * nums[i] * nums[i + 1]
res = 0
for k in range(i, j + 1):
res = max(res, self.dfs(nums, c, i, k - 1) + nums[i - 1] * nums[k] * nums[j + 1] + self.dfs(nums, c, k + 1, j))
c[i][j] = res
return c[i][j]

class Solution {
public:
int countArrangement(int N) {
int res = 0;
vector<int> visited(N + 1, 0);
helper(N, visited, 1, res);
return res;
}
private:
void helper(int N, vector<int>& visited, int pos, int& res) {
if (pos > N) {
res++;
return;
}
for (int i = 1; i <= N; i++) {
if (visited[i] == 0 && (i % pos == 0 || pos % i == 0)) {
visited[i] = 1;
helper(N, visited, pos + 1, res);
visited[i] = 0;
}
}
}
};


class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
const int N = nums.size();
vector<vector<int>> res;
vector<int> path;
vector<int> visited(N, 0);
dfs(nums, 0, visited, res, path);
return res;
}
private:
void dfs(vector<int>& nums, int pos, vector<int>& visited, vector<vector<int>>& res, vector<int>& path) {
const int N = nums.size();
if (pos == N) {
res.push_back(path);
return;
}
for (int i = 0; i < N; i++) {
if (!visited[i]) {
visited[i] = 1;
path.push_back(nums[i]);
dfs(nums, pos + 1, visited, res, path);
path.pop_back();
visited[i] = 0;
}
}
}
};


## 树

### 递归

617. Merge Two Binary Trees把两个树重叠，重叠部分求和，不重叠部分是两个树不空的节点。

class Solution:
def mergeTrees(self, t1, t2):
if not t2:
return t1
if not t1:
return t2
newT = TreeNode(t1.val + t2.val)
newT.left = self.mergeTrees(t1.left, t2.left)
newT.right = self.mergeTrees(t1.right, t2.right)
return newT


### 迭代

226. Invert Binary Tree

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
def invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
stack = []
stack.append(root)
while stack:
node = stack.pop()
if not node:
continue
node.left, node.right = node.right, node.left
stack.append(node.left)
stack.append(node.right)
return root


### 前序遍历

144. Binary Tree Preorder Traversal

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root: return []
res = []
stack = []
stack.append(root)
while stack:
node = stack.pop()
if not node:
continue
res.append(node.val)
stack.append(node.right)
stack.append(node.left)
return res



### 中序遍历

94. Binary Tree Inorder Traversal

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
stack = []
while True:
while root:
stack.append(root)
root = root.left
if not stack:
root = stack.pop()
root = root.right


### 后序遍历

145. Binary Tree Postorder Traversal

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if (!root) return res;
stack<TreeNode*> st;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top(); st.pop();
if (!node) continue;
res.push_back(node->val);
st.push(node->left);
st.push(node->right);
}
reverse(res.begin(), res.end());
return res;
}
};


## 构建完全二叉树

919. Complete Binary Tree Inserter

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class CBTInserter(object):

def __init__(self, root):
"""
:type root: TreeNode
"""
self.tree = list()
queue = collections.deque()
queue.append(root)
while queue:
node = queue.popleft()
self.tree.append(node)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)

def insert(self, v):
"""
:type v: int
:rtype: int
"""
_len = len(self.tree)
father = self.tree[(_len - 1) / 2]
node = TreeNode(v)
if not father.left:
father.left = node
else:
father.right = node
self.tree.append(node)
return father.val

def get_root(self):
"""
:rtype: TreeNode
"""
return self.tree[0]

# Your CBTInserter object will be instantiated and called as such:
# obj = CBTInserter(root)
# param_1 = obj.insert(v)
# param_2 = obj.get_root()


## 并查集

1. Accounts Merge
https://leetcode.com/articles/accounts-merge/
class DSU:
def __init__(self):
self.par = range(10001)

def find(self, x):
if x != self.par[x]:
self.par[x] = self.find(self.par[x])
return self.par[x]

def union(self, x, y):
self.par[self.find(x)] = self.find(y)

def same(self, x, y):
return self.find(x) == self.find(y)


C++版本如下：

vector<int> map_; //i的parent，默认是i
int f(int a) {
if (map_[a] == a)
return a;
return f(map_[a]);
}
void u(int a, int b) {
int pa = f(a);
int pb = f(b);
if (pa == pb)
return;
map_[pa] = pb;
}


684. Redundant Connection

class DSU(object):
def __init__(self):
self.par = range(1001)
self.rnk = [0] * 1001

def find(self, x):
if self.par[x] != x:
self.par[x] = self.find(self.par[x])
return self.par[x]

def union(self, x, y):
xr, yr = self.find(x), self.find(y)
if xr == yr:
return False
elif self.rnk[xr] < self.rnk[yr]:
self.par[xr] = yr
elif self.rnk[xr] > self.rnk[yr]:
self.par[yr] = xr
else:
self.par[yr] = xr
self.rnk[xr] += 1
return True


547. Friend Circles，代码如下：

class Solution(object):
def findCircleNum(self, M):
"""
:type M: List[List[int]]
:rtype: int
"""
dsu = DSU()
N = len(M)
for i in range(N):
for j in range(i, N):
if M[i][j]:
dsu.u(i, j)
res = 0
for i in range(N):
if dsu.f(i) == i:
res += 1
return res

class DSU(object):
def __init__(self):
self.d = range(201)
self.r = [0] * 201

def f(self, a):
return a if a == self.d[a] else self.f(self.d[a])

def u(self, a, b):
pa = self.f(a)
pb = self.f(b)
if (pa == pb):
return
if self.r[pa] < self.r[pb]:
self.d[pa] = pb
self.r[pb] += self.r[pa]
else:
self.d[pb] = pa
self.r[pa] += self.r[pb]


## 前缀树

208. Implement Trie (Prefix Tree)这个题是纯考Trie的。参考代码如下：

class TrieNode {
public:
vector<TrieNode*> child;
bool isWord;
TrieNode() : isWord(false), child(26, nullptr) {
}
~TrieNode() {
for (auto& c : child)
delete c;
}
};

class Trie {
public:
/** Initialize your data structure here. */
Trie() {
root = new TrieNode();
}

/** Inserts a word into the trie. */
void insert(string word) {
TrieNode* p = root;
for (char a : word) {
int i = a - 'a';
if (!p->child[i])
p->child[i] = new TrieNode();
p = p->child[i];
}
p->isWord = true;
}

/** Returns if the word is in the trie. */
bool search(string word) {
TrieNode* p = root;
for (char a : word) {
int i = a - 'a';
if (!p->child[i])
return false;
p = p->child[i];
}
return p->isWord;
}

/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
TrieNode* p = root;
for (char a : prefix) {
int i = a - 'a';
if (!p->child[i])
return false;
p = p->child[i];
}
return true;
}
private:
TrieNode* root;
};

/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* bool param_2 = obj.search(word);
* bool param_3 = obj.startsWith(prefix);
*/


677. Map Sum Pairs

class MapSum {
public:
/** Initialize your data structure here. */
MapSum() {}

void insert(string key, int val) {
int inc = val - vals_[key];
Trie* p = &root;
for (const char c : key) {
if (!p->children[c])
p->children[c] = new Trie();
p->children[c]->sum += inc;
p = p->children[c];
}
vals_[key] = val;
}

int sum(string prefix) {
Trie* p = &root;
for (const char c : prefix) {
if (!p->children[c])
return 0;
p = p->children[c];
}
return p->sum;
}
private:
struct Trie {
Trie():children(128, nullptr), sum(0){}
~Trie(){
for (auto child : children)
if (child) delete child;
children.clear();
}
vector<Trie*> children;
int sum;
};

Trie root;
unordered_map<string, int> vals_;
};


## 图遍历

743. Network Delay Time这个题很详细。

### Dijkstra算法

class Solution:
def networkDelayTime(self, times, N, K):
"""
:type times: List[List[int]]
:type N: int
:type K: int
:rtype: int
"""
K -= 1
nodes = collections.defaultdict(list)
for u, v, w in times:
nodes[u - 1].append((v - 1, w))
dist = [float('inf')] * N
dist[K] = 0
done = set()
for _ in range(N):
smallest = min((d, i) for (i, d) in enumerate(dist) if i not in done)[1]
for v, w in nodes[smallest]:
if v not in done and dist[smallest] + w < dist[v]:
dist[v] = dist[smallest] + w
return -1 if float('inf') in dist else max(dist)


### Floyd-Warshall算法

class Solution:
def networkDelayTime(self, times, N, K):
"""
:type times: List[List[int]]
:type N: int
:type K: int
:rtype: int
"""
d = [[float('inf')] * N for _ in range(N)]
for time in times:
u, v, w = time[0] - 1, time[1] - 1, time[2]
d[u][v] = w
for i in range(N):
d[i][i] = 0
for k in range(N):
for i in range(N):
for j in range(N):
d[i][j] = min(d[i][j], d[i][k] + d[k][j])
return -1 if float('inf') in d[K - 1] else max(d[K - 1])


### Bellman-Ford算法

class Solution:
def networkDelayTime(self, times, N, K):
"""
:type times: List[List[int]]
:type N: int
:type K: int
:rtype: int
"""
dist = [float('inf')] * N
dist[K - 1] = 0
for i in range(N):
for time in times:
u = time[0] - 1
v = time[1] - 1
w = time[2]
dist[v] = min(dist[v], dist[u] + w)
return -1 if float('inf') in dist else max(dist)


## 最小生成树

1135. Connecting Cities With Minimum Cost

### Kruskal算法

class Solution {
public:
static bool cmp(vector<int> & a,vector<int> & b){
return a[2] < b[2];
}

int find(vector<int> & f,int x){
while(x != f[x]){
x = f[x];
}
return x;
}

bool uni(vector<int> & f,int x,int y){
int x1 = find(f,x);
int y1 = find(f,y);
f[x1] = y1;

return true;
}

int minimumCost(int N, vector<vector<int>>& conections) {
int ans = 0;
int count = 0;
vector<int> father(N+1,0);

sort(conections.begin(),conections.end(),cmp);
for(int i = 0;i <= N; ++i){
father[i] = i;
}

for(auto conect : conections){
if(find(father,conect[0]) != find(father,conect[1])){
count++;
ans += conect[2];
uni(father,conect[0],conect[1]);
if(count == N-1){
return ans;
}
}
}

return -1;
}
};


### Prim算法

struct cmp {
bool operator () (const vector<int> &a, const vector<int> &b) {
return a[2] > b[2];
}
};

class Solution {
public:
int minimumCost(int N, vector<vector<int>>& conections) {
int ans = 0;
int selected = 0;
vector<vector<pair<int,int>>> edgs(N+1,vector<pair<int,int>>());
priority_queue<vector<int>,vector<vector<int>>,cmp> pq;
vector<bool> visit(N+1,false);

/*initial*/
for(auto re : conections){
edgs[re[0]].push_back(make_pair(re[1],re[2]));
edgs[re[1]].push_back(make_pair(re[0],re[2]));
}

if(edgs[1].size() == 0){
return -1;
}

/*kruskal*/
selected = 1;
visit[1] = true;
for(int i = 0;i < edgs[1].size(); ++i){
pq.push(vector<int>({1,edgs[1][i].first,edgs[1][i].second}));
}

while(!pq.empty()){
vector<int> curr = pq.top();
pq.pop();

if(!visit[curr[1]]){
visit[curr[1]] = true;
ans += curr[2];
for(auto e : edgs[curr[1]]){
pq.push(vector<int>({curr[1],e.first,e.second}));
}
selected++;
if(selected == N){
return ans;
}
}
}

return -1;
}
};


## 拓扑排序

BFS方式：

class Solution(object):
def canFinish(self, N, prerequisites):
"""
:type N,: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
graph = collections.defaultdict(list)
indegrees = collections.defaultdict(int)
for u, v in prerequisites:
graph[v].append(u)
indegrees[u] += 1
for i in range(N):
zeroDegree = False
for j in range(N):
if indegrees[j] == 0:
zeroDegree = True
break
if not zeroDegree: return False
indegrees[j] = -1
for node in graph[j]:
indegrees[node] -= 1
return True


DFS方式：

class Solution(object):
def canFinish(self, N, prerequisites):
"""
:type N,: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
graph = collections.defaultdict(list)
for u, v in prerequisites:
graph[u].append(v)
# 0 = Unknown, 1 = visiting, 2 = visited
visited = [0] * N
for i in range(N):
if not self.dfs(graph, visited, i):
return False
return True

# Can we add node i to visited successfully?
def dfs(self, graph, visited, i):
if visited[i] == 1: return False
if visited[i] == 2: return True
visited[i] = 1
for j in graph[i]:
if not self.dfs(graph, visited, j):
return False
visited[i] = 2
return True


BFS方式：

class Solution(object):
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: List[int]
"""
graph = collections.defaultdict(list)
indegrees = collections.defaultdict(int)
for u, v in prerequisites:
graph[v].append(u)
indegrees[u] += 1
path = []
for i in range(numCourses):
zeroDegree = False
for j in range(numCourses):
if indegrees[j] == 0:
zeroDegree = True
break
if not zeroDegree:
return []
indegrees[j] -= 1
path.append(j)
for node in graph[j]:
indegrees[node] -= 1
return path


DFS方式：

class Solution(object):
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: List[int]
"""
graph = collections.defaultdict(list)
for u, v in prerequisites:
graph[u].append(v)
# 0 = Unknown, 1 = visiting, 2 = visited
visited = [0] * numCourses
path = []
for i in range(numCourses):
if not self.dfs(graph, visited, i, path):
return []
return path

def dfs(self, graph, visited, i, path):
if visited[i] == 1: return False
if visited[i] == 2: return True
visited[i] = 1
for j in graph[i]:
if not self.dfs(graph, visited, j, path):
return False
visited[i] = 2
path.append(i)
return True


207. Course Schedule

210. Course Schedule II

310. Minimum Height Trees

## 双指针

int findSubstring(string s){
vector<int> map(128,0);
int counter; // check whether the substring is valid
int begin=0, end=0; //two pointers, one point to tail and one  head
int d; //the length of substring

for() { /* initialize the hash map here */ }

while(end<s.size()){

if(map[s[end++]]++ ?){  /* modify counter here */ }

while(/* counter condition */){

/* update d here if finding minimum*/

//increase begin to make it invalid/valid again

if(map[s[begin++]]-- ?){ /*modify counter here*/ }
}

/* update d here if finding maximum*/
}
return d;
}


424. 替换后的最长重复字符

class Solution(object):
def characterReplacement(self, s, k):
N = len(s)
left, right = 0, 0 # [left, right] 都包含
counter = collections.Counter()
res = 0
while right < N:
counter[s[right]] += 1
maxCnt = counter.most_common(1)[0][1]
while right - left + 1 - maxCnt > k:
counter[s[left]] -= 1
left += 1
res = max(res, right - left + 1)
right += 1
return res


## 动态规划

### 状态搜索

688. Knight Probability in Chessboard

62. Unique Paths

63. Unique Paths II

913. Cat and Mouse

576. Out of Boundary Paths

class Solution(object):
def findPaths(self, m, n, N, i, j):
"""
:type m: int
:type n: int
:type N: int
:type i: int
:type j: int
:rtype: int
"""
dp = [[0] * n for _ in range(m)]
for s in range(1, N + 1):
curStatus = [[0] * n for _ in range(m)]
for x in range(m):
for y in range(n):
v1 = 1 if x == 0 else dp[x - 1][y]
v2 = 1 if x == m - 1 else dp[x + 1][y]
v3 = 1 if y == 0 else dp[x][y - 1]
v4 = 1 if y == n - 1 else dp[x][y + 1]
curStatus[x][y] = (v1 + v2 + v3 + v4) % (10**9 + 7)
dp = curStatus
return dp[i][j]


## 贪心

1.贪心算法中，作出的每步贪心决策都无法改变，因为贪心策略是由上一步的最优解推导下一步的最优解，而上一部之前的最优解则不作保留。
2.由（1）中的介绍，可以知道贪心法正确的条件是：每一步的最优解一定包含上一步的最优解

1.全局最优解中一定包含某个局部最优解，但不一定包含前一个局部最优解，因此需要记录之前的所有最优解
2.动态规划的关键是状态转移方程，即如何由以求出的局部最优解来推导全局最优解
3.边界条件：即最简单的，可以直接得出的局部最优解

• 376
点赞
• 2298
收藏
觉得还不错? 一键收藏
• 37
评论
01-27
07-24
09-06 938
05-26 227
03-02
04-19 193
04-16 271
04-14 390

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

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

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