介绍
枚举算法 也叫暴力算法,是一种简单直接的问题求解方法,它通过逐一列举问题的所有可能解,并检查每个可能解是否符合问题的条件,直到找到正确的解或者遍历完所有可能的情况。
对于一个问题,首先确定解的范围,然后在这个范围内逐个尝试所有可能的值,例如,在寻找一个整数 n 的所有因数时,枚举算法会从1开始,逐个检查到 n ,判断每个数是否能整除 n 。
枚举几乎可以用于解决任何类型的问题,只要能够确定解的范围,但缺点也很明显,当问题规模增大时,需要检查的可能解数量会迅速增加,这会导致程序运行效率低下,为了克服枚举算法的这个缺点,需要对其进行优化,通过数学推导发现问题的规律,减少不必要的计算。
题目1
对于给定的整数 n,需进行如下判断:若存在三个不同的正整数,当它们分别与特定整数相乘时结果均为 n,则返回 true;若无法找到这样恰好三个正整数满足该情形,便返回 false。
举例而言,设存在整数 k,若 n = k * m,这里的 m 即为 n 的一个除数。当 n = 2 时,仅能以 1×2 表示,即其除数只有 1 和 2,所以此情形下应返回 false,而当 n = 4 时,可写成 1×4 与 2×2,其除数有 1、2 和 4,这种情况下则返回 true。
解题思路
从1到 n 遍历每个数字 i,满足条件能整除三次就返回true。
代码实现
java
public class Main {
public boolean isThree(int n) {
int count = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
count++;
}
}
return count == 3;
}
public static void main(String[] args) {
boolean result = new Main().isThree(4);
System.out.println(result);
}
}
检查 n 是否能被 i 整除,如果可以,那么 i 就是 n 的一个除数,将count 加1,全部执行完成后,检查 count 是否等于3,如果是,则返回 true ,否则返回 false 。
优化思路
当一个数有三个除数时,它一定不是质数, 对于每个 p ,检查 n 是否可以整除p,如果是,那么 n 就有三个除数(1、 p 、 n )。
java
public class Main {
public boolean isThree(int n) {
if(n<=3){
return false;
}
for(int p=2;p*p<=n;p++){
if(n%p==0){
return true;
}
}
return false;
}
public static void main(String[] args) {
boolean result = new Main().isThree(11);
System.out.println(result);
}
}
从2开始遍历到 n,如果它有平方根p,那么返回 true,如果遍历完都没有找到这样的 p ,则返回 false 。
(取自leedcode1952)
题目2
给定一个正整数 n,返回 连续正整数满足所有数字之和为 n 的组数 。
示例 1:输入: n = 5 输出: 2 解释: 5 = 2 + 3,共有两组连续整数([5],[2,3])求和后为 5。
示例 2:输入: n = 9 输出: 3 解释: 9 = 4 + 5 = 2 + 3 + 4
示例 3:输入: n = 15 输出: 4 解释: 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
解题思路
可以采取等差数列的公式,如果存在它的等差数列就将总数加1。
代码实现
java
public class Main {
public static void main(String[] args) {
int result = Sum(15);
System.out.println(result);
}
public static int Sum(int n) {
int count = 0;
n *=2;
for (int i = 1; i * i <= n; i++) {
if (n % i != 0) {
continue;
}
int a = n / i - i + 1;
boolean res = a % 2 == 0;
if (res) {
count++;
}
}
return count;
}
}
对于连续正整数序列a,a + 1,a+2 , a + 3 , a+k其和S=(2a + k)(k + 1)/2,我们要推导出2a。
将等式两边同时乘以2,得到2S=(2a + k)(k + 1)。
所以2a= 2S - k(k + 1) / k + 1,将项数减去 1就是 2a = 2S - k(k - 1) / k ,也就是2a = 2S/ k - k + 1,演变成我们公式里的 n*=2;int a = n / i - i + 1; 和 a % 2 == 0; 即可得出答案
(取自leedcode829)
题目3
给定一个非负的整数变量 num,需确定是否存在这样一个非负整数 k,使得 k 与其各位数字反转后所形成的整数相加的结果恰好等于 num,若存在这样的 k,则返回 true;若不存在,则返回 false。
解题思路
枚举从零到num的所有k数,判断它们反转相加的结果是否等于 num。
示例:
输入:num = 443 输出:true 解释:172 + 271 = 443 ,所以返回 true。
输入:num = 63 输出:false 解释:63 不能表示为非负整数及其反转后数字之和,返回 false 。
代码实现
java
public class Main {
public static void main(String[] args) {
int num = 443;
boolean flag = true;
for (int i = 0; i < num; i++) {
int rev = reverseNumber(i);
if (rev+i==num) {
flag = false;
}
}
if (flag) {
System.out.println(false);
}else {
System.out.println(true);
}
}
public static int reverseNumber(int n) {
int rev = 0;
while (n != 0) {
rev = rev * 10 + n % 10;
n /= 10;
}
return rev;
}
}
在以上代码中使用了 for 循环从0开始,每次递增1,直到 i 小于num,在每次循环中
都调用了reverseNumber 方法对当前的整数 i 进行反转,然后判断rev + i是否等于num,如果相等,说明找到了满足条件的整数 i ,此时将flag的值设置为false。
(取自leedcode2443)
以上就是枚举的应用示例,在实际应用中,对于复杂或大规模问题,通常需要结合问题特性对枚举进行优化,如利用数学规律减少不必要的枚举次数,或者借助更高效的数据结构来存储和处理数据,以提升效率。总之,枚举是算法学习的重要基石,理解其优劣有助于在不同场景下合理运用或优化算法,为解决更复杂的编程和数学问题奠定基础。