11的N次方

最近在网上看到一道题,感觉还蛮有意思的,题目要求要用程序实现11的N次方,这个N可能会很大,所以结果要用字符串表示。

在写程序之前我们先把测试用例写出来,这里从11的0次方到21次方都有测试到:

func TestPowOfEleven(t *testing.T) {var checkList = []string{"1", "11", "121", "1331", "14641", "161051", "1771561", "19487171", "214358881", "2357947691", "25937424601", "285311670611","3138428376721", "34522712143931", "379749833583241", "4177248169415651", "45949729863572161", "505447028499293771", "5559917313492231481", "61159090448414546291","672749994932560009201", "7400249944258160101211"}for index, value := range checkList {if value == PowerOfEleven(index) {t.Logf("Power Of %v is right", index)} else {t.Logf("Power Of %v is wrong, right value is %s, calculate value is %s", index, value, PowerOfEleven(index))}}
}

其实11的N次方是有一定的数学规律的,它满足帕斯卡三角形(杨辉三角),其实101的幂,1001的幂,10001的幂,也都是满足的。感兴趣可以研究一下。相关资料在拓展阅读中。

这道题的基本思路是快速幂+大数相乘。因为N很大的话数字是装不下的,只能用字符串表示,用字符串的话就用大数相乘,这是一个比较好的解决方法。N次方的话,为了优化计算速度,就要用快速幂的思想,把时间复杂度降低到log(N).话不多说,看看代码:

//计算11的N次方主要函数
func PowerOfEleven(n int) string {if n == 0 {return "1"}if n == 1 {return "11"}var baseNums = "11"var res = "1"for n > 0 {if n&1 == 1 {res = bigNumMultiplication(res, baseNums)}baseNums = bigNumMultiplication(baseNums, baseNums)n >>= 1}return res
}// 大数相乘
func bigNumMultiplication(nums1, nums2 string) string {bytes1, bytes2 := []byte(nums1), []byte(nums2)len1, len2 := len(bytes1), len(bytes2)var erveryLevels []stringfor i := len1 - 1; i >= 0; i-- {n1 := int(bytes1[i] - '0')flag := falseflagNum := 0var tempRes []bytefor k := 0; k < len1-1-i; k++ {tempRes = append(tempRes, '0')}for j := len2 - 1; j >= 0; j-- {n2 := int(bytes2[j] - '0')temp := n1 * n2if flag {temp += flagNumflag = falseflagNum = 0}if temp >= 10 {flag = trueflagNum = temp / 10}tempRes = append([]byte{byte(temp%10 + '0')}, tempRes...)}if flag {tempRes = append([]byte{byte(flagNum%10 + '0')}, tempRes...)}erveryLevels = append(erveryLevels, string(tempRes))}res := "0"for _, value := range erveryLevels {res = bigNumsAdd(res, value)}return res
}// 大数相加
func bigNumsAdd(nums1, nums2 string) string {if len(nums1) == 0 || nums1 == "" || nums1 == "0" {return nums2}if len(nums2) == 0 || nums2 == "" || nums2 == "0" {return nums1}nums1Bytes, nums2Bytes := []byte(nums1), []byte(nums2)index1, index2 := len(nums1Bytes)-1, len(nums2Bytes)-1flag := falsevar res []bytefor index1 >= 0 || index2 >= 0 {if index1 < 0 {n2 := int(nums2Bytes[index2] - '0')if flag {n2++flag = false}if n2 >= 10 {flag = true}res = append([]byte{byte(n2%10 + '0')}, res...)index2--continue}if index2 < 0 {n1 := int(nums2Bytes[index1] - '0')if flag {n1++flag = false}if n1 >= 10 {flag = true}res = append([]byte{byte(n1%10 + '0')}, res...)index1--continue}n1 := int(nums1Bytes[index1] - '0')n2 := int(nums2Bytes[index2] - '0')temp := n1 + n2if flag {temp++flag = false}if temp >= 10 {flag = true}res = append([]byte{byte(temp%10 + '0')}, res...)index1--index2--}if flag {res = append([]byte{'1'}, res...)}return string(res)
}

代码写完,跑跑单测,都跑过了,太nice了:

优化

细细想来,其实这个算法还是有可以优化的地方的,主要体现在大数相乘上面,如果我要计算的N次方还没有到计算机数字表示不了的时候,我们是不是可以用数字来直接参与计算和表示呢?其实是可以的。我们知道计算机可以表示的最大的数应该是无符号int64整数,在go种是uint64,也就是1 << 64 - 1.那么我们怎么计算小于1 << 64 - 1的11的最大次幂呢?这个思路还是比较简单的,因为数字表示不下的时候,会溢出,无论计算机的溢出策略是怎样的。这个时候必定存在一个N,使得在计算机中11的N + 1次方 / 11的N次方 != 11.所以下面代码就可以计算出这个11的最大次幂:

func calculateMaxPowerOf11() int {res, tempRes := uint64(1), uint64(11)num := 0for tempRes/res == 11 {res = tempRestempRes *= 11num++}return num
}

这里计算出来的是18.所以在N小于等于18之前用数字计算,得到结果之后转成字符串就好。下面代码是数字快速幂计算方式:

// 计算可用数字表示的最大的11的N次方
func calculatePowerOf11InNum(n int) uint64 {if n == 0 {return 1}if n == 1 {return 11}var res uint64 = 1baseNum := uint64(11)for n != 0 {if n&1 == 1 {res *= baseNum}n >>= 1baseNum *= baseNum}return res
}

可以通过下面代码验证18这个数的正确性:

func TestCalculateMaxPowerOf11(t *testing.T) {fmt.Println(calculatePowerOf11InNum(18))fmt.Println(calculatePowerOf11InNum(19))fmt.Println(calculatePowerOf11InNum(19) / calculatePowerOf11InNum(18))fmt.Println(calculatePowerOf11InNum(17))fmt.Println(calculatePowerOf11InNum(18))fmt.Println(calculatePowerOf11InNum(18) / calculatePowerOf11InNum(17))
}

结果是这样的:

可以看到19次方除18次方结果不是11,而18次方除17次方是11。是因为在19次方这里就发生了溢出。

基于这一点,我们可以把PowerOfEleven函数优化成下面这样子:

func PowerOfEleven(n int) string {if n == 0 {return "1"}if n == 1 {return "11"}if n <= calculateMaxPowerOf11() {res := calculatePowerOf11InNum(n)return strconv.FormatUint(res, 10)}var baseNums = "11"var res = "1"for n > 0 {if n&1 == 1 {res = bigNumMultiplication(res, baseNums)}baseNums = bigNumMultiplication(baseNums, baseNums)n >>= 1}return res
}

再跑一次单测:

完美通过,nice!!今天的分享到这里结束啦,感谢大家!

拓展阅读

  1. 杨辉三角:https://baijiahao.baidu.com/s?id=1607063654204393620&wfr=spider&for=pc
  2. 快速幂:https://zhuanlan.zhihu.com/p/95902286
  3. 大数相乘:https://blog.csdn.net/u010983881/article/details/77503519

个人推广

以下是笔者公众号,欢迎多多关注,一起成长。

计算11的N次方,N非常大相关推荐

  1. C语言_递归_计算x的y次方

    2020年9月18日 11:11:15 /* 编写递归函数getPower计算x的y次方 程序规定: x的y次方的整数形式, 当y<0时,返回0*/ /* 编写递归函数getPower计算x的y ...

  2. 计算 2 的 1000次方

    计算 2 的 1000次方 参考自:http://www.cnblogs.com/herbert/archive/2011/02/13/1953943.html Project Euler probl ...

  3. C语言:计算2的50次方需要多久?

    思路:1.电脑计算乘法时进行连续的加法计算,因此计算的数字总和为2的50次方即可. 2.由于用一般方法只能算到十位数,要把一项计算重复多次,运算量才相当于2的50次方. 代码: #include< ...

  4. 求e的c语言程序,(C语言)计算e的x次方

    计算e的x次方 题目:编写程序,计算 ex=1+x+(x2)/(2!)+(x3)/(3!)+(x4)/(4!)+-+(x^n)/n! 说明:e^x表示e的x次方,2!表示2的阶乘 输入输出格式要求: ...

  5. (C语言)计算e的x次方

    计算e的x次方 题目:编写程序,计算 ex=1+x+(x2)/(2!)+(x3)/(3!)+(x4)/(4!)+-+(x^n)/n! 说明:e^x表示e的x次方,2!表示2的阶乘 输入输出格式要求: ...

  6. 39页第7题 计算2的i次方之和

    /*计算2的i次方之和*/ #include<stdio.h> #include<math.h>/*调用math.h文件中的函数*/ int main(void) {int n ...

  7. PTA浙大版python程序设计题目集--第2章-1 计算 11+12+13+...+m (30 分)

    输入一个正整数m(20<=m<=100),计算 11+12+13+-+m 的值. 输入格式: 在一行输入一个正整数m. 输出格式: 在一行中按照格式"sum = S"输 ...

  8. Python计算 1的9999999次方,不到1s就得出答案!是如何处理的?

    问题引发 网友计算1的9999999次方,不到1s就得出答案.那python是如何处理的? >>> a=1 >>> i=a**9999999 >>> ...

  9. 从键盘上录入两个整数,计算a的b次方的结果

    从键盘上录入两个整数,计算a的b次方的结果 /*** 从键盘上录入两个整数,计算a的b次方的结果*/import java.util.Scanner;public class Test25 {publ ...

最新文章

  1. ElasticSearch面试题
  2. python vars 的用法
  3. left join on in
  4. Linux服务器上配置Tomcat的docBase路径映射时遇到的坑
  5. [AWS vs Azure] 云计算里AWS和Azure的探究(4)
  6. AMD收购Xilinx、Zoom为全体用户提供端到端加密、Facebook云游戏、苹果搜索引擎等|Decode the Week...
  7. cmd 调用JLink.exe 下载程序
  8. 广东省2021高考2bi补录成绩查询,重磅!广东省2021年普通高考美术统考成绩1月8日起可查询!...
  9. quartus管脚分配后需要保存吗_嵌入式必须会的一些硬件面试题,要试一试吗?你过来呀!...
  10. 不为失败找理由,只为成功找方法
  11. 单片机代码怎么读懂_单片机要这么学?八条谨记!
  12. vue导出Excel组件
  13. CUDA版本与驱动对应情况
  14. c语言中getnumber函数作用,C语言函数是什么
  15. linux命令界面切换桌面,Linux图形界面和命令行界面切换
  16. 高通voforia插件使相机对焦的方法
  17. 统计了300位硬件工程师的工资,我悟了
  18. 热门Java开发工具IDEA入门指南——如何安装IntelliJ IDEA(上)
  19. 这4个正经的网站,能看片还能涨知识!
  20. K8S数据采集组件metrics-server安装

热门文章

  1. C语言求田径场周长和面积,田径场尺寸计算及画法
  2. PMP/高项 项目管理培训大纲
  3. jy-12-SPRINGMYBATIS02——云笔记02-刘苍松
  4. 2021-2027全球与中国GPU服务器市场现状及未来发展趋势
  5. 营销值得学:创业做生意如何降维打击?
  6. mysql 5.5 slow log_mysql5.5开启慢日志slowlog的方法(log_slow_queries)_MySQL
  7. vue 根据链接生成二维码(功能实现)
  8. 2021牛客暑假多校第二场 K题—Stack (链表)
  9. dell10代cpu装linux,戴尔10代cpu装win7系统及bios设置|戴尔十代cpu台式机装win7
  10. 智能化运维最佳实践-自动化