Count Increasing Quadruplets

Count Increasing Quadruplets

Given a 0-indexed integer array nums of size n containing all numbers from 1 to n, return the number of increasing quadruplets.

A quadruplet (i, j, k, l) is increasing if:

  • 0i<j<k<l<n, and
  • nums[i]<nums[k]<nums[j]<nums[l].

Example 1:

Input: nums = [1,3,2,4,5]
Output: 2
Explanation: 
- When i = 0, j = 1, k = 2, and l = 3, nums[i] < nums[k] < nums[j] < nums[l].
- When i = 0, j = 1, k = 2, and l = 4, nums[i] < nums[k] < nums[j] < nums[l]. 
There are no other quadruplets, so we return 2.

Example 2:

Input: nums = [1,2,3,4]
Output: 0
Explanation: There exists only one quadruplet with i = 0, j = 1, k = 2, l = 3, but since nums[j] < nums[k], we return 0.

Constraints:

  • 4nums.length4000
  • 1nums[i]nums.length
  • All the integers of nums are unique. nums is a permutation.

 

解题思路

  一开始看错题了以为是求nums[i]<nums[j]<nums[k]<nums[l],这个直接用树状数组就可以实现了,参考三元组

  然后想了一下不会是枚举jk吧,结果正解就是这样做,但自己没想出来。

  暴力枚举jk,在满足nums[k]<nums[j]的前提下,找到所有小于ji且满足nums[i]<nums[k],和找到所有大于kl且满足nums[j]<nums[l],参考下面的示意图:

  因此为了在枚举jk的时候能够快速统计出来满足i<jnums[i]<nums[k]i的数量,和满足l>knums[l]>nums[j]l的数量,这里可以先开个数组g[x][v]表示下标为xnums[x]=v的数量,然后对g求二维前缀和,然后根据乘法原理将两部分的元素数目相乘得到答案。

  然而前缀和数组s[i][j]只能得到下标小于等于i且值小于等于j的元素数量,那么如何根据s来求得下标大于i且值大于j的元素数量呢?也就是下图的部分:

  很简单,只要根据s的定义减去白色的部分就行了,具体公式为 ans=sn,nsi,nsn,j+si,j

  AC代码如下,时间复杂度为O(n2)

复制代码
 1 class Solution {
 2 public:
 3     long long countQuadruplets(vector<int>& nums) {
 4         int n = nums.size();
 5         vector<vector<int>> s(n + 1, vector<int>(n + 1));
 6         for (int i = 1; i <= n; i++) {
 7             s[i][nums[i - 1]]++;    // 统计数量
 8         }
 9         for (int i = 1; i <= n; i++) {  // 求前缀和
10             for (int j = 1; j <= n; j++) {
11                 s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
12             }
13         }
14         long long ret = 0;
15         for (int i = 1; i <= n; i++) {
16             for (int j = i + 1; j <= n; j++) {
17                 if (nums[i - 1] > nums[j - 1]) {
18                     ret += 1ll * s[i - 1][nums[j - 1] - 1] * (s[n][n] - s[j][n] - s[n][nums[i - 1]] + s[j][nums[i - 1]]);   // 两部分相乘
19                 }
20             }
21         }
22         return ret;
23     }
24 };
复制代码

 

参考资料

  转化思路 前后缀分解【力扣周赛 330】:https://www.bilibili.com/video/BV1mD4y1E7QK/

posted @   onlyblues  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示