【算法】用c#实现计算方法中的经典降幂优化策略,减少计算复杂度
对于给定的数组[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#实现计算方法中的经典降幂优化策略,减少计算复杂度的更多相关文章
- MySQL中SQL语句常见优化策略
1.避免全表扫描 对查询进行优化,应尽量避免全表扫描,首先应考虑在where 及order by 涉及的列上建立索引. 2.避免判断null 值 应尽量避免在where 子句中对字段进行null 值判 ...
- .Net中的并行编程-6.常用优化策略
本文是.Net中的并行编程第六篇,今天就介绍一些我在实际项目中的一些常用优化策略. 一.避免线程之间共享数据 避免线程之间共享数据主要是因为锁的问题,无论什么粒度的锁 ...
- Java中的经典算法之冒泡排序(Bubble Sort)
Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...
- Java中的经典算法之选择排序(SelectionSort)
Java中的经典算法之选择排序(SelectionSort) 神话丿小王子的博客主页 a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕.也就是:每一趟 ...
- Java中的经典算法之快速排序(Quick Sort)
Java中的经典算法之快速排序(Quick Sort) 快速排序的思想 基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小, 然后再按此方法对 ...
- LeetCode初级算法--字符串02:字符串中的第一个唯一字符
LeetCode初级算法--字符串02:字符串中的第一个唯一字符 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog. ...
- .net core 中的经典设计模式的应用
.net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...
- C语言中的经典例题用javascript怎么解?(一)
C语言中的经典例题用javascript怎么解?(一) 一.1+2+3+……+100=? <script type="text/javascript"> ...
- MATLAB对于文本文件(txt)数据读取的技巧总结(经典中的经典)
振动论坛原版主eight的经典贴http://www.chinavib.com/thread-45622-1-1.html MATLAB对于文本文件(txt)进行数据读取的技巧总结(经典中的经典)由于 ...
- 如何在ubuntu 12.04 中安装经典的 GNOME桌面
这次介绍的是如何在ubuntu 12.04 中安装经典的 GNOME桌面,默认的 Ubuntu 12.04 默认unity桌面,一些用户不喜欢 Unity 桌面,所以想找回昔日的经典Gnome桌面. ...
随机推荐
- 用 C 语言开发一门编程语言 — 交互式解释器
目录 文章目录 目录 前言 环境 编译型 vs 解释型 实现交互式解释器 使用 GNU Readline 函数库 前言 通过开发一门类 Lisp 的编程语言来理解编程语言的设计思想,本实践来自著名的& ...
- 初识上位机(下):C#读写PLC数据块数据
大家好,我是Edison. 作为一个工业自动化领域的程序员,不懂点PLC和上位机,貌似有点说不过去.这里我用两篇小文带你快速进入上位机开发领域.后续,我会考虑再出一个系列文章一起玩工控上位机. 上一篇 ...
- T2T-ViT:更多的局部结构信息,更高效的主干网络 | ICCV 2021
论文提出了T2T-ViT模型,引入tokens-to-token(T2T)模块有效地融合图像的结构信息,同时借鉴CNN结果设计了deep-narrow的ViT主干网络,增强特征的丰富性.在ImageN ...
- ENVI自动地理配准:GCP地面控制点的自动产生
本文介绍基于ENVI软件,利用"Image Registration Workflow"工具实现栅格遥感影像自动寻找地面控制点从而实现地理配准的方法. 在ENVI手动地理配 ...
- Vue 3入门指南
title: Vue 3入门指南 date: 2024/5/23 19:37:34 updated: 2024/5/23 19:37:34 categories: 前端开发 tags: 框架对比 环境 ...
- 微信小程序,wx.getUserProfile接口将被收回,新的头像获取方式永久保存
微信文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ 新的获取头像方式:https://developers.weixin. ...
- .Net6 MiNiApi +EFCore6.0高B格操作的WebApi
编辑器的选择项目运行雏形EFCore6.0的使用实体创建![在这里插入图片描述](https://img-blog.csdnimg.cn/abe224cea341434c9299e9643dbcd9e ...
- 一文带你理解透MyBatis源码
本文分享自华为云社区<一文彻底吃透MyBatis源码!!>,作者:冰 河. 写在前面 随着互联网的发展,越来越多的公司摒弃了Hibernate,而选择拥抱了MyBatis.而且,很多大厂在 ...
- MySQL学习笔记-数据控制语言
SQL-数据控制语言(DCL) DCL语句用于管理数据库用户,控制数据库的访问权限 一. 管理用户 1. 查询用户 # 访问mysql数据库 use mysql; #查询user表 select * ...
- Java中的Collection集合(单列集合)
1.集合概述 集合:集合是java中提供的一种容器,可以用来存储多个数据. 集合与数组的区别: (1)数组的长度是固定的,集合的长度是可变的. (2)数组中存储的是同一类型的元素,可以存储基本数据类型 ...