45.最小步数归零问题
一、问题描述
小 R 拥有一个长度为 n 的数组,该数组中的每个元素均是正整数。存在这样一种操作规则:每次能够从数组中的某个数里删除其中一位数字,通过不断重复这样的操作,最终要将数组里的所有数字都变成 0。现在需要求出达成这一目标,也就是将数组中所有数字都变为 0 时,最少需要进行多少步操作。例如数字 103,可通过删除第 1 位数字变成 3,或删除第 2 位数字变为 13,又或是删除第 3 位数字变为 10,直至最终变为 0。
二、思路解析
- 整体思路:要确定将整个数组的所有数字变为 0 所需的最少操作步数,核心在于分别计算出数组中每个正整数变为 0 所需要的最少操作次数,然后把这些次数累加起来,得到的总和就是将数组中所有数字都变为 0 的最少操作步数。
- 针对单个数字的思路:对于数组中的每一个正整数,考虑将其转化为一种便于处理的形式来统计其中非零数字的个数。因为每一个非零数字都得经过一次删除操作才能使该整数最终变为 0,所以统计出非零数字个数也就相当于得到了将这个数字变为 0 的最少操作次数。在给定的代码中,是把整数先转换为字符串,再通过遍历字符串中的字符来判断是否为非零字符,进而统计非零数字的个数。
三、解题步骤
-
检查数组是否为空:
- 在开始处理数组元素之前,先判断输入的数组是否为空。如果为空数组,按照题意,此时将数组中所有数字变为 0 所需的操作步数为 0,直接返回 0 即可。
-
遍历数组元素:
- 若数组不为空,就开始遍历数组中的每一个正整数元素。这里使用基于范围的 for 循环(
for(auto x:a))来依次获取数组中的每个元素x。
- 若数组不为空,就开始遍历数组中的每一个正整数元素。这里使用基于范围的 for 循环(
-
处理单个整数:
- 对于当前遍历到的每一个正整数
x,先将其转换为字符串形式(string s = to_string(x)),以便能够逐个字符地去分析它。 - 接着遍历该字符串中的每一个字符(
for(auto &i:s))。
- 对于当前遍历到的每一个正整数
-
统计非零数字个数:
- 在遍历字符串字符的过程中,当发现字符
i所对应的数字大于 0(即不是字符 '0')时,就将记录操作步数的变量count加 1。因为每一个非零数字都意味着需要进行一次删除操作才能让这个整数最终变为 0。
- 在遍历字符串字符的过程中,当发现字符
-
累加操作步数:
- 当完成对数组中一个整数的处理后,继续遍历下一个整数,重复上述步骤 3 和 4,不断累加每个整数变为 0 所需的操作步数到变量
count中。
- 当完成对数组中一个整数的处理后,继续遍历下一个整数,重复上述步骤 3 和 4,不断累加每个整数变为 0 所需的操作步数到变量
-
得出最终结果:
- 当遍历完数组中的所有整数后,此时变量
count的值就是将数组中所有数字都变为 0 的最少操作步数,将其返回即可。
- 当遍历完数组中的所有整数后,此时变量
四、代码分析
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int solution(int n, vector<int>& a) {
// write code here
if(a.empty())
{
return 0;
}
int count=0;
for(auto x:a)
{
string s=to_string(x);
for(auto &i:s)
{
if(i>'0')
{
count++;
}
}
}
return count;
}
int main() {
vector<int> a1 = {10, 13, 22, 100, 30};
cout << (solution(5, a1) == 7) << endl;
vector<int> a2 = {5, 50, 505};
cout << (solution(3, a2) == 4) << endl;
vector<int> a3 = {1000, 1, 10, 100};
cout << (solution(4, a3) == 4) << endl;
}
(一)solution函数分析
- 空数组处理:
- 函数首先通过
if(a.empty())条件判断语句来检查输入的数组a是否为空。如果为空,就直接返回 0,这符合题目中对于空数组情况的设定,即空数组变为 0 所需操作步数为 0。
- 函数首先通过
- 变量初始化:
- 当数组不为空时,定义一个整型变量
count并初始化为 0,这个变量用于记录将数组中所有数字变为 0 的总操作步数。
- 当数组不为空时,定义一个整型变量
- 数组遍历与单个整数处理:
- 使用基于范围的 for 循环(
for(auto x:a))遍历数组a中的每一个元素x。对于每一个元素x,先通过string s = to_string(x)将其转换为字符串形式,以便后续对其每一位数字进行分析。 - 然后通过
for(auto &i:s)循环遍历转换后的字符串s中的每一个字符i。在这个字符遍历过程中,通过if(i>'0')条件判断语句来检查字符i所对应的数字是否大于 0。如果大于 0,就将count加 1,因为每一个非零数字都需要一次删除操作才能使对应的整数最终变为 0。
- 使用基于范围的 for 循环(
- 结果返回:
- 当完成对整个数组的遍历和处理后,函数最后返回
count,这个值就是将数组中所有数字都变为 0 的最少操作步数。
- 当完成对整个数组的遍历和处理后,函数最后返回
(二)main函数分析
- 测试用例定义:
- 在
main函数中,首先定义了三个不同的整数向量a1、a2和a3,它们分别代表了不同的测试用例场景,用于验证solution函数的正确性。
- 在
- 函数调用与结果验证:
- 对于每一个测试用例向量,如
a1,通过cout << (solution(5, a1) == 7) << endl;这样的语句来调用solution函数,并将其返回结果与预期结果(这里预期结果是通过手动分析测试用例得出的将数组中所有数字变为 0 的最少操作步数)进行比较。如果返回结果与预期结果相等,那么输出 1,表示验证通过;如果不相等,输出 0,表示验证失败。同样的操作也应用于a2和a3这两个测试用例向量。
- 对于每一个测试用例向量,如
五、知识总结
- 数组操作:学会了如何遍历数组中的元素,像这里使用基于范围的 for 循环(
for(auto x:a))是一种很便捷的遍历数组的方式。同时也了解到在处理数组相关问题时,首先要考虑数组是否为空的情况,并进行相应的处理。 - 数据转换:掌握了将整数转换为字符串的操作(
to_string函数),以便能够以字符的视角去分析整数的每一位数字。不过要注意这种转换可能会带来一定的性能开销,在某些情况下可以考虑寻找其他更高效的处理方式。 - 字符处理:明白了如何通过遍历字符串中的字符,并根据字符所对应的数字情况(如判断是否大于 0)来统计相关信息。这种字符处理技巧在处理一些需要分析数字每一位情况的问题时很有用。