列表

详情


100395. 单调数组对的数目 I

给你一个长度为 n 的  整数数组 nums 。

如果两个 非负 整数数组 (arr1, arr2) 满足以下条件,我们称它们是 单调 数组对:

请你返回所有 单调 数组对的数目。

由于答案可能很大,请你将它对 109 + 7 取余 后返回。

 

示例 1:

输入:nums = [2,3,2]

输出:4

解释:

单调数组对包括:

  1. ([0, 1, 1], [2, 2, 1])
  2. ([0, 1, 2], [2, 2, 0])
  3. ([0, 2, 2], [2, 1, 0])
  4. ([1, 2, 2], [1, 1, 0])

示例 2:

输入:nums = [5,5,5,5]

输出:126

 

提示:

相似题目

单调数列

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int countOfPairs(vector<int>& nums) { } };

golang 解法, 执行用时: 15 ms, 内存消耗: 4.5 MB, 提交时间: 2024-08-12 09:56:17

// 前缀和dp
func countOfPairs1(nums []int) (ans int) {
	const mod = 1_000_000_007
	n := len(nums)
	m := slices.Max(nums)
	f := make([][]int, n)
	for i := range f {
		f[i] = make([]int, m+1)
	}
	s := make([]int, m+1)

	for j := 0; j <= nums[0]; j++ {
		f[0][j] = 1
	}
	for i := 1; i < n; i++ {
		s[0] = f[i-1][0]
		for k := 1; k <= m; k++ {
			s[k] = s[k-1] + f[i-1][k] // f[i-1] 的前缀和
		}
		for j := 0; j <= nums[i]; j++ {
			maxK := j + min(nums[i-1]-nums[i], 0)
			if maxK >= 0 {
				f[i][j] = s[maxK] % mod
			}
		}
	}

	for _, v := range f[n-1][:nums[n-1]+1] {
		ans += v
	}
	return ans % mod
}

// 优化,压缩第一维
func countOfPairs2(nums []int) (ans int) {
	const mod = 1_000_000_007
	n := len(nums)
	m := nums[n-1]
	f := make([]int, m+1)
	for j := range f[:min(nums[0], m)+1] {
		f[j] = 1
	}
	for i := 1; i < n; i++ {
		for j := 1; j <= m; j++ {
			f[j] += f[j-1] // 计算前缀和
		}
		j0 := max(nums[i]-nums[i-1], 0)
		for j := min(nums[i], m); j >= j0; j-- {
			f[j] = f[j-j0] % mod
		}
		clear(f[:min(j0, m+1)])
	}
	for _, v := range f {
		ans += v
	}
	return ans % mod
}

// 进一步优化
func countOfPairs(nums []int) (ans int) {
	const mod = 1_000_000_007
	n := len(nums)
	m := nums[n-1]
	f := make([]int, m+1)
	for j := range f[:min(nums[0], m)+1] {
		f[j] = 1
	}
	for i := 1; i < n; i++ {
		j0 := max(nums[i]-nums[i-1], 0)
		m2 := min(nums[i], m)
		if j0 > m2 {
			return 0
		}
		for j := 1; j <= m2-j0; j++ {
			f[j] = (f[j] + f[j-1]) % mod // 计算前缀和
		}
		copy(f[j0:m2+1], f)
		clear(f[:j0])
	}
	for _, v := range f {
		ans += v
	}
	return ans % mod
}

java 解法, 执行用时: 3 ms, 内存消耗: 43.6 MB, 提交时间: 2024-08-12 09:53:05

class Solution {
    private static final int MOD = 1_000_000_007;
    private static final int MX = 3001; // MAX_N + MAX_M = 2000 + 1000 = 3000

    private static final long[] F = new long[MX]; // f[i] = i!
    private static final long[] INV_F = new long[MX]; // inv_f[i] = i!^-1

    static {
        F[0] = 1;
        for (int i = 1; i < MX; i++) {
            F[i] = F[i - 1] * i % MOD;
        }

        INV_F[MX - 1] = pow(F[MX - 1], MOD - 2);
        for (int i = MX - 1; i > 0; i--) {
            INV_F[i - 1] = INV_F[i] * i % MOD;
        }
    }

    public int countOfPairs(int[] nums) {
        int n = nums.length;
        int m = nums[n - 1];
        for (int i = 1; i < n; i++) {
            m -= Math.max(nums[i] - nums[i - 1], 0);
            if (m < 0) {
                return 0;
            }
        }
        return (int) comb(m + n, n);
    }

    private long comb(int n, int m) {
        return F[n] * INV_F[m] % MOD * INV_F[n - m] % MOD;
    }

    private static long pow(long x, int n) {
        long res = 1;
        for (; n > 0; n /= 2) {
            if (n % 2 > 0) {
                res = res * x % MOD;
            }
            x = x * x % MOD;
        }
        return res;
    }
}

cpp 解法, 执行用时: 21 ms, 内存消耗: 30.8 MB, 提交时间: 2024-08-12 09:52:38

class Solution {
public:
    int countOfPairs1(vector<int>& nums) {
        const int MOD = 1'000'000'007;
        int n = nums.size();
        int m = ranges::max(nums);
        vector<vector<long long>> f(n, vector<long long>(m + 1));
        vector<long long> s(m + 1);

        fill(f[0].begin(), f[0].begin() + nums[0] + 1, 1);
        for (int i = 1; i < n; i++) {
            partial_sum(f[i - 1].begin(), f[i - 1].end(), s.begin()); // f[i-1] 的前缀和
            for (int j = 0; j <= nums[i]; j++) {
                int max_k = j + min(nums[i - 1] - nums[i], 0);
                f[i][j] = max_k >= 0 ? s[max_k] % MOD : 0;
            }
        }

        return reduce(f[n - 1].begin(), f[n - 1].begin() + nums[n - 1] + 1, 0LL) % MOD;
    }


    int countOfPairs2(vector<int>& nums) {
        const int MOD = 1'000'000'007;
        int n = nums.size(), m = nums.back();
        vector<int> f(m + 1);
        fill(f.begin(), f.begin() + min(nums[0], m) + 1, 1);
        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= m; j++) {
                f[j] = (f[j] + f[j - 1]) % MOD; // 计算前缀和
            }
            int j0 = max(nums[i] - nums[i - 1], 0);
            for (int j = min(nums[i], m); j >= j0; j--) {
                f[j] = f[j - j0];
            }
            fill(f.begin(), f.begin() + min(j0, m + 1), 0);
        }
        return reduce(f.begin(), f.end(), 0LL) % MOD;
    }

    int countOfPairs(vector<int>& nums) {
        const int MOD = 1'000'000'007;
        int n = nums.size(), m = nums[n - 1];
        vector<int> f(m + 1);
        fill(f.begin(), f.begin() + min(nums[0], m) + 1, 1);
        for (int i = 1; i < n; i++) {
            int j0 = max(nums[i] - nums[i - 1], 0);
            int m2 = min(nums[i], m);
            if (j0 > m2) {
                return 0;
            }
            for (int j = 1; j <= m2 - j0; j++) {
                f[j] = (f[j] + f[j - 1]) % MOD; // 计算前缀和
            }
            copy(f.begin(), f.begin() + m2 - j0 + 1, f.begin() + j0);
            fill(f.begin(), f.begin() + j0, 0);
        }
        return reduce(f.begin(), f.end(), 0LL) % MOD;
    }
};

python3 解法, 执行用时: 49 ms, 内存消耗: 16.5 MB, 提交时间: 2024-08-12 09:50:25

# 前缀和优化dp
class Solution:
    def countOfPairs1(self, nums: List[int]) -> int:
        MOD = 1_000_000_007
        n = len(nums)
        m = max(nums)
        f = [[0] * (m + 1) for _ in range(n)]
        for j in range(nums[0] + 1):
            f[0][j] = 1
        for i in range(1, n):
            s = list(accumulate(f[i - 1]))  # f[i-1] 的前缀和
            for j in range(nums[i] + 1):
                max_k = j + min(nums[i - 1] - nums[i], 0)
                f[i][j] = s[max_k] % MOD if max_k >= 0 else 0
        return sum(f[-1][:nums[-1] + 1]) % MOD
    
    # 空间优化
    def countOfPairs2(self, nums: List[int]) -> int:
        MOD = 1_000_000_007
        m = nums[-1]
        f = [0] * (m + 1)
        for j in range(min(nums[0], m) + 1):
            f[j] = 1
        for pre, cur in pairwise(nums):
            for j in range(1, m + 1):
                f[j] += f[j - 1]  # 计算前缀和
            j0 = max(cur - pre, 0)
            for j in range(min(cur, m), j0 - 1, -1):
                f[j] = f[j - j0] % MOD
            for j in range(min(j0, m + 1)):
                f[j] = 0
        return sum(f) % MOD

    # 进一步优化
    def countOfPairs3(self, nums: List[int]) -> int:
        MOD = 1_000_000_007
        m = nums[-1]
        f = [0] * (m + 1)
        for j in range(min(nums[0], m) + 1):
            f[j] = 1
        for pre, cur in pairwise(nums):
            j0 = max(cur - pre, 0)
            m2 = min(cur, m)
            if j0 > m2:
                return 0
            for j in range(1, m2 - j0 + 1):
                f[j] = (f[j] + f[j - 1]) % MOD  # 计算前缀和
            f[j0: m2 + 1] = f[:m2 - j0 + 1]
            f[:j0] = [0] * j0
        return sum(f) % MOD
    
    # 组合数学
    def countOfPairs(self, nums: List[int]) -> int:
        MOD = 1_000_000_007
        m = nums[-1]
        for x, y in pairwise(nums):
            m -= max(y - x, 0)
        return comb(m + len(nums), m) % MOD if m >= 0 else 0

上一题