415. 字符串相加
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
示例 1:
输入:num1 = “11”, num2 = “123”
输出:“134”
示例 2:
输入:num1 = “456”, num2 = “77”
输出:“533”
示例 3:
输入:num1 = “0”, num2 = “0”
输出:“0”
提示:
1
<
=
n
u
m
1.
l
e
n
g
t
h
,
n
u
m
2.
l
e
n
g
t
h
<
=
1
0
4
1 <= num1.length, num2.length <= 10^4
1<=num1.length,num2.length<=104
num1 和num2 都只包含数字 0-9
num1 和num2 都不包含任何前导零
主要思路:保留一个进位位add,取模是当前位结果,做除法是进位结果。
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
string addStrings(string num1, string num2) {
int i = num1.size() - 1, j = num2.size() - 1, add = 0;
string res;
while (i >= 0 || j >= 0 || add > 0)
{
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int z = x + y + add;
res.push_back(z % 10 + '0');
add = z / 10;
i--;
j--;
}
reverse(res.begin(), res.end());
return res;
}
};
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
示例 1:
输入: num1 = “2”, num2 = “3”
输出: “6”
示例 2:
输入: num1 = “123”, num2 = “456”
输出: “56088”
提示:
1 <= num1.length, num2.length <= 200
num1 和 num2 只能由数字组成。
num1 和 num2 都不包含任何前导零,除了数字0本身。
主要思路就是按照竖式乘法进行模拟,代码如下:
class Solution
{
string addStrings(string num1, string num2)
{
if (num1 == "0" || num2 == "0")
{
return "0";
}
int i = num1.size() - 1, j = num2.size() - 1, add = 0;
string res;
while (i >= 0 || j >= 0 || add > 0)
{
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int z = x + y + add;
res.push_back(z % 10 + '0');
add = z / 10;
i--;
j--;
}
reverse(res.begin(), res.end());
return res;
}
public:
string multiply(string num1, string num2)
{
string res = "0";
for (int i = num2.size() - 1; i >= 0; i--)
{
string curr;
for (int j = num2.size() - 1; j > i; j--)
{
curr.push_back('0');
}
int x = num2[i] - '0';
int add = 0;
for (int j = num1.size() - 1; j >= 0; j--)
{
int y = num1[j] - '0';
int z = x * y + add;
add = z / 10;
curr.push_back(z % 10 + '0');
}
while (add != 0)
{
curr.push_back(add % 10 + '0');
add = add / 10;
}
reverse(curr.begin(), curr.end());
res = addStrings(res, curr);
}
return res;
}
};
其中涉及到了字符串的运算(push_back),需要反复开辟内存,较为耗时,可以利用定长字符数组进行优化。定长数组的大小,根据num1和num2的上下限就可以设置,代码如下:
class Solution
{
public:
string multiply(string num1, string num2)
{
if (num1 == "0" || num2 == "0")
{
return "0";
}
vector<int> num(num1.size() + num2.size());
for (int i = num1.size() - 1; i >= 0; i--)
{
int x = num1[i] - '0';
for (int j = num2.size() - 1; j >= 0; j--)
{
int y = num2[j] - '0';
num[i + j + 1] += x * y;
}
}
for (int i = num1.size() + num2.size() - 1; i > 0; i--)
{
num[i - 1] += num[i] / 10;
num[i] = num[i] % 10;
}
int index = num[0] == 0 ? 1 : 0;
string res;
while (index < num1.size() + num2.size())
{
res.push_back(num[index] + '0');
index++;
}
return res;
}
};
字符串相乘可以看作是2个多项式相乘,进一步可以利用快速傅里叶变换来进行优化。这道题目并不简单,在解题时也参考了题解中的思路,感觉题解写的很精彩。1
快速傅里叶变换(FFT)具体可参考b站视频:https://www.bilibili.com/video/BV1za411F76U/?spm_id_from=333.337.search-card.all.click&vd_source=05161a470997bd075d1f9b6710075f9f,有亿点点复杂 = = 。
59. 螺旋矩阵 II
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
提示:
1 <= n <= 20
这道题目不难,采用模拟的方法就可以解决问题。
-
切换方向的条件:我们通过一对方向向量dx,dy就可以实现对矩阵的遍历。切换方向向量的条件为,已经到达了四个角或者下一个需要访问的元素已经访问过了(val != 0)。
-
方向向量的更新:其中每一次迭代的方向向量(dx,dy)是一个有限状态机,通过观察,其切换顺序如下表所示:
dx | dy |
---|---|
0 | 1 |
1 | 0 |
0 | -1 |
-1 | 0 |
不难发现,如果dx为0的时候,我们只需要swap(dx, dy),否则,我们需要将dx取反,然后swap(dx, dy)。
代码如下:
class Solution
{
public:
vector<vector<int>> generateMatrix(int n)
{
vector<vector<int>> vec(n, vector<int>(n));
int i = 0, j = 0, idx = 1;
int dx = -1, dy = 0;
while (i >= 0 && i < n && j >= 0 && j < n && vec[i][j] == 0)
{
vec[i][j] = idx;
if ((i == n - 1 || i == 0) && (j == n - 1 || j == 0) || vec[i + dx][j + dy] != 0)
{
if (dx == 0)
{
swap(dx, dy);
}
else
{
dx = -dx;
swap(dx, dy);
}
}
i += dx;
j += dy;
idx++;
}
return vec;
}
};
61. 旋转链表
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
示例 2:
输入:head = [0,1,2], k = 4
输出:[2,0,1]
提示:
链表中节点的数目在范围 [0, 500] 内
-100 <= Node.val <= 100
0
<
=
k
<
=
2
∗
1
0
9
0 <= k <= 2 * 10^9
0<=k<=2∗109
主要思路为,首先统计链表中节点的个数,并将链表首尾相连。然后对k进行取余,计算得到需要切分的位置。然后第二次遍历链表到cutPos,切开并返回newHead即可。
// Definition for singly-linked list.
struct ListNode
{
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution
{
public:
ListNode *rotateRight(ListNode *head, int k)
{
if(head == nullptr){
return nullptr;
}
int nodeNum = 1;
ListNode *curNode = head;
while (curNode->next != nullptr)
{
nodeNum++;
curNode = curNode->next;
}
curNode->next = head;
k = k % nodeNum;
int cutPos = nodeNum - k;
curNode = head;
for (int i = 1; i < cutPos; i++)
{
curNode = curNode->next;
}
ListNode *newHead = curNode->next;
curNode->next = nullptr;
return newHead;
}
};
int main()
{
ListNode *node1 = new ListNode(1);
ListNode *node2 = new ListNode(2);
ListNode *node3 = new ListNode(3);
ListNode *node4 = new ListNode(4);
ListNode *node5 = new ListNode(5);
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5;
Solution sol;
ListNode *res = sol.rotateRight(node1, 2);
return 0;
}
https://leetcode.cn/problems/multiply-strings/solutions/372098/zi-fu-chuan-xiang-cheng-by-leetcode-solution/ ↩︎