对于给定的数组[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语言:如何删除在可视化网页中未可见的内容(网页txt)

    我这个代码仅仅限制于在chrome浏览器中下载china daliy的网页中实现删除可视化内容,因为每个网页的超链接或者文本主内容分布不一样,但是学会了删除一个网页类型的不可视化内容之后,修改其他网页 ...

  2. NumPy 数组迭代与合并详解

    NumPy 数组迭代 NumPy 数组迭代是访问和处理数组元素的重要方法.它允许您逐个或成组地遍历数组元素. 基本迭代 我们可以使用 Python 的基本 for 循环来迭代 NumPy 数组. 一维 ...

  3. 解析 ABP vNext 依赖注入实现【属性注入】的原理

    前言 这几天闲来没事看看ABP vNext的文档和源码,关于关于依赖注入(属性注入)这块儿产生了兴趣. 我们都知道.Volo.ABP 依赖注入容器使用了第三方组件Autofac实现的.有三种注入方式, ...

  4. 深度学习项目-MobileNetV2水果识别模型

    FruitRecognition DeepLearning深度学习小项目,利用CNN和MobileNetV2搭建的水果识别模型. github地址 fruit为本次大作业使用的数据集. geneFru ...

  5. C#的GroupBy方法是如何工作的

    前言:先贴结果 GroupBy方法是如何工作的? 一.准备6个待分组的学生对象 class student { public string name;//姓名 public int grade;//年 ...

  6. FFmpeg开发笔记(二十三)使用OBS Studio开启RTMP直播推流

    ​OBS是一个开源的直播录制软件,英文全称叫做Open Broadcaster Software,广泛用于视频录制.实时直播等领域.OBS不但开源,而且跨平台,兼容Windows.Mac OS.Lin ...

  7. js 中你不知道的各种循环测速

    在前端 js 中,有着多种数组循环的方式: for 循环: while 和 do-while 循环: forEach.map.reduce.filter 循环: for-of 循环: for-in 循 ...

  8. Vue cli路由

    上面是将Forecast组件作为了Home的子组件使用,现在我们将其作为一个路由组件使用. 在router/index.js路由系统注册路由: { path: '/forecast', name: ' ...

  9. NSInvocation 返回值在ARC下面的释放问题

    一.先看下面的代码 -(NSArray *) operationFromTakeoffAction:(NSString *) action AtPoint:(CGPoint) flightPoint ...

  10. XML Web 服务技术解析:WSDL 与 SOAP 原理、应用案例一览

    XML Web服务是一种用于在网络上发布.发现和使用应用程序组件的技术.它基于一系列标准和协议,如WSDL.SOAP.RDF和RSS.下面是一些相关的内容: WSDL(Web服务描述语言):用于描述W ...