leetcode刷题记录31(2024-1-15)【字符串相加(模拟) | 字符串相乘(竖式乘法、模拟) | 螺旋矩阵 II(模拟) | 旋转链表(模拟)】

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)是一个有限状态机,通过观察,其切换顺序如下表所示:

dxdy
01
10
0-1
-10

不难发现,如果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<=2109

主要思路为,首先统计链表中节点的个数,并将链表首尾相连。然后对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;
}

  1. https://leetcode.cn/problems/multiply-strings/solutions/372098/zi-fu-chuan-xiang-cheng-by-leetcode-solution/ ↩︎

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cherries Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值