总目录

自幂数,就是一个长度为nnn的自然数,等于自身各个位上数字的nnn次幂的和。
例如十进制中:153=13+53+33153=1^3+5^3+3^3153=13+53+33,153是3位数,每一位数的3次幂的和,还是等于其自身,对于3位的自幂,还有一个特殊的名字“水仙花数”(Narcissistic Number)。
求自幂数的算法非常简单,只要遍历区间内所有数字,算出每一位上数字的“数字长度”的幂之和,与原数比较,只要相等即为自幂数。
如果用以往普通Java循环来写,for、while满屏横飞,各种代码结构完全混杂在一起,而用Stream来写,就可以代码写得即简单,又直白,初始逻辑与判断逻辑完成分离,结构的美感就体现出来了。

思考
1.由于位数不同,导致算法不同,所以简化一下,只查找指定位数的自幂数,即指定nnn的值,如果让n=3n=3n=3,就是只查找100到999之间的自幂数。接下来的说法都以3位数来举例
2.需要将这个3位数中每一位的数取出来,取出后计算其3次幂的值
3.取每一位数的方法很多,这里使用与100相除的商来取百位,余数再与10相除,商为十位,余数再与1相除,商为个位数的方法
4.使用的方法中要尽量少用for、while语句

步骤1-初始化准备代码

计算3次幂的方法。

private int getPower(int initVal, int len) {return IntStream.iterate(initVal, v1 -> v1).limit(len).reduce(1, (a, b) -> a * b);
}
  • 这个代码可以用Math.power函数来实现,这里是个小炫技,求轻打
  • 参数len表示有多少位,initVal表示生成数列中包含的值。
  • getPower(5, 3)为例,IntStream.iterate(initVal, v1->v1)就会生成一个无限流,里面的内容全部都是5。
  • limit(len),是让这个无限流,只会有3个5,其他的全抛弃。
  • reduce(1, (a, b) -> a * b)是把这个流收敛,可以理解成把分散的流变成一个值,这里使用的收敛方法,让流中每个元素相乘在一起,最后就是形成5∗5∗55*5*55∗5∗5这样的效果,即最后方法得到的是125,5的3次幂的值。
  • 灵活使用这个方法getPower(10, 2),就可以得到100,是生成百位数时,要用到的第一个除数。
  • 当得到了100,就可以得到3位数中最大值999,以及最小值100:
int firstDivide = getPower(10, len - 1);
int max = firstDivide * 10 -1;
int min = firstDivide;

步骤2-核心逻辑判断代码

非常遗憾地告诉各位,在这部分代码中,不得不使用的for循环,我也不想啊,可是现实就是让你低头啊,如果列位有更好解决方案,万望不吝赐教。

private IntPredicate isSelfPower(int len, int firstDivide) {return e -> {int dividend = e;// 被除数int divisor = firstDivide;// 除数int quotient;// 商int remainder;// 余数int sum = 0;for (int i = 0; i < len; i++) {quotient = dividend / divisor;remainder = dividend % divisor;sum += getPower(quotient, len);dividend = remainder;divisor /= 10;}return sum == e;};
}
  • IntPredicate是一个函数式接口,返回真或假,而如何判断是应该返回真,还是返回假,全在return语句后面的实现代码中。
  • 实现代码中循环语句的作用举例来说就是:先解析出百位的数,然后对这个数求其3次幂的值,并加到sum变量中,然后再解析出十位的数,再求3次幂,并加到sum变量中……这样的循环。
  • 解析百位数是除以100,解析十位是除以10,解析个位是除以1(这是比较无用的,但可以不用单独处理个位,保证代码的一致性)
  • 最后就是比较这个和sum与这个数本身是不是一样,如果是true,则说明是自幂,反之则不是

步骤3-用一行代码实现查找自幂数

IntStream.iterate(min, v -> v + 1).limit(max - min).parallel().filter(isSelfPower(len, firstDivide)).forEach(System.out::println);
  • 这里面生成的数列的lambda表达式是v -> v+1,这个会生成1,2,3,4,5……这样递增的数列。
  • 使用parallel(),可以并行查找,如果把位数设的大一点,应该会有性能提升,但提升了多少,没有测试过,懒啊。

总结

把代码合并起来,就可以计算指定位数的自幂数了,如果设成8位数,可真是要算很长时间的。

之后的优化

  • 核心逻辑判断代码是用一个方法返回函数式接口的实例,其实可以用属性来代替
  • 在判断逻辑代码中使用了很多变量,也可以大幅度优化,修改后代码如下:
@FunctionalInterface
public interface ThreeParamPredicate<E> {boolean test(E e1, E e2, E e3);
}
private ThreeParamPredicate<Integer> threeParamPredicate = (len, divisor, dividend) -> {int sum = 0;for (int i = 0; i < len; i++) {int quotient = dividend / divisor;int remainder = dividend % divisor;sum += Double.valueOf(Math.pow(quotient, len)).intValue();dividend = remainder;divisor /= 10;}return sum == dividend;
}
  • 举例说明一下这个代码的作用:
  • 由于代码需要传入三个参数,而函数式接口中没有提供,所以自己写了一个接收三个入参的函数式接口
  • 比如判断153是不是自幂数,首先要把153折成1、5、3三个数
  • 循环第1次就是先拆出1这个数来,然后求1的3次幂,加到sum变量中
  • 循环第2次拆出5来,求出5的3次幂,再加到sum变量中
  • 循环第3次拆出3来,求出3的3次幂,再加到sum变量中
  • 最后比较sum变量的值与153的比较,相等则说明是自幂数
  • 但是这些代码,没有按照希望写出不带for/while语句的代码,所以再次修改如下
private IntPredicate isSelfPower1 = v -> {String str = String.valueOf(v);int len = str.length();int sum = Arrays.stream(str.split("")).mapToInt(e -> Double.valueOf(Math.pow(Integer.valueOf(e), len)).intValue()).sum();return v == sum;
}
  • 这个代码意思是,先数字转换成字符串,求出其长度,再通过字符串,把每一个字符拆解出来,再转成数字,求幂值,最后求和
  • 通过这个代码优化,可以看出之前写的代码,把数字长度做为参数传进来,还把除数也传入,是完全没必要的
  • 这里面完全没有for/while语句了,很好啊!

Java Stream来写算法01——自幂数(水仙花数)相关推荐

  1. Java Stream来写算法10——毕达哥拉斯Pythagoras——勾股定理数

    总目录 分析 除了等腰直角三角形,求解全部勾股数,需要知道求解两个正整数,m,nm, nm,n 这两个数要满足如下条件 序号 条件内容 1 m>nm > nm>n 2 mmm与nnn ...

  2. Java Stream如何写出高雅又装*的代码

    Java Stream如何写出高雅又装*的代码 一. 冷静分析 二. 直接开装 2.1 初级炫 2.2 普通炫 2.3 高级炫 2.4 再炫一波 拿到当前key与对应的数量 2.5 Map Reduc ...

  3. Java 求解自幂数(水仙花数)

    文章目录 什么是自幂数 Java pow() 方法扩展 如何求自幂数 什么是水仙花数 如何求水仙花数 附:常见水仙花数 什么是自幂数 如果在一个固定的进制中,一个 n 位自然数等于自身各个数位上数字的 ...

  4. 【C语言】(百合花)水仙花数的算法思考习题4-6 水仙花数

    题目:水仙花数是指该N位数的各位的N次方之和等于其本身: 先写出较为简单的三位水仙花数 代码如下: #include<stdio.h> int main() {int i,t,n,sum; ...

  5. java使用for循环打印出所有的水仙花数

    import java.util.Scanner; class Shuixianhua {public static void main(String[] args) {//使用for循环打印出所有的 ...

  6. 用php写水仙花及思路,php水仙花数

    "水仙花数"指一个三位整数数中,个十百位的立方之和等于这个数的本身.比如整数:153就是水仙花数,因为:153 = 1³ + 5³ + 3³ .在计算时需要分别计算出个十百位的值, ...

  7. 用Java编写求出100~999之间的水仙花数

    关键是求十位数:153 % 100 = 53,然后53 / 10 = 5 package day_2023_4_4;public class ShuiTest {public static void ...

  8. 什么是水仙花数,使用Java的for循环简单输出100~999的水仙花数和个数

    水仙花是一种很美丽的花,那我们数学领域中有一种数字也是和水仙花般美的数字,叫做水仙花数,那么这种数字和其他数字有什么区别呢?水仙花数的特别之处在哪呢? 首先,水仙花数是一个三位数,也就是说,水仙花数的 ...

  9. java矩阵连乘算法_使用java写的矩阵乘法实例(Strassen算法)

    Strassen算法于1969年由德国数学家Strassen提出,该方法引入七个中间变量,每个中间变量都只需要进行一次乘法运算.而朴素算法却需要进行8次乘法运算. 原理 Strassen算法的原理如下 ...

最新文章

  1. JQuery整体简化学习
  2. iphone电池怎么保养_怎么保持iPhone的电池健康?掌握这4个方面,3年不用换电池...
  3. dubbo学习之服务消费者
  4. Highly Available (Mirrored) Queues
  5. C# 中使用HttpClient读取大型Json数据集
  6. sklearn集合算法预测泰坦尼克号幸存者
  7. C++ 深拷贝和浅拷贝
  8. 线程八锁,同步锁的应用
  9. 数据挖掘:模型选择——集成算法与树模型
  10. Linux内核启动过程
  11. String 常用方法总结
  12. 你真的懂协程 (Coroutine) 吗 ? Kotlin Coroutines — Suspending Functions
  13. 国家开放大学专科计算机应用实训项目,国家开放大学电大专科《微机系统与维护》网络课实训1实训3作业及答案.docx...
  14. java毕业设计智能小区物业管理系统Mybatis+系统+数据库+调试部署
  15. 我们的宇宙,在某种意义上,是最好的一个
  16. 经典Excel VBA代码
  17. hdu 1735 文字统计
  18. H3C 不同版本登录认证配置
  19. 怎么入驻亚马逊跨境电商平台?
  20. Python——创建二维列表的简易方法

热门文章

  1. 淘宝商品详情API接口(网页版,APP端二合一接口)
  2. win7matlab2016启动闪退,大白菜修复win7系统启动matlab出现闪退的图文方案
  3. 封闭解、解析解和数值解定义
  4. Single Image Haze Removal Using Dark Channel Prior 基于暗原色先验的单一图像去雾方法【翻译】
  5. 虹科分享 | 基于流的流量分类的工作原理 | 网络流量监控
  6. 红帽 RHCSA笔记
  7. 网络层路由选择协议(RIPOSF)
  8. 全球与中国云合同管理软件市场深度研究分析报告
  9. 牢记这一波CAD快捷键,制图速度坐火箭!
  10. Android 模仿淘宝历史记录,记录存在手机内