当前位置: 首页 > news >正文

力扣热题——找出 3 位偶数

目录

题目链接:2094. 找出 3 位偶数 - 力扣(LeetCode)

题目描述

解法一:暴力枚举

Java写法:

C++写法:

C写法:

运行时间

时间复杂度和空间复杂度

解法二:计数数组来统计

思路解析

Java写法:

C++写法:

运行时间

时间复杂度和空间复杂度

总结


题目链接:2094. 找出 3 位偶数 - 力扣(LeetCode)

注:下述题目描述和示例均来自力扣

这题打开就发现做过了。

题目描述

给你一个整数数组 digits ,其中每个元素是一个数字(0 - 9)。数组中可能存在重复元素。

你需要找出 所有 满足下述条件且 互不相同 的整数:

  • 该整数由 digits 中的三个元素按 任意 顺序 依次连接 组成。
  • 该整数不含 前导零
  • 该整数是一个 偶数

例如,给定的 digits 是 [1, 2, 3] ,整数 132 和 312 满足上面列出的全部条件。

将找出的所有互不相同的整数按 递增顺序 排列,并以数组形式返回

示例 1:

输入:digits = [2,1,3,0]
输出:[102,120,130,132,210,230,302,310,312,320]
解释:
所有满足题目条件的整数都在输出数组中列出。 
注意,答案数组中不含有 奇数 或带 前导零 的整数。

示例 2:

输入:digits = [2,2,8,8,2]
输出:[222,228,282,288,822,828,882]
解释:
同样的数字(0 - 9)在构造整数时可以重复多次,重复次数最多与其在 digits 中出现的次数一样。 
在这个例子中,数字 8 在构造 288、828 和 882 时都重复了两次。 

示例 3:

输入:digits = [3,7,5]
输出:[]
解释:
使用给定的 digits 无法构造偶数。

解法一:暴力枚举

        通过暴力枚举的方式来找出所有符合条件的三位数,并确保这些三位数满足题目给定的条件:没有前导零、是偶数且由 digits 数组中的三个不同元素组成。以下是具体步骤:

  1. 初始化集合

    • 使用一个 HashSet 来存储符合条件的数字,利用集合的特性(不允许重复元素)来自动去重。
  2. 三层循环遍历

    • 通过三层嵌套的 for 循环,分别选取三位数字的不同位置。外层循环变量 i 代表百位数字的位置,中层循环变量 j 代表十位数字的位置,内层循环变量 k 代表个位数字的位置。
    • 在每一层循环中检查当前选择的三个位置是否相同,如果相同则跳过此次循环(避免选取相同的数字作为不同的位),这保证了我们每次组合都是基于三个不同的数字位置。
  3. 条件判断与数字构造

    • 对于每一个可能的组合,首先构造出对应的整数 num = digits[i] * 100 + digits[j] * 10 + digits[k]
    • 然后检查该整数是否大于等于100(确保是一个三位数),并且是个偶数(即 num % 2 == 0),这样就同时保证了没有前导零和是偶数的要求。
  4. 结果处理

    • 将所有符合条件的数字加入到集合中。
    • 最后,将集合转换为数组,并对数组进行排序,以满足输出要求(按递增顺序排列)。

Java写法:

class Solution {public int[] findEvenNumbers(int[] digits) {int len = digits.length;// 这里使用集合的原因主要是java中数组的长度是事先固定的,但是我们又不知道长度,所以采用集合Set<Integer> set = new HashSet<>();// 三层for循环解决问题for (int i = 0; i < len; i++) {for (int j = 0; j < len; j++) {for (int k = 0; k < len; k++) {// 重复位置跳过if (i == j || j == k || i == k) {continue;}// 判断是否满足条件int num = digits[i] * 100 + digits[j] * 10 + digits[k];if (num >= 100 && num % 2 == 0) {// 满足条件加入集合set.add(num);}}}}// 集合转化为 int数组int[] res = set.stream().mapToInt(Integer::intValue).toArray();// 从小到大排序Arrays.sort(res);return res;}
}

C++写法:

class Solution {
public:vector<int> findEvenNumbers(vector<int>& digits) {int len = digits.size();std::set<int> s;for (int i = 0; i < len; i++) {for (int j = 0; j < len; j++) {for (int k = 0; k < len; k++) {// 重复位置跳过if (i == j || j == k || i == k) {continue;}// 判断是否满足条件int num = digits[i] * 100 + digits[j] * 10 + digits[k];if (num >= 100 && num % 2 == 0) {// 满足条件加入集合s.insert(num);}}}}// 集合转化为 vectorstd::vector<int> res(s.begin(), s.end());// 从小到大排序std::sort(res.begin(), res.end());return res;}
};

C写法:


// 定义比较函数用于排序
int compare(const void *a, const void *b) {return (*(int *)a - *(int *)b);
}// 判断是否为偶数
int isEven(int num) {return num % 2 == 0;
}int* findEvenNumbers(int* digits, int digitsSize, int* returnSize) {// 生成所有可能的三位数int count = 0;int maxResultSize = digitsSize * digitsSize * digitsSize;int* result = (int*)malloc(sizeof(int) * maxResultSize);int* isVisited = (int*)calloc(1000, sizeof(int));for (int i = 0; i < digitsSize; i++) {for (int j = 0; j < digitsSize; j++) {for (int k = 0; k < digitsSize; k++) {// 判断索引是否相同if (i != j && i != k && j != k) {// 将三个数字按顺序连接成三位数int number = digits[i] * 100 + digits[j] * 10 + digits[k];// 检查是否满足条件且未访问过if (isEven(number) && number >= 100 && number <= 999 && !isVisited[number]) {result[count++] = number;isVisited[number] = 1;}}}}}// 如果没有找到符合条件的数字,则返回空数组if (count == 0) {free(result);free(isVisited);*returnSize = 0;return NULL;}// 排序结果数组qsort(result, count, sizeof(int), compare);// 动态分配内存以保存结果int* finalResult = (int*)malloc(sizeof(int) * count);for (int i = 0; i < count; i++) {finalResult[i] = result[i];}// 释放内存free(result);free(isVisited);// 更新返回结果的大小*returnSize = count;return finalResult;
}

运行时间

时间复杂度和空间复杂度




解法二:计数数组来统计

思路解析

  1. 统计数字频率

    • 使用一个大小为10的数组(因为数字范围是0到9)来记录每个数字在输入数组中的出现次数。这一步允许我们快速检查某个数字是否可用以及它还剩余多少次使用机会。
  2. 构造符合条件的三位数

    • 枚举所有可能的三位数组合 (a, b, c),其中:
      • a(百位)不能为0(否则会导致前导零),因此它的取值范围是1到9。
      • c(个位)必须是偶数,以保证生成的数字是偶数,所以它的取值只能是0, 2, 4, 6, 8。
      • 对于每一个(a, b, c)组合,首先确保对应的计数器值大于0(即该数字在原数组中有足够的数量供使用)。
      • 如果满足条件,则根据公式 num = a * 100 + b * 10 + c 计算出当前组合代表的实际数字,并将其添加到结果集中。
  3. 回溯与更新计数器

    • 每当选择了一个数字作为某一位(比如百位或十位或个位)时,相应地减少其计数器的值。一旦完成当前组合的所有可能性探索后,需要将计数器值恢复(回溯),以便下一次迭代可以正确计算。
  4. 排序并返回结果

    • 因为题目要求返回的结果需要按升序排列,所以在收集完所有符合条件的三位数之后,对这些数字进行排序。
    • 在Java和C++中,分别使用了TreeSetset自动去重并排序;而在C语言中,使用qsort函数对结果进行排序。

Java写法:

import java.util.*;public class Solution {public int[] findEvenNumbers(int[] digits) {// 计数数组,用于记录每个数字出现的次数int[] count = new int[10];for (int digit : digits) {count[digit]++;}// 使用TreeSet自动排序且去重Set<Integer> res = new TreeSet<>();// 遍历所有可能的百位、十位、个位数字for (int a = 1; a <= 9; a++) { // 百位不能为0if (count[a] == 0) continue;count[a]--; // 使用a后减少其计数for (int b = 0; b <= 9; b++) {if (count[b] == 0) continue;count[b]--;for (int c = 0; c <= 8; c += 2) { // 个位必须是偶数if (count[c] == 0) continue;int num = a * 100 + b * 10 + c;res.add(num);}count[b]++; // 回溯}count[a]++; // 回溯}// 转换为数组返回return res.stream().mapToInt(Integer::intValue).toArray();}
}

C++写法:

#include <vector>
#include <set>
using namespace std;class Solution {
public:vector<int> findEvenNumbers(vector<int>& digits) {// 计数数组,用于记录每个数字出现的次数vector<int> count(10, 0);for (int digit : digits) {count[digit]++;}// 使用set自动排序且去重set<int> res;// 遍历所有可能的百位、十位、个位数字for (int a = 1; a <= 9; ++a) { // 百位不能为0if (count[a] == 0) continue;count[a]--; // 使用a后减少其计数for (int b = 0; b <= 9; ++b) {if (count[b] == 0) continue;count[b]--;for (int c = 0; c <= 8; c += 2) { // 个位必须是偶数if (count[c] == 0) continue;int num = a * 100 + b * 10 + c;res.insert(num);}count[b]++; // 回溯}count[a]++; // 回溯}// 转换为vector返回return vector<int>(res.begin(), res.end());}
};

运行时间

时间复杂度和空间复杂度


总结

       介绍了两种解决“找出由给定数字数组中的三个不同元素组成的三位偶数”问题的方法。第一种方法是暴力枚举,通过三层嵌套循环遍历所有可能的数字组合,确保没有前导零且为偶数,并使用集合去重和排序。第二种方法利用计数数组统计每个数字的频率,通过回溯法构造符合条件的三位数,并使用集合自动去重和排序。两种方法均能有效解决问题,但第二种方法在效率上更优,尤其是在处理较大数据集时。

http://www.xdnf.cn/news/446455.html

相关文章:

  • 康谋分享 | 自动驾驶仿真进入“标准时代”:aiSim全面对接ASAM OpenX
  • C++类和对象--高阶
  • 猫眼浏览器:简约安全,极速浏览
  • 基于多目标进化算法的神经网络架构搜索及其高级可视化技术
  • Huffman树
  • 常用的Java工具库
  • 错误: 加载主类 org.springframework.boot.loader.launch.JarLauncher 时出现 LinkageError
  • 鸿蒙Next API17新特性学习之如何使用新增鼠标轴事件
  • 蚂蚁seo强引蜘蛛池,SEO优化的利器
  • 【Linux笔记】——进程信号的捕捉——从中断聊聊OS是怎么“活起来”的
  • Kotlin Compose 与传统 Android UI 开发对比
  • LabVIEW在电子电工教学中的应用
  • Python 之 selenium 打开浏览器指定端口进行接续操作
  • Nginx+Lua 实战避坑:从模块加载失败到版本冲突的深度剖析
  • 数字信号处理-大实验1.1
  • Vue3吸顶导航的实现
  • Jmeter变量传递介绍
  • JavaScript 中级进阶技巧之map函数
  • 哈希表的实现01
  • java每日精进 5.14【参数校验】
  • qml中定时器的用法
  • 操作系统期末复习笔记
  • WHAT - 前端开发滚动场景API罗列
  • Web UI测试效率低?来试Parasoft Selenic的智能修复与分析!
  • 从 “学会学习” 到高效适应:元学习技术深度解析与应用实践
  • 常见 RPC 协议类别对比
  • 《Effective Python》第2章 字符串和切片操作——深入理解 Python 中 __repr__ 与 __str__
  • 行业趋势与技术创新:驾驭工业元宇宙与绿色智能制造
  • 【氮化镓】AlGaN合金中成分相关的辐射响应
  • 最短路和拓扑排序知识点