2026-04-05:范围内总波动值Ⅰ。用go语言,给定两个整数 num1 和 num2,考虑它们之间所有的整数(包含端点),即区间 [num1, num2]。

0 阅读9分钟

2026-04-05:范围内总波动值Ⅰ。用go语言,给定两个整数 num1 和 num2,考虑它们之间所有的整数(包含端点),即区间 [num1, num2]。

对区间内的每个整数,把它的每一位数字看作一个“位置”。对某一位数字,判断它是否构成“峰”或“谷”:

若这一位数字 严格大于 它左右相邻的两位数字,则这位属于峰。

若这一位数字 严格小于 它左右相邻的两位数字,则这位属于谷。

数字的第一位和最后一位不允许被算作峰或谷(因为它们没有两侧相邻位)。

若该数字的位数少于 3(即没有足够左右对比),则它的“波动值”为 0。

于是,一个整数的波动值等于:该数中所有峰的数量加上所有谷的数量。

最后要求:把区间 [num1, num2] 内每个整数的波动值加总,返回这个总和。

1 <= num1 <= num2 <= 100000。

输入: num1 = 120, num2 = 130。

输出: 3。

解释:

在范围 [120, 130] 内:

120:中间数位 2 是峰,波动值 = 1。

121:中间数位 2 是峰,波动值 = 1。

130:中间数位 3 是峰,波动值 = 1。

范围内所有其他数字的波动值均为 0。

因此,总波动值为 1 + 1 + 1 = 3。

题目来自力扣3751。

一、代码整体执行流程

步骤1:入口函数初始化

  1. 程序从main函数开始,输入区间num1=120num2=130
  2. 调用totalWaviness(num1, num2),这是总结果的计算入口。

步骤2:区间差值计算(总波动值核心逻辑)

  1. totalWaviness函数执行:
    • 计算f(num2):0到130所有数字的总波动值;
    • 计算f(num1-1):0到119所有数字的总波动值;
    • 最终结果 = f(130) - f(119),直接得到区间[120,130]的总波动值。

步骤3:单边界总波动值计算(f(n)函数)

以计算f(130)为例,执行totalWavinessWithBound(130)

  1. 基础判断:130>100,不直接返回0,进入数位DP计算;
  2. 获取数字位数:130是3位数,记为m=3
  3. 计算位数因子:3位数的最高位因子是100(10²),用于拆分每一位数字;
  4. 初始化记忆化数组(memo)
    • 用途:存储DP过程中重复计算的结果,避免重复递归,提升效率;
    • 维度:[位数][前一位数字][大小关系标记][是否受限],所有值初始化为-1(标记未计算);
  5. 启动递归DP:从数字的**最高位(第0位)**开始递归计算,返回0到n的总波动值。

步骤4:数位DP递归核心逻辑(dp函数)

这是计算波动值的核心,递归遍历数字的每一位,逐位枚举可能的数字,记录状态并累加波动值:

  1. 递归终止条件:遍历完所有位数(到达最后一位的下一位),返回:当前波动值=0,当前数字个数=1(代表1个完整数字);
  2. 状态读取:如果当前状态已经计算过(非受限状态),直接读取记忆化数组的结果,不重复计算;
  3. 确定当前位可枚举的最大数字
    • 受限(tight=true):当前位不能超过原数字的对应位(如130最高位只能枚举1);
    • 不受限:当前位可以枚举0~9所有数字;
  4. 逐位枚举数字(0~最大数字)
    • 记录当前位数字作为下一位的「前一位数字」;
    • 计算新的大小关系:当前位数字 和 前一位数字 的大小对比(小于/等于/大于/初始未知);
    • 更新受限状态:只有上一步受限且当前位取到最大值,下一步才继续受限;
    • 递归下一位:计算后续所有位的总波动值和数字个数;
    • 累加波动值:根据「前后大小关系的变化」判断是否新增峰/谷,每新增1个峰/谷,就给所有后续数字的波动值+1;
  5. 记忆化存储:将非受限状态的计算结果存入memo数组,方便后续复用;
  6. 返回结果:返回当前状态下的总波动值数字总个数

步骤5:大小关系判断辅助函数

  1. getNewComparison:判断当前位数字和前一位数字的大小关系(小于/等于/大于),初始状态(无前一位)标记为未知;
  2. wavinessIncrease:判断是否新增峰/谷——只有前一次是小于、当前是大于前一次是大于、当前是小于(严格交替),才会产生1个峰/谷,波动值+1;其余情况不增加。

步骤6:输出最终结果

f(130) - f(119) = 3,程序打印结果3,与题目示例一致。


二、关键细节补充

  1. 位数过滤:代码中n≤100直接返回0,因为≤100的数字位数<3,波动值恒为0;
  2. 记忆化优化:memo数组避免了大量重复递归,是数位DP高效的核心;
  3. 波动值统计规则:严格按照「中间位、严格大于/小于、峰谷交替」统计,首尾位不参与,完全符合题目要求。

三、时间复杂度分析

  1. 核心计算单元:数位DP的状态总数 = 位数 × 前一位数字(0~9) × 大小关系(4种) × 受限状态(2种);
  2. 最大位数:题目上限100000是6位数,因此总状态数 = 6 × 10 × 4 × 2 = 480(常数级);
  3. 递归次数:每个状态仅计算1次,逐位枚举数字最多10次(常数);
  4. 总时间复杂度O(1)(常数级)。 原因:数字最大固定为6位,所有计算量都是固定常数,与输入数字大小无关。

四、额外空间复杂度分析

额外空间指除输入输出外,程序运行中申请的内存

  1. 主要空间:memo记忆化数组,大小为6 × 10 × 4 × 2 = 480个int64元素;
  2. 递归栈空间:最大递归深度=数字最大位数=6层;
  3. 其他变量:位数、因子、临时变量等,均为常数级;
  4. 总额外空间复杂度O(1)(常数级)。

总结

  1. 执行过程:区间差值法拆分计算 → 数位DP逐位枚举数字 → 状态记忆化优化 → 辅助函数判断峰谷 → 累加总波动值;
  2. 时间复杂度:O(1)(常数级,固定计算量);
  3. 额外空间复杂度:O(1)(常数级,固定内存占用)。

Go完整代码如下:

package main

import (
	"fmt"
)

const (
	UNKNOWN = 0
	LESS    = 1
	EQUAL   = 2
	GREATER = 3
)

func totalWaviness(num1 int64, num2 int64) int64 {
	return totalWavinessWithBound(num2) - totalWavinessWithBound(num1-1)
}

func totalWavinessWithBound(n int64) int64 {
	if n <= 100 {
		return 0
	}
	m := getLength(n)
	factor := int64(1)
	for i := 1; i < m; i++ {
		factor *= 10
	}

	// memo[position][prev][comparison][tight]
	memo := make([][][][]int64, m)
	for i := 0; i < m; i++ {
		memo[i] = make([][][]int64, 10)
		for j := 0; j < 10; j++ {
			memo[i][j] = make([][]int64, 4)
			for k := 0; k < 4; k++ {
				memo[i][j][k] = []int64{-1, -1}
			}
		}
	}

	res, _ := dp(memo, n, factor, 0, 0, UNKNOWN, true)
	return res
}

func getLength(n int64) int {
	length := 0
	for n > 0 {
		n /= 10
		length++
	}
	return length
}

func dp(memo [][][][]int64, n int64, factor int64, position int, prev int, comparison int, tight bool) (int64, int64) {
	if position == len(memo) {
		return 0, 1
	}
	tightFlag := 0
	if !tight {
		tightFlag = 1
	}
	if tightFlag == 1 && memo[position][prev][comparison][0] >= 0 {
		return memo[position][prev][comparison][0], memo[position][prev][comparison][1]
	}

	var newWaviness int64 = 0
	var newCount int64 = 0
	digit := int((n / factor) % 10)
	maxDigit := digit
	if !tight {
		maxDigit = 9
	}
	for d := 0; d <= maxDigit; d++ {
		newPrev := d
		newComparison := getNewComparison(d, prev, comparison)
		newTight := tight && d == digit
		nextWav, nextCount := dp(memo, n, factor/10, position+1, newPrev, newComparison, newTight)
		newWaviness += nextWav + int64(wavinessIncrease(comparison, newComparison))*nextCount
		newCount += nextCount
	}

	if tightFlag == 1 {
		memo[position][prev][comparison][0] = newWaviness
		memo[position][prev][comparison][1] = newCount
	}
	return newWaviness, newCount
}

func getNewComparison(curr int, prev int, comparison int) int {
	if comparison == UNKNOWN && prev == 0 {
		return UNKNOWN
	}
	if curr < prev {
		return LESS
	} else if curr == prev {
		return EQUAL
	} else {
		return GREATER
	}
}

func wavinessIncrease(comparison int, newComparison int) int {
	if (comparison == LESS && newComparison == GREATER) || (comparison == GREATER && newComparison == LESS) {
		return 1
	}
	return 0
}

func main() {
	num1 := int64(120)
	num2 := int64(130)
	result := totalWaviness(num1, num2)
	fmt.Println(result)
}

在这里插入图片描述

Python完整代码如下:

# -*-coding:utf-8-*-

class Solution:
    UNKNOWN = 0
    LESS = 1
    EQUAL = 2
    GREATER = 3

    def totalWaviness(self, num1: int, num2: int) -> int:
        return self.totalWavinessWithBound(num2) - self.totalWavinessWithBound(num1 - 1)

    def totalWavinessWithBound(self, n: int) -> int:
        if n <= 100:
            return 0
        
        m = self.getLength(n)
        factor = 10 ** (m - 1)
        
        # memo[position][prev][comparison] = [waviness, count] for non-tight states
        memo = [[[[-1, -1] for _ in range(4)] for _ in range(10)] for _ in range(m)]
        
        res, _ = self.dp(memo, n, factor, 0, 0, self.UNKNOWN, True)
        return res

    def getLength(self, n: int) -> int:
        length = 0
        while n > 0:
            n //= 10
            length += 1
        return length

    def dp(self, memo, n: int, factor: int, position: int, prev: int, comparison: int, tight: bool):
        if position == len(memo):
            return 0, 1
        
        if not tight and memo[position][prev][comparison][0] >= 0:
            return memo[position][prev][comparison][0], memo[position][prev][comparison][1]
        
        newWaviness = 0
        newCount = 0
        digit = (n // factor) % 10
        maxDigit = digit if tight else 9
        
        for d in range(maxDigit + 1):
            newPrev = d
            newComparison = self.getNewComparison(d, prev, comparison)
            newTight = tight and (d == digit)
            nextWav, nextCount = self.dp(memo, n, factor // 10, position + 1, newPrev, newComparison, newTight)
            newWaviness += nextWav + self.wavinessIncrease(comparison, newComparison) * nextCount
            newCount += nextCount
        
        if not tight:
            memo[position][prev][comparison][0] = newWaviness
            memo[position][prev][comparison][1] = newCount
        
        return newWaviness, newCount

    def getNewComparison(self, curr: int, prev: int, comparison: int) -> int:
        if comparison == self.UNKNOWN and prev == 0:
            return self.UNKNOWN
        if curr < prev:
            return self.LESS
        elif curr == prev:
            return self.EQUAL
        else:
            return self.GREATER

    def wavinessIncrease(self, comparison: int, newComparison: int) -> int:
        if (comparison == self.LESS and newComparison == self.GREATER) or \
           (comparison == self.GREATER and newComparison == self.LESS):
            return 1
        return 0


def main():
    sol = Solution()
    num1 = 120
    num2 = 130
    result = sol.totalWaviness(num1, num2)
    print(result)


if __name__ == "__main__":
    main()

在这里插入图片描述

C++完整代码如下:

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

const int UNKNOWN = 0;
const int LESS = 1;
const int EQUAL = 2;
const int GREATER = 3;

int getLength(long long n) {
    int length = 0;
    while (n > 0) {
        n /= 10;
        length++;
    }
    return length;
}

int getNewComparison(int curr, int prev, int comparison) {
    if (comparison == UNKNOWN && prev == 0) {
        return UNKNOWN;
    }
    if (curr < prev) {
        return LESS;
    } else if (curr == prev) {
        return EQUAL;
    } else {
        return GREATER;
    }
}

int wavinessIncrease(int comparison, int newComparison) {
    if ((comparison == LESS && newComparison == GREATER) ||
        (comparison == GREATER && newComparison == LESS)) {
        return 1;
    }
    return 0;
}

// memo[position][prev][comparison][0] = waviness, [1] = count
vector<vector<vector<vector<long long>>>> memo;

pair<long long, long long> dp(long long n, long long factor, int position, int prev, int comparison, bool tight) {
    if (position == memo.size()) {
        return {0, 1};
    }

    int tightFlag = tight ? 0 : 1;
    if (!tight && memo[position][prev][comparison][0] >= 0) {
        return {memo[position][prev][comparison][0], memo[position][prev][comparison][1]};
    }

    long long newWaviness = 0;
    long long newCount = 0;
    int digit = (n / factor) % 10;
    int maxDigit = tight ? digit : 9;

    for (int d = 0; d <= maxDigit; d++) {
        int newPrev = d;
        int newComparison = getNewComparison(d, prev, comparison);
        bool newTight = tight && (d == digit);
        auto [nextWav, nextCount] = dp(n, factor / 10, position + 1, newPrev, newComparison, newTight);
        newWaviness += nextWav + (long long)wavinessIncrease(comparison, newComparison) * nextCount;
        newCount += nextCount;
    }

    if (!tight) {
        memo[position][prev][comparison][0] = newWaviness;
        memo[position][prev][comparison][1] = newCount;
    }

    return {newWaviness, newCount};
}

long long totalWavinessWithBound(long long n) {
    if (n <= 100) {
        return 0;
    }

    int m = getLength(n);
    long long factor = 1;
    for (int i = 1; i < m; i++) {
        factor *= 10;
    }

    // 初始化 memo
    memo.assign(m, vector<vector<vector<long long>>>(
                       10, vector<vector<long long>>(
                           4, vector<long long>(2, -1))));

    auto [res, _] = dp(n, factor, 0, 0, UNKNOWN, true);
    return res;
}

long long totalWaviness(long long num1, long long num2) {
    return totalWavinessWithBound(num2) - totalWavinessWithBound(num1 - 1);
}

int main() {
    long long num1 = 120;
    long long num2 = 130;
    long long result = totalWaviness(num1, num2);
    cout << result << endl;
    return 0;
}

在这里插入图片描述