双指针题目:满足条件的子序列数目

文章目录

题目

标题和出处

标题:满足条件的子序列数目

出处:1498. 满足条件的子序列数目

难度

7 级

题目描述

要求

给定一个整数数组 nums \texttt{nums} nums 和一个整数 target \texttt{target} target。

返回 nums \texttt{nums} nums 中满足最小元素与最大元素的和小于或等于 target \texttt{target} target 的非空 子序列的数目。由于答案可能非常大,返回答案模 10 9 + 7 \texttt{10}^\texttt{9} + \texttt{7} 109+7 的余数。

示例

示例 1:

输入: nums = [3,5,6,7], target = 9 \texttt{nums = [3,5,6,7], target = 9} nums = [3,5,6,7], target = 9

输出: 4 \texttt{4} 4

解释:有 4 \texttt{4} 4 个子序列满足该条件。

3\] → 3 + 3 ≤ 9 \\texttt{\[3\]} \\rightarrow \\texttt{3} + \\texttt{3} \\le \\texttt{9} \[3\]→3+3≤9 \[3,5\] → 3 + 5 ≤ 9 \\texttt{\[3,5\]} \\rightarrow \\texttt{3} + \\texttt{5} \\le \\texttt{9} \[3,5\]→3+5≤9 \[3,5,6\] → 3 + 6 ≤ 9 \\texttt{\[3,5,6\]} \\rightarrow \\texttt{3} + \\texttt{6} \\le \\texttt{9} \[3,5,6\]→3+6≤9 \[3,6\] → 3 + 6 ≤ 9 \\texttt{\[3,6\]} \\rightarrow \\texttt{3} + \\texttt{6} \\le \\texttt{9} \[3,6\]→3+6≤9 **示例 2:** 输入: nums = \[3,3,6,8\], target = 10 \\texttt{nums = \[3,3,6,8\], target = 10} nums = \[3,3,6,8\], target = 10 输出: 6 \\texttt{6} 6 解释:有 6 \\texttt{6} 6 个子序列满足该条件: \[3\] \\texttt{\[3\]} \[3\]、 \[3\] \\texttt{\[3\]} \[3\]、 \[3,3\] \\texttt{\[3,3\]} \[3,3\]、 \[3,6\] \\texttt{\[3,6\]} \[3,6\]、 \[3,6\] \\texttt{\[3,6\]} \[3,6\]、 \[3,3,6\] \\texttt{\[3,3,6\]} \[3,3,6\]。 **示例 3:** 输入: nums = \[2,3,3,4,6,7\], target = 12 \\texttt{nums = \[2,3,3,4,6,7\], target = 12} nums = \[2,3,3,4,6,7\], target = 12 输出: 61 \\texttt{61} 61 解释:共有 63 \\texttt{63} 63 个非空子序列,其中 2 \\texttt{2} 2 个不满足条件( \[6,7\] \\texttt{\[6,7\]} \[6,7\]、 \[7\] \\texttt{\[7\]} \[7\])。有效子序列总数为 63 − 2 = 61 \\texttt{63} - \\texttt{2} = \\texttt{61} 63−2=61。 #### 数据范围 * 1 ≤ nums.length ≤ 10 5 \\texttt{1} \\le \\texttt{nums.length} \\le \\texttt{10}\^\\texttt{5} 1≤nums.length≤105 * 1 ≤ nums\[i\] ≤ 10 6 \\texttt{1} \\le \\texttt{nums\[i\]} \\le \\texttt{10}\^\\texttt{6} 1≤nums\[i\]≤106 * 1 ≤ target ≤ 10 6 \\texttt{1} \\le \\texttt{target} \\le \\texttt{10}\^\\texttt{6} 1≤target≤106 ## 前言 这道题要求计算数组 nums \\textit{nums} nums 中满足最小值与最大值之和不超过 target \\textit{target} target 的非空子序列的数目。当一个子序列的最小值与最大值确定时,在最小值与最大值之间的其余元素是否加入子序列不会影响子序列的最小值与最大值。如果最小值与最大值之间的其余元素有 x x x 个,则当前最小值与最大值确定的子序列个数是 2 x 2\^x 2x,其中 x x x 不超过数组 nums \\textit{nums} nums 的长度。为了快速计算任意 x x x 对应的 2 x 2\^x 2x,需要预计算从 0 0 0 到数组长度的每个整数对应的 2 2 2 的幂。在预计算 2 2 2 的幂之后,再计算满足条件的子序列数目。 ## 解法一 ### 思路和算法 由于这道题要求计算满足条件的子序列数目,子序列不要求在原数组中连续,因此可以将数组 nums \\textit{nums} nums 按升序排序,然后在排序后的数组中计算满足条件的子序列数目。 将数组 nums \\textit{nums} nums 排序之后,从左到右遍历数组 nums \\textit{nums} nums,对于下标 i i i,当 nums \[ i \] × 2 ≤ target \\textit{nums}\[i\] \\times 2 \\le \\textit{target} nums\[i\]×2≤target 时,一定存在下标 j ≥ i j \\ge i j≥i 使得 nums \[ i \] + nums \[ j \] ≤ target \\textit{nums}\[i\] + \\textit{nums}\[j\] \\le \\textit{target} nums\[i\]+nums\[j\]≤target,此时 nums \[ i \] \\textit{nums}\[i\] nums\[i\] 和 nums \[ j \] \\textit{nums}\[j\] nums\[j\] 可以分别作为满足条件的子序列中的最小值和最大值。 由于数组 nums \\textit{nums} nums 按升序排序,因此当 nums \[ i \] × 2 ≤ target \\textit{nums}\[i\] \\times 2 \\le \\textit{target} nums\[i\]×2≤target 时,对于下标 i i i 可以使用二分查找的做法找到满足 j ≥ i j \\ge i j≥i 且 nums \[ i \] + nums \[ j \] ≤ target \\textit{nums}\[i\] + \\textit{nums}\[j\] \\le \\textit{target} nums\[i\]+nums\[j\]≤target 的最大下标 j j j。二分查找的下界和上界分别记为 low \\textit{low} low 和 high \\textit{high} high,初始时 low \\textit{low} low 位于下标 i i i, high \\textit{high} high 位于数组的最大下标,每次查找取 mid \\textit{mid} mid 为 low \\textit{low} low 和 high \\textit{high} high 的平均数向上取整,执行如下操作。 * 如果 nums \[ mid \] ≤ target \\textit{nums}\[\\textit{mid}\] \\le \\textit{target} nums\[mid\]≤target,则最大下标大于等于 mid \\textit{mid} mid,因此在下标范围 \[ mid , high \] \[\\textit{mid}, \\textit{high}\] \[mid,high\] 中继续查找。 * 如果 nums \[ mid \] \> target \\textit{nums}\[\\textit{mid}\] \> \\textit{target} nums\[mid\]\>target,则最大下标小于 mid \\textit{mid} mid,因此在下标范围 \[ low , mid − 1 \] \[\\textit{low}, \\textit{mid} - 1\] \[low,mid−1\] 中继续查找。 当 low = high \\textit{low} = \\textit{high} low=high 时,查找结束,此时 low \\textit{low} low 为满足 j ≥ i j \\ge i j≥i 且 nums \[ i \] + nums \[ j \] ≤ target \\textit{nums}\[i\] + \\textit{nums}\[j\] \\le \\textit{target} nums\[i\]+nums\[j\]≤target 的最大下标 j j j。 当 nums \[ i \] \\textit{nums}\[i\] nums\[i\] 是子序列中的最小值时, nums \[ i \] \\textit{nums}\[i\] nums\[i\] 必须在子序列中出现,满足条件的子序列中的最大值可以是大于等于 nums \[ i \] \\textit{nums}\[i\] nums\[i\] 且小于等于 nums \[ j \] \\textit{nums}\[j\] nums\[j\] 的任意值,对于任意 i \< k ≤ j i \< k \\le j i\ target \\textit{nums}\[\\textit{left}\] + \\textit{nums}\[\\textit{right}\] \> \\textit{target} nums\[left\]+nums\[right\]\>target 时,将 right \\textit{right} right 向左移动,直到 nums \[ left \] + nums \[ right \] ≤ target \\textit{nums}\[\\textit{left}\] + \\textit{nums}\[\\textit{right}\] \\le \\textit{target} nums\[left\]+nums\[right\]≤target,此时 right \\textit{right} right 是当前 left \\textit{left} left 对应的使得 nums \[ left \] + nums \[ right \] ≤ target \\textit{nums}\[\\textit{left}\] + \\textit{nums}\[\\textit{right}\] \\le \\textit{target} nums\[left\]+nums\[right\]≤target 的最大下标。 2. 当 nums \[ left \] \\textit{nums}\[\\textit{left}\] nums\[left\] 是子序列中的最小值时, nums \[ left \] \\textit{nums}\[\\textit{left}\] nums\[left\] 必须在子序列中出现,满足条件的子序列中的最大值可以是大于等于 nums \[ left \] \\textit{nums}\[\\textit{left}\] nums\[left\] 且小于等于 nums \[ right \] \\textit{nums}\[\\textit{right}\] nums\[right\] 的任意值,对于任意 left \< k ≤ right \\textit{left} \< k \\le \\textit{right} left\ target) { right--; } int count = power2[right - left]; subsequences = (subsequences + count) % MODULO; left++; } return subsequences; } } ``` ### 复杂度分析 * 时间复杂度: O ( n log ⁡ n ) O(n \\log n) O(nlogn),其中 n n n 是数组 nums \\textit{nums} nums 的长度。需要 O ( n ) O(n) O(n) 的时间预计算 2 2 2 的幂,需要 O ( n log ⁡ n ) O(n \\log n) O(nlogn) 的时间将数组 nums \\textit{nums} nums 排序,排序后需要使用双指针遍历数组 nums \\textit{nums} nums,因此时间复杂度是 O ( n + n log ⁡ n + n ) = O ( n log ⁡ n ) O(n + n \\log n + n) = O(n \\log n) O(n+nlogn+n)=O(nlogn)。 * 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \\textit{nums} nums 的长度。需要创建长度为 n n n 的数组存储 2 2 2 的幂,排序需要 O ( log ⁡ n ) O(\\log n) O(logn) 的递归调用栈空间,因此空间复杂度是 O ( n + log ⁡ n ) = O ( n ) O(n + \\log n) = O(n) O(n+logn)=O(n)。

相关推荐
旖-旎1 天前
二分查找(点名)(8)
c++·算法·二分查找·力扣
We་ct1 天前
LeetCode 74. 搜索二维矩阵:两种高效解题思路
前端·算法·leetcode·矩阵·typescript·二分查找
旖-旎2 天前
二分查找(寻找旋转排序数组中的最小值)(7)
c++·算法·二分查找·力扣
旖-旎3 天前
二分查找(山脉数组的峰顶索引)(5)
c++·算法·leetcode·二分查找·力扣·双指针
旖-旎4 天前
二分查找(x的平方根)(4)
c++·算法·二分查找·力扣·双指针
旖-旎6 天前
二分查找(1)
c++·算法·二分查找·力扣·双指针
旖-旎6 天前
二分查找(搜索插入位置)(3)
c++·算法·二分查找·力扣·双指针
无尽的罚坐人生7 天前
hot 100 35. 搜索插入位置
数据结构·算法·leetcode·二分查找
伟大的车尔尼7 天前
双指针题目:分割两个字符串得到回文串
双指针