对于给定的数组[x1,x2,x3,…,xn],计算幂的累积:x1^(x2^(x3^(…^xn))的最后一位(十进制)数字。

例如,对于数组[3,4,2],您的代码应该返回1,因为3^(4^2)=3^16=43046721。

结果的增长得快得令人难以置信。例如,9^(9^9)有超过3.69亿个数字。你计算的lastDigit必须有效地处理这些数字。

我们假设0^0=1,并且空列表的lastDigit等于1。


算法实现:

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Numerics;
5 namespace Solution
6 {
7 public class Calculator
8 {
9 public static int LastDigit(int[] array)
10 {
11 BigInteger t = 1;
12 var arr = array.Reverse().ToList();
13
14 foreach(var x in arr)
15 {
16 if(t < 4)
17 t = BigInteger.Pow(x,int.Parse(t.ToString()));
18 else
19 {
20 int exponent = int.Parse(BigInteger.ModPow(t,1,4).ToString()) + 4;
21 t = BigInteger.Pow(x,exponent);
22 }
23 }
24
25 return (int)BigInteger.ModPow(t,1,10);
26 }
27 }
28 }

算法详解:

 1 public static int LastDigit(int[] array)
2 {
3 BigInteger t = 1; // 初始化变量t为1,用于存储计算结果
4 var arr = array.Reverse().ToList(); // 将输入数组倒序并转换为列表
5
6 foreach(var x in arr) // 对列表中的每个元素进行循环遍历
7 {
8 if(t < 4) // 如果t小于4
9 t = BigInteger.Pow(x, int.Parse(t.ToString())); // 使用x的t次方更新t
10 else // 如果t大于等于4
11 {
12 int exponent = int.Parse(BigInteger.ModPow(t, 1, 4).ToString()) + 4; // 计算指数值,将t对4取模后加上4
13 t = BigInteger.Pow(x, exponent); // 使用x的exponent次方更新t
14 }
15 }
16
17 return (int)BigInteger.ModPow(t, 1, 10); // 返回t对10取模的结果作为最后一位数字
18 }

在代码中,判断 if(t < 4) 的目的是为了处理指数较小的情况。当指数较小(小于4)时,直接使用 BigInteger.Pow(x, int.Parse(t.ToString())) 计算 x 的指数结果,并将结果赋给变量 t

这是因为指数较小的情况下,计算结果不会非常大,可以直接使用 BigInteger.Pow 方法进行计算。这种情况下,不需要进行额外的处理,直接将计算结果赋给 t 即可。

而当指数较大(大于等于4)时,为了避免计算结果过大导致性能问题,代码使用了一种降幂优化策略。在这种情况下,通过计算 t 的模 4 的结果(BigInteger.ModPow(t, 1, 4)),并加上4,得到一个新的指数值 exponent。然后使用 BigInteger.Pow(x, exponent) 计算 x 的新指数结果,并将结果赋给 t

因此,if(t < 4) 分支用于处理指数较小的情况,而 else 分支用于处理指数较大的情况,并进行了一种优化策略来避免计算结果过大。这样可以在不牺牲性能的情况下,处理更大的指数值。

让我们通过一个示例来解释这个降幂计算过程。

假设我们有以下输入数据:
- `x = 2`:底数为2。
- `t = 10`:指数为10。

根据代码逻辑,我们首先检查指数是否大于等于4。在这种情况下,指数为10大于4,因此我们需要执行优化策略。

1. 计算 `t` 对 4 取模的结果:
- `t_mod4 = t % 4 = 10 % 4 = 2`
这里我们使用 `%` 运算符来计算 `t` 对 4 取模的结果,得到 `2`。

2. 将 `t_mod4` 加上 4,得到新的指数值 `exponent`:
- `exponent = t_mod4 + 4 = 2 + 4 = 6`
这里我们将 `t_mod4` 的结果 `2` 加上 4,得到新的指数值 `6`。

3. 计算 `x` 的新指数结果:
- `new_t = BigInteger.Pow(x, exponent) = BigInteger.Pow(2, 6) = 64`
这里我们使用 `BigInteger.Pow` 方法计算 `x` 的新指数结果,即将底数 `2` 的指数值设为 `6`,得到 `64`。

4. 将新的指数结果赋给 `t`:
- `t = new_t = 64`
我们将计算得到的新指数结果 `64` 赋给变量 `t`。

最后,我们得到的结果是 `t = 64`。这个结果将在后续的代码中继续使用,进行其他的计算或操作。

这就是当指数较大时,代码使用的优化策略的步骤。通过对指数取模并加上一个固定值,我们得到一个较小的指数值,以避免计算结果过大导致性能问题。


测试用例:

  1 namespace Solution {
2 using NUnit.Framework;
3 using System;
4
5 public struct LDCase {
6 public int[] test;
7 public int expect;
8 public LDCase(int[] t, int e) {
9 test = t;
10 expect = e;
11 }
12 }
13
14 [TestFixture]
15 public class SolutionTest {
16 private static int CalculateLD(int[] array) {
17 int ans = 1;
18 for(int i=array.Length-1; i>=0;i--) {
19 int exp = ans;
20 if(ans >= 4) {
21 exp = ans%4+4;
22 }
23 int b = array[i]%4+4;
24 if(i == 0) {
25 b = array[i]%10;
26 }
27 else if(array[i] < 4) {
28 b = array[i];
29 }
30 ans = (int)(Math.Pow(b, exp));
31 }
32 return ans%10;
33 }
34
35 [Test]
36 public void SampleTest() {
37 LDCase[] allCases = new LDCase[] {
38 new LDCase(new int[0], 1),
39 new LDCase(new int[] {0,0}, 1),
40 new LDCase(new int[] {0,0,0}, 0),
41 new LDCase(new int[] {1,2}, 1),
42 new LDCase(new int[] {3,3,1}, 7),
43 new LDCase(new int[] {3,3,2}, 3),
44 new LDCase(new int[] {3,5,3}, 3),
45 new LDCase(new int[] {3,4,5}, 1),
46 new LDCase(new int[] {4,3,6}, 4),
47 new LDCase(new int[] {7,6,1}, 9),
48 new LDCase(new int[] {7,6,2}, 1),
49 new LDCase(new int[] {7,6,21}, 1),
50 new LDCase(new int[] {12,30,21}, 6),
51 new LDCase(new int[] {2,0,1}, 1),
52 new LDCase(new int[] {2,2,2,0}, 4),
53 new LDCase(new int[] {2,2,101,2},6),
54 new LDCase(new int[] {4,0}, 1),
55 new LDCase(new int[] {3,0,0}, 3),
56 new LDCase(new int[] {2,2,1}, 4),
57 new LDCase(new int[] {2,2,1,2}, 4),
58 new LDCase(new int[] {3,3,0,0}, 7),
59 new LDCase(new int[] {3,4,0}, 3),
60 new LDCase(new int[] {3,2,1,4,4},9),
61 new LDCase(new int[] {5,0}, 1),
62 new LDCase(new int[] {2,3,2}, 2),
63 new LDCase(new int[] {82242,254719,736371}, 8),
64 new LDCase(new int[] {937640,767456,981242}, 0),
65 new LDCase(new int[] {123232,694022,140249}, 6),
66 new LDCase(new int[] {499942,898102,846073}, 6),
67 new LDCase(new int[] {837142,918895,51096}, 2),
68 new LDCase(new int[] {625703,43898,614961,448629}, 1),
69 new LDCase(new int[] {2147483647,2147483647,2147483647,2147483647}, 3)
70 };
71 for(int i=0; i<allCases.Length;i++) {
72 string msg = $"Incorrect answer for array=[{string.Join(", ", allCases[i].test)}]";
73 Assert.AreEqual(allCases[i].expect, Calculator.LastDigit(allCases[i].test), msg);
74 }
75 }
76
77 [Test]
78 public void RandomTest() {
79 Random rnd = new Random();
80
81 for(int i=0; i<100;i++) {
82 int size = rnd.Next(1,20);
83 int[] array1 = new int[size];
84 int[] array2 = new int[size];
85 int[] array3 = new int[size];
86 for(var j=0; j<size;j++) {
87 var rand1 = rnd.Next(0,1000000);
88 var rand2 = rnd.Next(0,3);
89 var rand3 = rnd.Next(0,2);
90 if(j == 0) {
91 rand1++; rand2++; rand3++;
92 }
93 array1[j] = rand1;
94 array2[j] = rand2;
95 array3[j] = rand3;
96 }
97
98 string msg1 = $"Incorrect answer for array=[{string.Join(", ", array1)}]";
99 int expect1 = SolutionTest.CalculateLD(array1);
100 Assert.AreEqual(expect1, Calculator.LastDigit(array1), msg1);
101
102 string msg2 = $"Incorrect answer for array=[{string.Join(", ", array2)}]";
103 int expect2 = SolutionTest.CalculateLD(array2);
104 Assert.AreEqual(expect2, Calculator.LastDigit(array2), msg2);
105
106 string msg3 = $"Incorrect answer for array=[{string.Join(", ", array3)}]";
107 int expect3 = SolutionTest.CalculateLD(array3);
108 Assert.AreEqual(expect3, Calculator.LastDigit(array3), msg3);
109 }
110 }
111 }
112 }

【算法】用c#实现计算方法中的经典降幂优化策略,减少计算复杂度的更多相关文章

  1. MySQL中SQL语句常见优化策略

    1.避免全表扫描 对查询进行优化,应尽量避免全表扫描,首先应考虑在where 及order by 涉及的列上建立索引. 2.避免判断null 值 应尽量避免在where 子句中对字段进行null 值判 ...

  2. .Net中的并行编程-6.常用优化策略

                本文是.Net中的并行编程第六篇,今天就介绍一些我在实际项目中的一些常用优化策略.      一.避免线程之间共享数据 避免线程之间共享数据主要是因为锁的问题,无论什么粒度的锁 ...

  3. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

  4. Java中的经典算法之选择排序(SelectionSort)

    Java中的经典算法之选择排序(SelectionSort) 神话丿小王子的博客主页 a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕.也就是:每一趟 ...

  5. Java中的经典算法之快速排序(Quick Sort)

    Java中的经典算法之快速排序(Quick Sort) 快速排序的思想 基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小, 然后再按此方法对 ...

  6. LeetCode初级算法--字符串02:字符串中的第一个唯一字符

    LeetCode初级算法--字符串02:字符串中的第一个唯一字符 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog. ...

  7. .net core 中的经典设计模式的应用

    .net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...

  8. C语言中的经典例题用javascript怎么解?(一)

    C语言中的经典例题用javascript怎么解?(一) 一.1+2+3+……+100=?        <script type="text/javascript">  ...

  9. MATLAB对于文本文件(txt)数据读取的技巧总结(经典中的经典)

    振动论坛原版主eight的经典贴http://www.chinavib.com/thread-45622-1-1.html MATLAB对于文本文件(txt)进行数据读取的技巧总结(经典中的经典)由于 ...

  10. 如何在ubuntu 12.04 中安装经典的 GNOME桌面

    这次介绍的是如何在ubuntu 12.04 中安装经典的 GNOME桌面,默认的 Ubuntu 12.04 默认unity桌面,一些用户不喜欢 Unity 桌面,所以想找回昔日的经典Gnome桌面. ...

随机推荐

  1. 用 C 语言开发一门编程语言 — 异常处理

    目录 文章目录 目录 前文列表 异常捕获 定义 Lisp Value 函数 前文列表 <用 C 语言开发一门编程语言 - 交互式解析器l> <用 C 语言开发一门编程语言 - 跨平台 ...

  2. C# Socket 封包 拆包 ProtoBuf 的使用

    //这是消息头包,消息头包大小是固定的, //每次传输都要先传消息头,在传消息体 enum EnumMsgType:消息类型 long PackgeSize:包大小 long TotalPackage ...

  3. 未能加载文件或程序集“UFIDA.U8.UAP.GcRegister, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项

    这是做采购入库单新增的时候遇到的问题,我是采用模仿写用友u8的zpurrkdhead 主表视图和子表视图zpurrkdtail 去构建 xml文档这样做的,但是再做的时候 [cgcroutecode] ...

  4. Flyway简单迁移失败问题

    因为我是初学者,所以问题 只是一些细节性问题,现在看看V开头创建数据库迁移时的错误 问题一: flyway 命名规则问题这个绝对的细节中的细节问题 问题一解决方案: 命名规则:一定要遵循flyway的 ...

  5. 【web】自定义协议Protocol URL

    URL Protocol(自定义协议)可以让web页面调用本地exe程序,这个神奇的功能是怎么实现的呢? URL ProtocolURL Protocol,没错就是标题里所说的自定义协议.这玩意儿大家 ...

  6. ASP.NET Core SignalR 概述

    什么是 SignalR? ASP.NET Core SignalR 是一个开放源代码库,可用于简化向应用添加实时 Web 功能. 实时 Web 功能使服务器端代码能够将内容推送到客户端. 适合 Sig ...

  7. RSS 解析:全球内容分发的利器及使用技巧

    使用 RSS 可以将最新的网络内容从一个网站分发到全球数千个其他网站. RSS 允许快速浏览新闻和更新. RSS 文档示例 <?xml version="1.0" encod ...

  8. Excel Wps 透视表去重计数方法

    Excel Wps 透视表去重计数方法 在处理表格,遇到处理根据某个列去重后统计数量,而不是仅仅统计数量.在网上查找资料,不确定EXCEL或者WPS某个版本可以支持该功能的实现. 折中的方案,分两步来 ...

  9. RestApi请求地址支持多路径访问

    RestApi请求地址支持多路径访问 @RestController@RequestMapping("/test") //单路径@RequestMapping(path = {&q ...

  10. FreeRTOS简单内核实现3 任务管理

    0.思考与回答 0.1.思考一 对于 Cotex-M4 内核的 MCU 在发生异常/中断时,哪些寄存器会自动入栈,哪些需要手动入栈? 会自动入栈的寄存器如下 R0 - R3:通用寄存器 R12:通用寄 ...