LC 43. Multiply Strings 大数乘法 / 字符串操作 / 细节:“000”要转化为“0”输出

本文介绍了一种基于字符串的大数乘法实现方法,通过分解乘法过程为一系列基本操作,如单个数字的乘法及大数加法,来解决大数运算的问题。
部署运行你感兴趣的模型镜像

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2.

Note:

  1. The length of both num1 and num2 is < 110.
  2. Both num1 and num2 contains only digits 0-9.
  3. Both num1 and num2 does not contain any leading zero.

题目就是让实现一个大数的乘法。这道题建立在大数加法之上。分析乘法的原理,对于 a * b,最基本的就是 a 以 b 中从右往左乘的每一个单个数字,并将结果乘以适当的 10^n,然后将得到的所有数相加。因此需要两个辅助函数,一个支持大数的加法,另一个支持一个很长的数乘以一个一位数并乘以10^n。非常简单,直接上代码:

string add(string num1, string num2) {
    string res;
    int i = (int)num1.length() - 1;
    int j = (int)num2.length() - 1;
    int a, b, sum, flag = 0;
    while(i > -1 || j > -1 || flag) {
        a = i > -1 ? num1[i] - '0' : 0;
        b = j > -1 ? num2[j] - '0' : 0;
        sum = a + b + flag;
        flag = sum > 9 ? 1 : 0;
        res = (char)(sum % 10 + '0') + res;
        i--;
        j--;
    }
    return res;
}
string multiplyWithOneDigit(string longNum, int oneNum, int pos) {
    int i, flag = 0;
    string res;
    int product;
    i = (int)longNum.length() - 1;
    while (i > -1 || flag) {
        product = i > -1 ? oneNum * (longNum[i] - '0') + flag : flag;
        flag = product > 9 ? product / 10 : 0;
        res = (char)(product % 10 + '0') + res;
        i--;
    }
    while (pos > 0) {
        res += '0';
        pos--;
    }
    return res[0] == '0' ? "0" : res;
}
string multiply(string num1, string num2) {
    string res="0";
    int n = (int)num2.length();
    for(int i = n - 1; i >= 0; i--) {
        string product = multiplyWithOneDigit(num1, num2[i] - '0', n - i -1);
        res = add(res, product);
    }
    return res;
}

唯一需要注意的一点也是我唯一一个第一次提交没有AC的test case,就是一个数乘以0的情况。例如999 * 0第一次返回000了。问题出在multiplyWithOneDigit()这个函数上,因为一开始没有

return res[0] == '0' ? "0" : res;

这个处理,导致

res = (char)(product % 10 + '0') + res;
产生的字符串在结果为零的时候不能发现“0000...00”其实必须表示成“0”。也正是因为这个小细节我才为了这么简单的题目专门写了这一篇记录下来。

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>好的,我现在需要解决用户的问题:如何在MongoDB聚合管道中将字符串类型的时间戳字段换为日期格式,并按日期分组以获取最新日期的文档。用户提到要忽略具体时间,仅取最新日期进行查询。 首先,回顾用户提供的引用内容。引用[1]提到了PHP的getdate函数,这可能和日期处理相关,但用户的问题是关于MongoDB的,所以可能需要关注MongoDB的日期换函数。引用[2]中提到了MongoDB的Date类型存储的是从标准纪元开始的毫秒数,不存储时区。这提示我需要使用MongoDB的日期处理功能,比如$dateFromString。引用[3]提到MongoDB的管道机制,类似于Unix的管道,用于将处理结果传递给下一个阶段,这帮助我确认应该使用聚合管道的各个阶段来处理数据。 用户上一次的问题是关于将字符串字段换为日期并取最近的值,我之前给出的解决方案中使用了$dateFromString和排序。现在用户的新问题是在聚合管道中字符串时间戳为日期格式,并按日期分组获取最新文档。需要结合分组操作。 首先,我需要确认时间戳字段的格式。用户提到是字符串类型的时间戳,但未说明具体格式。常见的有两种可能:一种是Unix时间戳(如秒数或毫秒数),另一种是ISO格式的日期字符串(如"2023-10-05T12:34:56Z")。不同的格式会影响换方法。 假设用户的字符串是Unix时间戳(如"1633430400"),需要先将其换为整数,再使用$toDate换为日期。如果字符串是ISO格式,可以直接用$dateFromString。但用户提到时间戳字段,可能更倾向于数字类型,但存储为字符串。比如"1633430400"这样的字符串,需要先为整数,再为日期。 例如,如果字段名为timestampStr,存储的是秒数,换步骤可能如下: 1. $addFields或$project阶段,使用$toLong将字符串为长整型。 2. 使用$toDate将长整型为日期。 3. 使用$dateToString去掉时间部分,只保留日期,方便分组。 4. 按日期分组,并获取每个分组的最新文档。 如果用户的时间戳是ISO格式字符串,如"2023-10-05T12:34:56Z",则可以直接使用$dateFromString,并设置格式参数,提取日期部分。 接下来,考虑如何按日期分组并获取最新文档。分组后,每个组的_id为日期,然后使用$max或$last操作符获取最新时间戳对应的文档。 需要注意的是,分组后可能需要使用$first或$last结合排序来获取每个组的最新文档。例如,在分组前按日期降序排序,然后在分组时使用$first来获取最新的文档。 另外,用户希望忽略具体时间,只按日期分组。因此,需要将日期字段换为仅包含年月日的格式,例如"YYYY-MM-DD",这样相同日期的文档会被分到同一组。 可能的聚合步骤: 1. 字符串时间戳为日期类型。 2. 提取日期部分(如格式化为"YYYY-MM-DD")。 3. 按提取的日期分组,并记录每个分组的最大日期时间。 4. 将每个分组的文档与最大日期时间匹配,筛选出最新文档。 或者,另一种方法是先排序,然后按日期分组,取每个组的第一个文档,因为排序后第一个就是最新的。 例如: 1. 字符串为日期。 2.换后的日期降序排序。 3. 添加日期字段(格式化为"YYYY-MM-DD")。 4. 按日期字段分组,取每个组的第一个文档。 这种方法可能更高效,因为排序后分组时只需取每个组的第一个。 需要处理可能的错误,例如字符串时间戳格式不正确,可以使用$dateFromString的onError参数,或者先进行类型检查。 此外,用户可能希望保留原始文档结构,所以在分组后可能需要使用$mergeObjects或$first来保留所需字段。 现在,结合这些步骤,构建聚合管道: 假设字段名为timestampStr,存储的是秒数的字符串: 1. $addFields阶段,将字符串为长整型: { $addFields: { timestampLong: { $toLong: "$timestampStr" } } } 2. 换为日期: { $addFields: { date: { $toDate: "$timestampLong" } } } 如果是毫秒数,可能需要乘以1000,或者直接使用$toDate处理字符串。 如果时间戳是ISO字符串,直接使用$dateFromString: { $addFields: { date: { $dateFromString: { dateString: "$timestampStr" } } } } 3. 格式化日期为仅日期部分: { $addFields: { dateOnly: { $dateToString: { format: "%Y-%m-%d", date: "$date" } } } } 4. 按dateOnly分组,并获取每个组的最新文档: 这里需要确定每个组中的最新文档。一种方法是先按date降序排序,然后按dateOnly分组,取每个组的第一个文档。 完整聚合管道可能如下: [ { $addFields: { date: { $dateFromString: { dateString: "$timestampStr", onError: null // 处理换错误 } } } }, { $addFields: { dateOnly: { $dateToString: { format: "%Y-%m-%d", date: "$date" } } } }, { $sort: { date: -1 } // 按日期降序排列,确保最新的在前 }, { $group: { _id: "$dateOnly", latestDoc: { $first: "$$ROOT" }, // 取每个分组中的第一个文档(即最新) maxDate: { $max: "$date" } // 记录最大日期 } }, { $replaceRoot: { newRoot: "$latestDoc" // 恢复文档结构 } } ] 这样,每个日期分组中的最新文档会被选出。同时,保留了原始文档结构,方便后续使用。 需要注意的点: - 时间戳字符串的格式是否正确,可能需要调整$dateFromString的参数,如format。 - 处理换错误,避免整个管道失败。 - 排序可能会影响性能,确保有合适的索引,比如在timestampStr字段上创建索引。 如果时间戳是Unix秒数,可能需要先换为毫秒数,因为MongoDB的日期需要毫秒级的时间戳: { $addFields: { date: { $toDate: { $multiply: [ { $toLong: "$timestampStr" }, 1000 ] } } } } 或者,如果存储的是毫秒数的字符串,直接使用$toDate。 总结,步骤包括字符串为日期、提取日期部分、排序、分组取最新,最后恢复文档结构。需要根据时间戳的具体格式调整换方法,并考虑错误处理和性能优化。</think>### **解决方案:字符串时间戳日期并获取最新文档** --- #### **一、字符串时间戳为日期类型** 根据时间戳格式选择换方式: 1. **Unix时间戳(秒/毫秒字符串)** ```javascript // 秒级时间戳(如"1633430400") { $addFields: { timestampLong: { $toLong: "$timestampStr" }, // 成数值类型 date: { $toDate: { $multiply: ["$timestampLong", 1000] } } // 秒毫秒 }} ``` ```javascript // 毫秒级时间戳(如"1633430400000") { $addFields: { date: { $toDate: { $toLong: "$timestampStr" } } }} ``` 2. **ISO格式字符串(如"2023-10-05T12:34:56Z")** ```javascript { $addFields: { date: { $dateFromString: { dateString: "$timestampStr", onError: null // 错误时返回null } } }} ``` --- #### **二、提取日期部分并分组** 1. **格式化日期为`YYYY-MM-DD`** ```javascript { $addFields: { dateOnly: { $dateToString: { format: "%Y-%m-%d", date: "$date" } } }} ``` 2. **按日期分组并获取最新文档** ```javascript [ { $sort: { date: -1 } }, // 按实际日期降序排列 { $group: { _id: "$dateOnly", // 按日期分组 latestDoc: { $first: "$$ROOT" }, // 取组内第一个(即最新) maxDate: { $max: "$date" } // 验证最大值 } }, { $replaceRoot: { newRoot: "$latestDoc" } } // 恢复原始文档结构 ] ``` --- #### **三、完整聚合管道示例** 假设字段`timestampStr`存储秒级Unix时间戳: ```javascript db.collection.aggregate([ // 阶段1:字符串日期 { $addFields: { timestampLong: { $toLong: "$timestampStr" }, date: { $toDate: { $multiply: ["$timestampLong", 1000] } } }}, // 阶段2:提取日期部分 { $addFields: { dateOnly: { $dateToString: { format: "%Y-%m-%d", date: "$date" } } }}, // 阶段3:排序确保最新文档在前 { $sort: { date: -1 } }, // 阶段4:按日期分组取最新 { $group: { _id: "$dateOnly", latestDoc: { $first: "$$ROOT" }, maxDate: { $max: "$date" } } }, // 阶段5:恢复原始文档结构 { $replaceRoot: { newRoot: "$latestDoc" } } ]); ``` --- #### **四、关键优化点** 1. **索引优化** 为时间戳字段添加降序索引加速排序: ```javascript db.collection.createIndex({ timestampStr: -1 }) ``` 2. **错误处理** 若存在格式错误的时间戳,添加`$cond`逻辑过滤无效数据: ```javascript { $addFields: { date: { $cond: [ { $ne: ["$timestampLong", null] }, // 检查是否成功换 { $toDate: { $multiply: ["$timestampLong", 1000] } }, null ] } }} ``` 3. **时区处理** 如需调整时区,在`$dateToString`中指定时区参数: ```javascript { $dateToString: { format: "%Y-%m-%d", date: "$date", timezone: "+08:00" // 东八区时间 }} ``` --- ### **应用场景** 1. **日志分析** 统计每日最新日志记录(如安全审计、系统监控)。 2. **报表生成** 按自然日汇总业务数据(如每日订单、用户活跃数)。 --- ### **相关问题** 1. 如何将MongoDB日期字段格式化为`YYYY-MM`形式按月分组? 2. 如何在聚合管道中处理混合格式的日期字段? 3. 如何优化大集合的日期范围查询性能? 4. MongoDB中如何计算两个日期字段的时间差?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值