LeetCode: 2552. 统计上升四元组 动态规划 时间复杂度O(n*n)

2552. 统计上升四元组

today 2552. 统计上升四元组

题目描述

给你一个长度为n下标从 0 开始的整数数组 nums ,它包含1到n的所有数字,请你返回上升四元组的数目。

如果一个四元组 (i, j, k, l) 满足以下条件,我们称它是上升的:

  • 0 <= i < j < k < l < n 且
  • nums[i] < nums[k] < nums[j] < nums[l]。

示例 1:

复制代码
输入:nums = [1,3,2,4,5]
输出:2
解释:
- 当 i = 0 ,j = 1 ,k = 2 且 l = 3 时,有 nums[i] < nums[k] < nums[j] < nums[l] 。
- 当 i = 0 ,j = 1 ,k = 2 且 l = 4 时,有 nums[i] < nums[k] < nums[j] < nums[l] 。
没有其他的四元组,所以我们返回 2 。

示例 2:

复制代码
输入:nums = [1,2,3,4]
输出:0
解释:没有四元组,所以我们返回 0 。

提示:

  • 4 <= nums.length <= 4000
  • 1 <= nums[i] <= nums.length
  • nums 中所有数字 互不相同 ,nums 是一个排列。

解题思路

我们可以枚举四元组中的 j 和 k,那么问题转化为,对于当前的 j 和 k:

统计有多少个 l 满足 l>k 且 nums[l]>nums[j],记为cnt1;

统计有多少个 i 满足 i<j 且 nums[i]<nums[k],记为cnt2;

所以,对于每一组 j 和 k,满足条件的组合数目为cnt1*cnt2,将所有j 和 k组合数目相加,就是答案。

那么我们可以用动态规划解决这个问题。

使用二维数组 f 来记录 j 和 k 组合的情况,f[j][k] 表示 有多少个l满足满足 l>k 且 nums[l]>nums[j]。

初始化 f[j][n-1] 为 0,表示对于末尾元素为k的情况下,没有满足条件的l。注意1<=j<n-2。

从后往前填充行f[j],如果nums[k]>nums[j],则f[j][k-1]=f[j][k]+1。

此时,对于每个j 和 k,我们都可以计算出有多少个 l 满足 l>k 且 nums[l]>nums[j],即cnt1=f[j][k]。

对于每个j 和 k,我们已经通过二维数组 f,记录了cnt1的取值,接下来,我们只需要记录cnt2的取值即可。

对于每个j 和 k,我们可以确定k,,之后从前往后遍历数组。

初始化cnt2=0,如果

  • nums[j]<nums[k],则cnt2+=1,表示当前有多少个i满足nums[i]<nums[k]。
  • nums[j]>nums[k],则当前j 和 k满足条件,我们将cnt2*cnt1即cnt2*f[j][k]加入答案。

最后,返回答案即可。

复杂度分析:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 是数组的长度。
  • 空间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 是数组的长度。

代码实现

Python实现:

python 复制代码
class Solution(object):
    def countQuadruplets(self, nums):
        n=len(nums)
        f=[[0]*n for i in range(n)]
        ans=0
        for j in range(1,n-2):
            cnt=0
            for k in range(n-1,j,-1):
                f[j][k]=cnt
                if nums[k]>nums[j]:
                    cnt+=1
        for k in range(2,n-1):
            cnt=0
            for j in range(0,k):
                if(nums[j]>nums[k]):
                    ans+=cnt*f[j][k]
                else:
                    cnt+=1
        return ans

C++实现:

cpp 复制代码
class Solution {
public:
    long long countQuadruplets(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>> f(n,vector<int>(n,0));
        long long res=0;
        for(int j=1;j<n-2;j++){
            int cnt=0;
            for(int k=n-1;k>j;k--){
                f[j][k]=cnt;
                if(nums[k]>nums[j]){
                    cnt++;
                }
            }
        }
        for(int k=2;k<n-1;k++){
            int cnt=0;
            for(int j=0;j<k;j++){
                if(nums[j]<nums[k]){
                    cnt++;
                    continue;
                }else{
                    res+=cnt*f[j][k];
                }
            }
        }
        return res;
    }
};

Go实现:

go 复制代码
func countQuadruplets(nums []int) int64 {
	n := len(nums)
	f := make([][]int, n)
	for i := range f {
		f[i] = make([]int, n)
	}
	for j := 1; j < n-2; j++ {
		cnt := 0
		for k := n-1; k >j; k-- {
            f[j][k] = cnt
			if nums[j] < nums[k] {
				cnt++
			} 
		}
	}
	ans := 0
	for k := 2; k < n-1; k++ {
		cnt := 0
		for j := 0; j <k; j++ {
			if nums[j] < nums[k] {
				cnt++
                continue
			}else{
                ans+=cnt*f[j][k]
            }
		}
	}
	return int64(ans)
}
相关推荐
海绵宝宝转agent12 分钟前
LeetCode100 二叉树个人题解
算法·leetcode·深度优先
octopus_c18 分钟前
C++ 模板详解:函数模板、类模板、特化与分离编译
开发语言·c++·算法
東隅已逝,桑榆非晚24 分钟前
算法1. 双指针法-移动零
c++·算法
CQU_JIAKE1 小时前
11.1[A]
算法
文丑颜不良啊1 小时前
LeetCode1581~1600题目解析
java·leetcode
小郎君6582 小时前
(六)el-cascader 的展示值为什么不能直接 join:emitPath、路径还原与多选去重
vue.js·算法
郝学胜-神的一滴3 小时前
游戏设计:原型与开发 19:U3D工位布置与性格说明书
人工智能·算法·unity·unreal engine·游戏策划·游戏设计
hahaha60164 小时前
数字图像时域滤波或者3D降噪算法FPGA实现
算法·计算机视觉·fpga开发
文丑颜不良啊4 小时前
LeetCode1541~1560题目解析
java·leetcode
YSL0701244 小时前
一文通关-----树和二叉树
数据结构·算法