近期刷题总结(7月15 至 8月10日)

动态规划组

1. 数塔问题(动态规划 + 滚动数组)

经典dp了,学动态规划的第一道例题,给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

[2],
[3,4],
[6,5,7],
[4,1,8,3]

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/triangle

思路1
d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j + 1 ] ) + c [ i ] [ j ] dp[i][j] = min(dp[i-1][j], dp[i-1][j+1]) + c[i][j] dp[i][j]=min(dp[i1][j],dp[i1][j+1])+c[i][j]

关键是滚动数组在空间上的优化:通过转移方程可以看出,每一行的最小值,只与下一行有关,因此我们只需要使用2行的dp数组 d p [ 2 ] [ n ] dp[2][n] dp[2][n]即可,由于是枚举行号,因此我们利用行号的奇偶性来判断行号。

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int leng = triangle.size();
        if (leng == 1) return triangle[0][0];
        int dp[2][1007] = {0};
        int minValue = 99999;
        dp[0][0] = triangle[0][0];
        for(int i=1;i<leng;++i) {
        	// 特殊处理最左列
            dp[i & 1][0] = triangle[i][0] + dp[i-1 & 1][0];
            for (int j=1;j<i;++j) {
                dp[i & 1][j] = triangle[i][j] + min(dp[i-1 & 1][j-1], dp[i-1 & 1][j]);
            }
            // 特殊处理最右列
            dp[i & 1][i] = triangle[i][i] + dp[i-1 & 1][i-1];
        }
        for(int i=0;i<leng;++i) {
            minValue = min(dp[leng-1 & 1][i], minValue);
        }
        return minValue;
    }
};

思路2
自下而上,略


2. 不同的二叉搜索树1(动态规划 & 卡特兰数)

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/unique-binary-search-trees

思路:动态规划
在[1…n]中枚举i作为树根,然后递归的枚举[1…i-1],和[i+1…n]。
定义如下信息:

  1. G ( n ) G(n) G(n):长度为 n 的序列能构成的不同二叉搜索树的个数
  2. F ( i , n ) F(i, n) F(i,n)以i为根,序列长度为n的不同二叉搜索树个数

推出

  1. G ( n ) = Σ F ( i , n ) , 1 < = i < = n G(n) = \Sigma F(i,n),1<=i<=n G(n)=ΣF(i,n),1<=i<=n
  2. F ( i , n ) = G ( i − 1 ) ∗ G ( n − i ) F(i,n) = G(i-1) * G(n-i) F(i,n)=G(i1)G(ni)

把4式代入3式

G ( n ) = Σ G ( i − 1 ) ∗ G ( n − i ) G(n) = \Sigma{ G(i-1) * G(n-i) } G(n)=ΣG(i1)G(ni)

class Solution {
public:
    int numTrees(int n) {
        int g[20] = {1, 1};
        for (int i = 2; i <= n; ++ i) {
            for (int j = 1; j <= i; ++ j) {
                g[i] += g[j-1] * g[i-j];
            }
        }
        return g[n];
    }
};

3. 整数拆分(DP & 数学)

https://blog.csdn.net/swallowblank/article/details/107685100

4. 不同的二叉搜索树2(递归 & 记忆化搜索)

给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树 。

示例:

输入:3
输出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

思路:和上一题相似
我们枚举树根,并递归的生成左右子树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    vector<vector<vector<TreeNode*>>> globalTree;
public:
    
    vector<TreeNode*> generateTrees(int n) {
        if (n == 0) return {};
        globalTree.resize(n+1, vector<vector<TreeNode*>>(n+1));
        return back(1, n);
    }

    vector<TreeNode*> back(int start, int end) {
        if (start > end) return { nullptr };
        vector<TreeNode*> allTrees;
        if (!globalTree[start][end].empty()) {
            return globalTree[start][end];
        }
        for (int i=start; i<=end; ++i) {
            vector<TreeNode*> leftTree = back(start, i-1);
            vector<TreeNode*> rightTree = back(i+1, end);
            for (auto& leftpt : leftTree) {
                for (auto& rightpt : rightTree) {
                    allTrees.emplace_back(new TreeNode(i, leftpt, rightpt));
                }
            }
        }
        globalTree[start][end] = allTrees;
        return allTrees;
    }
};

5. 寻宝(状压DP)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xun-bao

这道题根本没想到状压DP,但是用状压BFS做出来了,但是超时了。

class Solution {

public:

    bool mark[100][100][1<<11][2];
    int M_id[103][103];
    int dir[4][2] = {
        {-1,0},
        {0,1},
        {1,0},
        {0,-1}
    };
    int sx,sy,ex,ey,M_num,target;
    struct node {
        int x, y;
        int state;
        int hasRock;
        int step;
        node(int a, int b, int c, int d, int e): x(a), y(b), state(c), hasRock(d), step(e) {}
    };
    int bfs (vector<string>& maze, int len) {
        node start = node(sx, sy, 0, 0, 0);
        queue<node> q;
        q.push(start);
        mark[start.x][start.y][start.state][start.hasRock] = true;
        while(!q.empty()) {
            node now = q.front(); q.pop();
            if (maze[now.x][now.y] == 'T' && mark[now.x][now.y][target][0] == true)
                return now.step;
            else {
                for (int i=0;i<4;++i) {
                    int new_x = now.x + dir[i][0];
                    int new_y = now.y + dir[i][1];
                    if (new_x < 0 || new_x >= len || new_y < 0 || new_y >= len || maze[new_x][new_y] == '#') {
                        continue;
                    }
                    int new_state = now.state, new_hasRock = now.hasRock;

                    if (maze[new_x][new_y] == 'O' && now.hasRock == 1) {
                        continue;
                    }
                    else if (maze[new_x][new_y] == 'O' && now.hasRock == 0 && now.state != target) {
                        new_hasRock = 1;
                    }
                    if (maze[new_x][new_y] == 'M' && now.hasRock == 1 && (now.state & (1 << M_id[new_x][new_y])) == 0) {
                        new_state = now.state | (1 << M_id[new_x][new_y]);
                        new_hasRock = 0;
                    }
                    if (mark[new_x][new_y][new_state][new_hasRock] == true) {
                        continue;
                    }
                    q.push(node(new_x,new_y,new_state,new_hasRock,now.step+1));
                    mark[new_x][new_y][new_state][new_hasRock] = true;
                }
            }
        }
        return -1;
    }

    int minimalSteps(vector<string>& maze) {
        memset(mark, false, sizeof(mark));
        memset(M_id, 0, sizeof(M_id));
        int len = maze.size();
        M_num = 0;
        for (int i=0; i<len; ++i) {
            for (int j=0;j<len;++j) {
                if (maze[i][j] == 'S') {
                    sx = i;
                    sy = j;
                }
                else if (maze[i][j] == 'T') {
                    ex = i;
                    ey = j;
                }
                else if (maze[i][j] == 'M') {
                    M_id[i][j] = M_num;
                    M_num += 1;
                }
            }
        }
        target = (1 << M_num) - 1;
        return bfs(maze, len);
    }
};

6. 打家劫舍3(DP思路 & 记忆化搜索)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:
输入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/house-robber-iii

思路:记忆化搜索

经典的拿和不拿问题,如果不拿当前的,则从四个孙子节点选最大的;如果拿当前的,则从两个子节点选最大的再加上自身。

这里我用了一个小技巧,很多题解都没有提到,就是在记忆化搜索中有一个很重要的点就是——在递归的时候判断当前节点是否已经被计算过,如果被计算过,那么直接返回,以避免重复计算。在一般的题目中,我们会用一个额外的数组visited来判断是否已经被完全计算,但此题由于是数值类型,我用负数来代表完全被计算过,在参与其他节点的运算时,只需取反恢复即可。

class Solution {
public:
    int get(TreeNode* root) {
        if (root == NULL) return 0;
        if (root->val < 0) return -(root->val);
        int b = 0;
        if (root->left != NULL) {
            root->val += get(root->left->left) + get(root->left->right);
        }
        if (root->right != NULL) {
            root->val += get(root->right->left) + get(root->right->right);
        }
        b += get(root->left) + get(root->right);
        root->val = -max(root->val, b);
        return -(root->val);
    }
    int rob(TreeNode* root) {
        return get(root);
    }
};

图论搜索组

1. 相同的树(DFS、BFS)【简单】

给定两个二叉树,编写一个函数来检验它们是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:
输入:       1         1
          / \       / \
         2   3     2   3
        [1,2,3],   [1,2,3]
输出: true

示例 2:
输入:      1          1
          /           \
         2             2
        [1,2],     [1,null,2]
输出: false

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/same-tree

思路:
没什么好说的, 两个指针同时指向两个数的根节点,同时dfs或bfs判断是否相同。

bool isSameTree(TreeNode* p, TreeNode* q) {
    if (p == nullptr && q == nullptr) {
        return true;
    } else if (p == nullptr || q == nullptr) {
        return false;
    } else if (p->val != q->val) {
        return false;
    } else {
        return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
}

2. 判断二分图(BFS & 染色)

给定一个无向图graph,当这个图为二分图时返回true。

如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。

graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。

示例 1:
输入: [[1,3], [0,2], [1,3], [0,2]]
输出: true
解释: 
无向图如下:
0----1
|    |
|    |
3----2
我们可以将节点分成两组: {0, 2} 和 {1, 3}。

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/is-graph-bipartite

思路:BFS

图的染色问题,对于图中的任意两个节点 uu 和 vv,如果它们之间有一条边直接相连,那么 uu 和 vv 必须属于不同的集合。

如果给定的无向图连通,那么我们就可以任选一个节点开始,给它染成红色。随后我们对整个图进行遍历,将该节点直接相连的所有节点染成绿色,表示这些节点不能与起始节点属于同一个集合。我们再将这些绿色节点直接相连的所有节点染成红色,以此类推,直到无向图中的每个节点均被染色。

如果我们能够成功染色,那么红色和绿色的节点各属于一个集合,这个无向图就是一个二分图;如果我们未能成功染色,即在染色的过程中,某一时刻访问到了一个已经染色的节点,并且它的颜色与我们将要给它染上的颜色不相同,也就说明这个无向图不是一个二分图。

class Solution {
public:
    int belong[107];
    bool BFS(int start, vector<vector<int>>& g) {
        queue<int> q;
        q.push(start);
        belong[start] = 0;
        while(!q.empty()) {
            int now = q.front();q.pop();
            for (auto i : g[now]) {
                if (belong[i] == -1) {
                    belong[i] = (belong[now]+1) & 1;
                    q.push(i);
                } else if (belong[i] != ((belong[now]+1) & 1)) {
                    return false;
                }
            }
        }
        return true;
    }

    bool isBipartite(vector<vector<int>>& graph) {
        int length = graph.size();
        memset(belong, -1, sizeof(belong));
        for ( int i = 0; i < length; ++ i) {
            if (graph[i].size() == 0) continue;
            else if (belong[i] == -1 && !BFS(i, graph)) return false;
        }
        return true;
    }
};

3. 课程表(判环 & DFS & BFS & 拓扑排序)

你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

示例 1:
输入: 2, [[1,0]] 
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。

示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/course-schedule

**思路:**判环 & DFS & BFS & 拓扑排序,我只写了深搜判环,广度后续可以再看看

这里主要要对节点做3类标记

  1. 未搜索
  2. 正在搜索,即还在遍历子节点
  3. 完成搜索,该节点的全部子节点遍历完毕

只有做三种标记才能判环,只有visited or !visited是不够的。

class Solution {
public:
    vector<int> visited;
    vector<vector<int>> g;

    bool dfs(int u) {
        visited[u] = 1;
        for (int v : g[u]) {
            if (visited[v] == 1) {
                return false;
            }
            else if (visited[v] == 2) {
                if(!dfs(v)) return false;
            }
        }
        visited[u] = 2;
        return true;
    }
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        if (numCourses == 1) return true;
        g.resize(numCourses);
        visited.resize(numCourses);
        for (auto &i: prerequisites) {
            g[i[1]].push_back(i[0]);
        }
        for(int i=0; i<numCourses; ++i) {
            if (visited[i] == 0) {
                if (dfs(i)) continue;
                else return false;
            }
        }
        return true;
    }
};

分治

1. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n=nums.size();
        if(n==0) return 0;
        int left=0,right=n-1;
        while(left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]<target) left=mid+1;
            else if(nums[mid]==target) return mid;
            else right=mid;
        }
        if(nums[left]<target) return n;
        return left;
    }
};

智商、数学题

1. 两数之和 II - 输入有序数组(双指针)

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

说明:

  • 返回的下标值(index1 和 index2)不是从零开始的。
  • 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:

输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted

思路双指针

使用双指针的实质是缩小查找范围。那么会不会把可能的解过滤掉?答案是不会。假设numbers[i]+numbers[j]=target 是唯一解,其中0≤i<j≤numbers.length−1。初始时两个指针分别指向下标 0和下标numbers.length−1,左指针指向的下标小于或等于 i,右指针指向的下标大于或等于 j。除非初始时左指针和右指针已经位于下标 i 和 j,否则一定是左指针先到达下标 i 的位置或者右指针先到达下标 j 的位置。

如果左指针先到达下标 i 的位置,此时右指针还在下标 j 的右侧,sum>target,因此一定是右指针左移,左指针不可能移到 ii 的右侧。

如果右指针先到达下标 j 的位置,此时左指针还在下标 i 的左侧,sum<target,因此一定是左指针右移,右指针不可能移到 j 的左侧。

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int length = numbers.size();
        vector<int> ans;
        int i = 0, j = length - 1;
        while(i < j) {
            if (numbers[i] + numbers[j] < target) {
                ++i;
            } else if (numbers[i] + numbers[j] > target) {
                --j;
            } else {
                ans.push_back(++i);
                ans.push_back(++j);
                return ans;
            }
        }
        return ans;
    }
};

2. 回文对(哈希/字典树 + 回文判断)【困难】

给定一组 互不相同 的单词, 找出所有不同 的索引对(i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。

示例 1:
输入:["abcd","dcba","lls","s","sssll"]
输出:[[0,1],[1,0],[3,2],[2,4]] 
解释:可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/palindrome-pairs

思路:这个题思路很重要
枚举每一个字符串s,再枚举s的每一个下标i,分别拆成前后缀t1,t2两个子串,再分别判断t1,t2是不是回文串,若是回文,判断另外一半子串是否在原数组中存在翻转。

算法实现用到的小技巧:

  • 其中判断是否存在翻转串,用到了hash结构unordered_map
  • 利用string_view代替strng进行大量的字符串操作,避免大量的耗时
class Solution {
private:
    vector<string> wordsRev;
    unordered_map<string_view, int> indices;

public:
    int findWord(const string_view& s, int left, int right) {
        auto iter = indices.find(s.substr(left, right - left + 1));
        return iter == indices.end() ? -1 : iter->second;
    }

    bool isPalindrome(const string_view& s, int left, int right) {
        int len = right - left + 1;
        for (int i = 0; i < len / 2; i++) {
            if (s[left + i] != s[right - i]) {
                return false;
            }
        }
        return true;
    }

    vector<vector<int>> palindromePairs(vector<string>& words) {
        int n = words.size();
        for (const string& word: words) {
            wordsRev.push_back(word);
            reverse(wordsRev.back().begin(), wordsRev.back().end());
        }
        for (int i = 0; i < n; ++i) {
            indices.emplace(wordsRev[i], i);
        }

        vector<vector<int>> ret;
        for (int i = 0; i < n; i++) {
            int m = words[i].size();
            if (!m) {
                continue;
            }
            string_view wordView(words[i]);
            for (int j = 0; j <= m; j++) {
                if (isPalindrome(wordView, j, m - 1)) {
                    int left_id = findWord(wordView, 0, j - 1);
                    if (left_id != -1 && left_id != i) {
                        ret.push_back({i, left_id});
                    }
                }
                if (j && isPalindrome(wordView, 0, j - 1)) {
                    int right_id = findWord(wordView, j, m - 1);
                    if (right_id != -1 && right_id != i) {
                        ret.push_back({right_id, i});
                    }
                }
            }
        }
        return ret;
    }
};

3. 整数拆分

https://blog.csdn.net/swallowblank/article/details/107685100

4. 计数二进制子串(脑筋急转弯)

给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。重复出现的子串要累计它们出现的次数。

示例 1 :
输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。

请注意,一些重复出现的子串要累计它们出现的次数。
另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/count-binary-substrings
思路:
我们可以将字符串 s 按照 0 和 1 的连续段分组,存在counts 数组中,例如 s = 00111011,可以得到这样的counts 数组:counts={2,3,1,2}。
它们能组成的满足条件的子串数目为 min{u,v},即一对相邻的数字对答案的贡献。

class Solution {
public:
    int countBinarySubstrings(string s) {
        vector<int> counts;
        int ptr = 0, n = s.size();
        while (ptr < n) {
            char c = s[ptr];
            int count = 0;
            while (ptr < n && s[ptr] == c) {
                ++ptr;
                ++count;
            }
            counts.push_back(count);
        }
        int ans = 0;
        for (int i = 1; i < counts.size(); ++i) {
            ans += min(counts[i], counts[i - 1]);
        }
        return ans;
    }
};

模拟

1. 大数加法(如何优雅的书写,是一个好题)

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。

提示:

num1 和num2 的长度都小于 5100
num1 和num2 都只包含数字 0-9
num1 和num2 都不包含任何前导零
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/add-strings

我写的和标准答案是有很大差距

#include<cstring>
using namespace std;
class Solution {
public:
    string addStrings(string num1, string num2) {
        string ans;
        int end_1 = num1.size();
        int end_2 = num2.size();
        int i = end_1 - 1;
        int j = end_2 - 1;
        int k = 0;
        for (;i>=-1 && j >=-1;) {
            int now;
            if (i<0 && j >= 0) {
                now = num2[j] - '0';
            }
            else if (i>=0 && j<0) {
                now = num1[i] - '0';
            } else if (i >= 0 && j >=0) 
                now = num1[i] - '0' + num2[j] - '0';
            if (i<0 && j<0 && k == 0) break;
            if (i<0 && j<0 && k != 0)
                now = 0;
            
            now += k;
            if (now >= 10) {
                ans.push_back('0'+(now-10));
                k = 1;
            } else {
                ans.push_back('0'+now);
                k = 0;
            }
            if (i > -1) 
                i --;
            if (j>-1)
                j --;
        }
        string aans;
        for (int i=ans.size()-1;i>=0;i--) {
            aans.push_back(ans[i]);
        }
        return aans;
    }
};

标答

class Solution {
public:
    string addStrings(string num1, string num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        string ans = "";
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1[i] - '0' : 0;
            int y = j >= 0 ? num2[j] - '0' : 0;
            int result = x + y + add;
            ans.push_back('0' + result % 10);
            add = result / 10;
            i -= 1;
            j -= 1;
        }
        // 计算完以后的答案需要翻转过来
        reverse(ans.begin(), ans.end());
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值