2552. 统计上升四元组

328 阅读1分钟

题目:
相关企业

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

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

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

算法:
方法一:枚举
技巧:我们考虑对符合条件的j,k进行枚举:

  • great[k][nums[j]]表示k右侧大于nums[j]的元素个数。
  • less[j][nums[k]]表示j左侧小于nums[k]的元素个数。

针对每一个符合条件的(j,k),上升四元组的数目为:less[j][nums[k]] * great[k][nums[j]]。

  1. 维护great数组,从右往左遍历得到元素值x,那么对于所有的great[k][0~x - 1]都 都要+1
  2. 维护less数组,从左往右遍历得到元素x,那么对于所有的less[j][x + 1 ~ n]都要+1
func countQuadruplets(nums []int) int64 {
    n := len(nums)
    great := make([][]int, n)
    great[n - 1] = make([]int, n + 1)
    for k := n - 2; k >= 1; k -- {
        // k = 6,great[k][3]=3
        // 那么k = 5时,great[k][3]至少也是3,less同理。
        great[k] = append([]int{} ,great[k + 1]...) 
        for x := nums[k + 1] - 1; x >= 0; x -- {
            great[k][x] ++
        }
    }
    less := make([]int, n + 1)
    ans := int64(0)
    for j := 1; j <= n - 2; j ++ {
        for x := nums[j - 1] + 1; x <= n; x ++ {
            less[x] ++
        }
        for k := j + 1; k < n - 1; k ++ {
            if nums[j] > nums[k] {
                ans = ans + int64(less[nums[k]] * great[k][nums[j]])
            }
        }
    }
    return ans
}

方法二:前缀和+后缀和

  1. great[i][x]表示 i <= index 且x <= value的nums元素个数
  2. less[i][x]表示 index <= i且value <= x 的nums元素个数
    结果为:j<k,vk<vjless[j1][vk1]great[k+1][vj+1]\sum_{j<k, vk<vj}less[j - 1][vk - 1] * great[k + 1][vj + 1]
var great, less [4003][4003]int
func countQuadruplets(nums []int) int64 {
    n := len(nums)
    // 对great,less数组初始化,否则上次的执行结果会影响下一次
    for i := 0; i <= n + 1; i ++ {
        for j := 0; j <= n + 1; j ++ {
            great[i][j] = 0
            less[i][j] = 0
        }
    }

    // great[i][x]表示 i <= index 且x <= value的nums元素个数
    // less[i][x]表示 index <= i且value <= x 的nums元素个数
    // great,less相对nums的index有+1的偏移量
    // great, less = [4003][4003]int{}, [4003][4003]int{}
    for i := 1; i <= n; i ++ {
        great[i][nums[i - 1]] = 1
        less[i][nums[i - 1]] = 1
    }
    // 初始化less数组,前缀和
    for i := 1; i <= n; i ++ {
        for j := 1; j <= n; j ++ {
            less[i][j] = less[i][j] + less[i][j - 1]
        }
    }
    for i := 1; i <= n; i ++ {
        for j := 1; j <= n; j ++ {
            less[i][j] = less[i][j] + less[i - 1][j]
        }
    }
    // 初始化great数组,后缀和
    for i := n; i > 0; i -- {
        for j := n; j > 0; j -- {
            great[i][j] = great[i][j] + great[i][j + 1]
        }
    }
    for i := n; i > 0; i -- {
        for j := n; j > 0; j -- {
            great[i][j] = great[i][j] + great[i + 1][j]
        }
    }
    // 计算结果
    ans := int64(0)
    // j:[1,n-2],k[2,n-1];
    // j,k都有+1的偏移量
    for j := 1; j <= n ; j ++ {
        for k := j + 1; k <= n; k ++ {
            if nums[j - 1] > nums[k - 1] {
                // fmt.Println(j-1, k-1,less[j - 1][nums[k - 1] - 1], great[k + 1][nums[j - 1] + 1])
                ans = ans + int64(less[j - 1][nums[k - 1] - 1] * great[k + 1][nums[j - 1] + 1])
            }
        }
    }
    return ans
}