二项式定理——力扣2221.数组的三角和
力扣2221.数组的三角和
【LeetCode 2221】数组的三角和 —— 题解与思路详解
题目描述
给你一个下标从 0 开始的整数数组 nums
,其中 nums[i]
是 0 到 9 之间的一个数字。
定义数组的三角和计算规则如下:
-
如果数组长度
n == 1
,则直接返回该元素。 -
否则,生成一个新的数组
newNums
,它的长度为n - 1
。
对于每个下标i
(0 ≤ i < n - 1),计算:newNums[i] = (nums[i] + nums[i+1]) % 10
然后用
newNums
替换nums
。 -
重复以上步骤,直到数组只剩下一个元素。
-
返回这个唯一的元素。
示例 1
输入: nums = [1,2,3,4,5]
输出: 8
计算过程:
[1,2,3,4,5]
[3,5,7,9]
[8,2,6]
[0,8]
[8]
最终结果为 8。
示例 2
输入: nums = [5]
输出: 5
数组只有一个元素,直接返回 5。
题目限制
- 1 <= nums.length <= 1000
- 0 <= nums[i] <= 9
思路分析
这道题的本质是不断将数组压缩,每次计算相邻两数之和的个位数,直到只剩下一个数。
常见的两种解法如下:
解法一:模拟法(直观解)
最直接的思路就是模拟题目描述的步骤:
- 不断生成新数组
newNums
。 - 每次长度减少 1,直到只剩下一个数。
时间复杂度
- 每次操作长度减少 1,总共有
n-1
轮操作。 - 第 1 轮长度 n,第 2 轮长度 n-1,… 最后一轮长度 1。
- 总操作次数为
n + (n-1) + ... + 1 = O(n^2)
。
空间复杂度
- 可以原地修改,不需要新数组,O(1)。
代码(Java 示例):
class Solution {public int triangularSum(int[] nums) {int n = nums.length;while (n > 1) {for (int i = 0; i < n - 1; i++) {nums[i] = (nums[i] + nums[i + 1]) % 10;}n--; // 数组长度减少 1}return nums[0];}
}
解释:
每次只需要覆盖前 n-1 个元素,不用额外开新数组。最终结果就是 nums[0]
。
解法二:数学优化(组合数 + 二项式定理)
仔细观察会发现这个过程其实和杨辉三角(组合数)类似。
举例 nums = [1,2,3,4,5]
:
1 2 3 4 5\ / \ / \ / \ /3 5 7 9\ / \ / \ /8 2 6\ / \ /0 8\ /8
最终结果可以表示为:
sum(nums[i] * C(n-1, i)) % 10
其中 C(n-1, i)
是组合数。
计算示例:
nums = [1,2,3,4,5], n=5
结果 = 1*C(4,0) + 2*C(4,1) + 3*C(4,2) + 4*C(4,3) + 5*C(4,4)= 1*1 + 2*4 + 3*6 + 4*4 + 5*1= 1 + 8 + 18 + 16 + 5= 48
48 % 10 = 8
和模拟结果一致。
这种方法的时间复杂度为 O(n),空间复杂度为 O(1)。
总结
- 模拟法:代码简单直观,时间复杂度 O(n^2)。在
n <= 1000
的范围内可接受。 - 数学优化:利用组合数公式,将最终结果转化为加权和,时间复杂度 O(n)。更高效。
最终代码(推荐:模拟法,简单好写)
class Solution {public int triangularSum(int[] nums) {int n = nums.length;while (n > 1) {for (int i = 0; i < n - 1; i++) {nums[i] = (nums[i] + nums[i + 1]) % 10;}n--;}return nums[0];}
}
扩展思考
- 如果数组长度非常大,例如
10^6
以上,模拟法会超时。这时必须用组合数公式。 - 本题和杨辉三角密切相关,以后遇到类似“逐层相加”的问题,可以优先考虑组合数规律。