当前位置:首页>java>LeetCode:乘积最大子数组代码实现与单元测试·

LeetCode:乘积最大子数组代码实现与单元测试·

  • 2026-09-07 18:50:00
LeetCode:乘积最大子数组代码实现与单元测试·
题目:

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

请注意,一个只包含一个元素的数组的乘积是这个元素的值。

示例 1:

输入: nums = [2,3,-2,4]输出:6解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

输入: nums = [-2,0,-1]输出: 0解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

提示:

  • 1 <= nums.length <= 2 * 104
  • -10 <= nums[i] <= 10
  • nums
     的任何子数组的乘积都 保证 是一个 32-位 整数
代码实现:
def maxProduct(nums):    """    找出数组中乘积最大的非空连续子数组    参数:        nums: 整数数组    返回:        最大乘积(32位整数)    """    if not nums:        return 0    # 初始化当前最大乘积、当前最小乘积和全局最大乘积    cur_max = cur_min = global_max = nums[0]    for i in range(1, len(nums)):        num = nums[i]        # 如果当前数是负数,交换最大和最小值(因为负负得正)        if num < 0:            cur_max, cur_min = cur_min, cur_max        # 更新当前最大和最小乘积        cur_max = max(num, cur_max * num)        cur_min = min(num, cur_min * num)        # 更新全局最大乘积        global_max = max(global_max, cur_max)    return global_max# 测试示例if __name__ == "__main__":    # 示例1    nums1 = [2, 3, -2, 4]    print(f"示例1: {maxProduct(nums1)}")  # 输出: 6    # 示例2    nums2 = [-2, 0, -1]    print(f"示例2: {maxProduct(nums2)}")  # 输出: 0    # 额外测试用例    nums3 = [-2, 3, -4]    print(f"测试用例: {maxProduct(nums3)}")  # 输出: 24 (-2 × 3 × -4 = 24)    nums4 = [0, 2]    print(f"测试用例: {maxProduct(nums4)}")  # 输出: 2

算法说明

关键洞察

  • 负负得正:两个负数相乘得到正数,所以需要同时跟踪最小乘积

  • 零的影响:遇到零时,乘积会重置为零,需要重新开始计算

执行过程示例

以 nums = [2, 3, -2, 4]为例:

最终结果:6(对应子数组 [2, 3])

复杂度分析

  • 时间复杂度:O(n),只需遍历数组一次

  • 空间复杂度:O(1),只使用常数级别的额外空间

替代实现(更直观的版本)

如果您觉得上述代码的逻辑不够直观,这里有一个更易理解的版本:

def maxProduct_alternative(nums):    if not nums:        return 0    cur_max = cur_min = global_max = nums[0]    for i in range(1, len(nums)):        num = nums[i]        # 同时计算三种可能的值        candidates = [num, cur_max * num, cur_min * num]        # 更新当前最大和最小值        cur_max = max(candidates)        cur_min = min(candidates)        # 更新全局最大值        global_max = max(global_max, cur_max)    return global_max
单元测试验证:
import unittestfrom typing import Listdef maxProduct_alternative(nums: List[int]) -> int:    """    找出数组中乘积最大的非空连续子数组    参数:        nums: 整数数组    返回:        最大乘积(32位整数)    """    if not nums:        return 0    cur_max = cur_min = global_max = nums[0]    for i in range(1, len(nums)):        num = nums[i]        # 同时计算三种可能的值        candidates = [num, cur_max * num, cur_min * num]        # 更新当前最大和最小值        cur_max = max(candidates)        cur_min = min(candidates)        # 更新全局最大值        global_max = max(global_max, cur_max)    return global_maxclass TestMaxProductAlternative(unittest.TestCase):    """测试乘积最大子数组的替代算法"""    def test_empty_array(self):        """测试空数组"""        self.assertEqual(maxProduct_alternative([]), 0)    def test_single_element(self):        """测试单元素数组"""        self.assertEqual(maxProduct_alternative([5]), 5)        self.assertEqual(maxProduct_alternative([-3]), -3)        self.assertEqual(maxProduct_alternative([0]), 0)    def test_all_positive(self):        """测试全正数数组"""        self.assertEqual(maxProduct_alternative([1, 2, 3, 4]), 24)  # 全部相乘        self.assertEqual(maxProduct_alternative([3, 2, 1]), 6)  # 3×2=6    def test_all_negative(self):        """测试全负数数组"""        self.assertEqual(maxProduct_alternative([-2, -3, -4]), 12)  # -3×-4=12        self.assertEqual(maxProduct_alternative([-1, -2]), 2)  # -1×-2=2    def test_mixed_positive_negative(self):        """测试正负数混合数组"""        self.assertEqual(maxProduct_alternative([2, 3, -2, 4]), 6)  # 2×3=6        self.assertEqual(maxProduct_alternative([-2, 3, -4]), 24)  # 3×-2×-4=24    def test_with_zeros(self):        """测试包含零的数组"""        self.assertEqual(maxProduct_alternative([0, 2]), 2)  # 最大为2        self.assertEqual(maxProduct_alternative([2, 0, 3]), 3)  # 最大为3        self.assertEqual(maxProduct_alternative([-2, 0, -1]), 0)  # 最大为0    def test_leetcode_examples(self):        """测试LeetCode官方示例"""        # 示例1        self.assertEqual(maxProduct_alternative([2, 3, -2, 4]), 6)        # 示例2        self.assertEqual(maxProduct_alternative([-2, 0, -1]), 0)    def test_edge_cases(self):        """测试边界情况"""        # 最小数组        self.assertEqual(maxProduct_alternative([1]), 1)        # 包含最小整数        self.assertEqual(maxProduct_alternative([-10]), -10)        # 两个元素        self.assertEqual(maxProduct_alternative([-2, 3]), 3)    def test_complex_scenarios(self):        """测试复杂场景"""        # 需要动态更新cur_min的情况        self.assertEqual(maxProduct_alternative([-2, 3, -4]), 24)        # 多个负数        self.assertEqual(maxProduct_alternative([-1, -2, -3, -4]), 24)        # 正负交替        self.assertEqual(maxProduct_alternative([1, -2, 3, -4, 5]), 120)  # 3×-4×5=60不对,应该是全部相乘    def test_greedy_failure_cases(self):        """测试贪心算法会失败的案例"""        # 这个案例说明为什么需要同时维护max和min        nums = [3, -1, 4]  # 最大乘积应该是4,不是3        self.assertEqual(maxProduct_alternative(nums), 4)        # 另一个经典案例        nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]        # 最大乘积子数组应该是[4,-1,2,1]乘积为-8?不对,应该是[4]或者[4,-1,2,1]需要验证        # 先计算一下:4×-1×2×1 = -8,所以最大应该是4        self.assertEqual(maxProduct_alternative(nums), 4)    def test_large_numbers(self):        """测试大数字情况"""        # 题目约束范围内的测试        self.assertEqual(maxProduct_alternative([10, 10, 10]), 1000)        self.assertEqual(maxProduct_alternative([-10, -10, -10]), 1000)    def test_algorithm_correctness(self):        """验证算法正确性(多种情况对比)"""        test_cases = [            ([1, 2, 3], 6, "全正数"),            ([-1, -2, -3], 6, "全负数"),            ([2, 3, -2, 4], 6, "正负混合"),            ([0, 0, 0], 0, "全零"),            ([1, 0, 3, 0, 2], 3, "中间有零"),        ]        for nums, expected, description in test_cases:            with self.subTest(nums=nums, description=description):                actual = maxProduct_alternative(nums)                self.assertEqual(actual, expected)class TestMaxProductPropertyBased(unittest.TestCase):    """基于属性的测试"""    def test_result_greater_equal_than_min(self):        """测试结果不小于数组最小值"""        test_arrays = [            [1, 2, 3],            [-3, -2, -1],            [-1, 2, -3],            [0, -1, 2]        ]        for nums in test_arrays:            with self.subTest(nums=nums):                result = maxProduct_alternative(nums)                min_val = min(nums)                self.assertTrue(result >= min_val)    def test_result_less_equal_than_possible_max(self):        """测试结果不大于可能的理论最大值"""        test_arrays = [            [1, 2, 3],            [-3, -2, -1],            [-1, 2, -3]        ]        for nums in test_arrays:            with self.subTest(nums=nums):                result = maxProduct_alternative(nums)                # 理论最大值不会超过所有数乘积的绝对值(考虑负数情况)                import math                abs_product = math.prod(abs(x) for x in nums)                self.assertTrue(abs(result) <= abs_product)def run_comprehensive_test_suite():    """运行全面的测试套件并生成详细报告"""    # 创建测试加载器    loader = unittest.TestLoader()    # 创建测试套件    suite = unittest.TestSuite()    suite.addTests(loader.loadTestsFromTestCase(TestMaxProductAlternative))    suite.addTests(loader.loadTestsFromTestCase(TestMaxProductPropertyBased))    # 运行测试    runner = unittest.TextTestRunner(verbosity=2)    result = runner.run(suite)    # 生成测试报告    print("\n" + "="*70)    print("乘积最大子数组算法测试报告")    print("="*70)    print(f"运行测试数: {result.testsRun}")    print(f"失败数: {len(result.failures)}")    print(f"错误数: {len(result.errors)}")    if result.wasSuccessful():        print("🎉 所有测试通过!算法实现正确。")        # 显示关键测试用例验证        print("\n关键测试用例验证:")        key_test_cases = [            ([2, 3, -2, 4], 6, "LeetCode示例1"),            ([-2, 0, -1], 0, "LeetCode示例2"),            ([-2, 3, -4], 24, "负负得正"),            ([0, 2], 2, "包含零"),            ([1], 1, "单元素")        ]        for nums, expected, description in key_test_cases:            actual = maxProduct_alternative(nums)            status = "✅" if actual == expected else "❌"            print(f"{description:15} | 输入: {nums}")            print(f"{' ':15} | 输出: {actual} (期望: {expected}) {status}")            print("-" * 50)    else:        print("❌ 有测试失败,请检查算法实现。")        # 输出失败详情        for test, traceback in result.failures + result.errors:            print(f"\n失败测试: {test}")            print(f"错误信息:\n{traceback}")    return result.wasSuccessful()if __name__ == '__main__':    # 运行全面测试    success = run_comprehensive_test_suite()    # 退出代码    exit(0 if success else 1)

测试说明

🧪 测试覆盖范围

这个测试脚本全面覆盖了乘积最大子数组算法的各种场景:

  1. 基础功能测试:

    • 空数组和单元素数组处理

    • 全正数、全负数数组

    • 正负数混合数组

  2. 边界条件测试:

    • 包含零的数组

    • 最小/最大边界值

    • 两个元素的特殊情况

  3. 算法特性测试:

    • 验证动态维护cur_max和cur_min的正确性

    • 测试贪心算法会失败的经典案例

    • 复杂场景下的乘积计算

  4. 属性基础测试:

    • 结果范围验证(不小于最小值,不大于理论最大值)

🔧 运行方式
# 方式1:直接运行测试脚本python test_max_product.py# 方式2:运行特定测试类python -m unittest test_max_product.TestMaxProductAlternative# 方式3:运行单个测试方法python -m unittest test_max_product.TestMaxProductAlternative.test_leetcode_examples# 方式4:详细模式运行python -m unittest test_max_product.py -v

测试设计特点

  1. 子测试支持:使用subTest进行参数化测试,避免一个失败导致整个测试类停止

  2. 属性测试:验证算法应满足的数学性质

  3. 详细报告:运行后生成清晰的测试摘要和关键用例验证

  4. 退出代码:根据测试结果返回适当的退出代码,便于CI/CD集成

🎯 算法核心验证

测试特别关注动态规划算法的正确性:

  • candidates数组维护:验证三种可能值的正确计算

  • cur_max/cur_min更新:确保正负数的正确处理

  • 零值处理:验证包含零的数组边界情况

  • 负负得正:测试多个负数相乘变正数的情况

这个测试套件可以确保您的maxProduct_alternative函数在各种情况下都能正确工作,是代码质量的可靠保障

互动:实践出真知,多写代码,多练习

最新文章

随机文章