前面已经学到了Kotlin的数据类型,那么就要用这些数据类型来做些事情。
一个程序,逃脱不了最基本的运行本质,那就是,分支判断和循环。一款程序无外乎从头到尾的执行,只是这个程序是否会停止,运行过程中的判断决定了程序运行的方向,循环可以让程序执行多次,和判断进行结合可以有更多的组合方式也会有更多的运行结果。
废话不说,直接上代码。
package cc.acme_me.kotlin
fun main(args: Array<String>) {
testWhile()
testDoWhile()
testFor()
printNarcissisticNumber(100, 1000000)
}
/**
* 水仙花数
* 水仙花指三位数的数值,每个位上的数的立方之和等于这个数
* 比如1^3 + 5^3 + 3^3 = 153
*/
fun testWhile() {
var num = 100
while (num < 1000) {
var a: Int = num.rem(10)//个位数
var b = (num.rem(100) - a) / 10//十位数
var c: Int = num / 100//百位数
//判断是否符合条件,这个写法比较恶心,而且效率也有问题,初学这门语言,所以先写以后语言特性什么学会了再优化
if (num == Math.pow(a.toDouble(), 3.0).toInt() + Math.pow(b.toDouble(), 3.0).toInt() + Math.pow(c.toDouble(), 3.0).toInt()) {
println("$a^3 + $b^3 + $c^3 = $num")
}
num++
}
}
/**
* 四叶玫瑰数
* 四叶玫瑰数四位数的数值,每个位上的数的四次方之和等于这个数
* 比如1^4 + 6^4 + 3^4 + 4^4 = 1634
*/
fun testDoWhile() {
var num = 1000
//while循环和do while循环的区别是前者先进行判断,满足条件后进入循环体,后者与之相反,先运行循环体再进行判断是否满足条件进行一下次循环
do {
var a: Int = num.rem(10)//个位数
var b = num.rem(100) / 10//十位数
var c: Int = num.rem(1000) / 100//百位数
var d: Int = num / 1000//千位数
if (num == Math.pow(a.toDouble(), 4.0).toInt() + Math.pow(b.toDouble(), 4.0).toInt() + Math.pow(c.toDouble(), 4.0).toInt() + Math.pow(d.toDouble(), 4.0).toInt()) {
println("$a^4 + $b^4 + $c^4 + $d^4 = $num")
}
num++
} while (num < 10000)
}
/**
* 五角星数
* 五角星数是五位数的数值,每个位上的数的五次方之和等于这个数
* 比如5^5 + 4^5 + 7^5 + 4^5 + 8^5 = 54748
*/
fun testFor() {
//声明一个数组并且赋值10000~99999闭区间(包含头尾)
//下面的一条等价于 var num = 10000 until 100000 前闭后开区间(包含头不包含尾)
var num = 10000..99999
//在这个情况下step 1可以省略 这个可以理解为i++ 如果递增是i+=2的时候可以写成step 2 以此类推
for (i in num step 1) {
var a: Int = i.rem(10)//个位数
var b: Int = i.rem(100) / 10//十位数
var c: Int = i.rem(1000) / 100//百位数
var d: Int = i.rem(10000) / 1000//千位数
var e: Int = i / 10000 //万位数
if (i == Math.pow(a.toDouble(), 5.0).toInt() + Math.pow(b.toDouble(), 5.0).toInt() + Math.pow(c.toDouble(), 5.0).toInt() + Math.pow(d.toDouble(), 5.0).toInt() + Math.pow(e.toDouble(), 5.0).toInt()) {
println("$a^5 + $b^5 + $c^5 + $d^5 + $e^5 = $i")
}
}
}
/**
* 输入开始值和结束值,在这个范围内寻找水仙花数并且打印出来
*/
fun printNarcissisticNumber(startNum: Int, endNum: Int) {
//Kotlin的三目运算符 我这么做是确定最小的值作为起始位置
var innerStartNum = if (endNum < startNum) endNum else startNum
//和上面差不多的意思 决定大的值作为结束位置
var innerEndNum = if (endNum > startNum) endNum else startNum
//上面两行代码等同于下面的判断,上面是为了用一下三目运算
/*if (startNum > endNum) {
inner_startNum = endNum
inner_endNum = startNum
} else {
inner_endNum = endNum
inner_startNum = startNum
}*/
//最小的水仙花数是153,如果结束位置比这个小,那么这个程序就没有运行下去的意义了
if (innerEndNum < 153) {
println("您输入数值范围内没有水仙花数!")
return
}
//水仙花数至少要三位数,所以如果给了两位数,那么就要让它变到三位数
//为什么放到153 因为已经满足上面的条件,说明数值范围内肯定是有水仙花数的,那么就从第一个水仙花数开始
if (innerStartNum < 153) {
innerStartNum = 153
}
//记录取值范围内水仙花数的数量
var numCount: Int = 0
//将取值范围变成数组然后开始循环
var nums = innerStartNum..innerEndNum
//step 1 可以省略,因为默认就是1
for (i in nums) {
//指数是多少,因为三位水仙花是三次幂 四位是四次 五位是五次 以此类推
var index: Int = i.toString().length
//下面这一段写得很恶心,而且效率真的很低,所以先这样写一下 将来再优化
//十位数先计算出来
var count: Int = (Math.pow(i.rem(10).toDouble(), index.toDouble())).toInt()
//这里是计算百位数到第二最高位
var b = 2 until index
for (j in b) {
count += Math.pow(((i.rem(Math.pow(10.0, j.toDouble())).toInt() / Math.pow(10.0, (j - 1).toDouble()).toInt()).toDouble()), index.toDouble()).toInt()
}
//最后在计算最高位
count += Math.pow((i / Math.pow(10.0, (index - 1).toDouble()).toInt()).toDouble(), index.toDouble()).toInt()
if (i == count) {
numCount++
print("$i ")
}
}
//这个存在的意义就是,如果取值范围内没有水仙花数,但是程序什么都没显示感觉比较难看,所以没有水仙花数提醒一下
if (numCount == 0) {
println("您输入数值范围内没有水仙花数!")
}
}
acme