区间计数相关题目 907,828,795,3234,2444,3639
Given an array of integers arr, find the sum of min(b), where b ranges over every (contiguous) subarray of arr. Since the answer may be large, return the answer modulo 109 + 7.
Example 1:
Input: arr = [3,1,2,4] Output: 17 Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4]. Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1. Sum is 17.
Example 2:
Input: arr = [11,81,94,43,3] Output: 444
Constraints:
1 <= arr.length <= 3 * 1041 <= arr[i] <= 3 * 104
分析:
如果brute force的话,时间复杂度在O(N3) 或者 做优化后O(N2)
[3] [3,1] [3,1,2] [3,1,2,4]
[1] [1,2] [1,2,4]
[2] [2,4]
[4]
如果我们从每个数字角度考虑的话,会发现:
3可以贡献的只有一次[3]
1可以贡献的有 [3,1] [3,1,2] [3,1,2,4] [1] [1,2] [1,2,4]
2可以贡献的有 [2] [2,4]
4可以贡献的只有 [4]
因此,针对1 ,可以贡献的次数为:
[3,1,2,4] left=-1(左侧小于1的位置), right=4(右侧小于1的位置) ,pos=1(1自己所在位置), 1可以贡献的次数即为:(1-(-1))*(4-1) = 6
针对 2可以贡献的次数为:
[3,1,2,4] left=1, right = 4, 可以贡献的次数即为: (2-1)*(3-1) = 2
另外: 关于重复的情况:
[3,1,2,1]
3可以贡献的只有一次[3]
1可以贡献的有 [3,1] [1] [3,1,2] [1,2] [1,2,1] [3,1,2,1]
2可以贡献的有 [2] [2,4]
1可以贡献的只有 [3,1,2,1] [1,2,1] [2,1][1]
标红的部分会重复计算,我们应该在计算左侧最小时,包括相等的情况,右侧计算时不包含相等的情况
class Solution { public int sumSubarrayMins(int[] arr) {
//定义stack1计算每个数字的左侧/右侧小于自己的数字位置 Stack<Integer> stack1 = new Stack(); Stack<Integer> stack2 = new Stack(); int[] preSmaller = new int[arr.length]; int[] postSmaller = new int[arr.length]; for(int i=0;i<arr.length;i++){ while(!stack1.isEmpty() && arr[stack1.peek()] > arr[i]) //左侧计算包含相等的情况 stack1.pop(); preSmaller[i] = stack1.isEmpty() ? -1 : stack1.peek(); stack1.push(i); } for(int i=arr.length-1;i>=0;i--){ while(!stack2.isEmpty() && arr[stack2.peek()] >= arr[i]) // 右侧计算不包含相等的情况 stack2.pop(); postSmaller[i] = stack2.isEmpty() ? arr.length : stack2.peek(); stack2.push(i); }
//计算结束后 long sum = 0; long mod = (long)1e9 + 7; for(int i=0;i<arr.length;i++){ sum += ((long)(i-preSmaller[i]) * (postSmaller[i]-i) * arr[i])%mod; sum %= mod; } return (int)sum; } }
Let's define a function countUniqueChars(s) that returns the number of unique characters on s.
- For example, calling
countUniqueChars(s)ifs = "LEETCODE"then"L","T","C","O","D"are the unique characters since they appear only once ins, thereforecountUniqueChars(s) = 5.
Given a string s, return the sum of countUniqueChars(t) where t is a substring of s. The test cases are generated such that the answer fits in a 32-bit integer.
Notice that some substrings can be repeated so in this case you have to count the repeated ones too.
Example 1:
Input: s = "ABC" Output: 10 Explanation: All possible substrings are: "A","B","C","AB","BC" and "ABC". Every substring is composed with only unique letters. Sum of lengths of all substring is 1 + 1 + 1 + 2 + 2 + 3 = 10
Example 2:
Input: s = "ABA"
Output: 8
Explanation: The same as example 1, except countUniqueChars("ABA") = 1.
Example 3:
Input: s = "LEETCODE" Output: 92
Constraints:
1 <= s.length <= 105sconsists of uppercase English letters only.
同样,bruteforce ,时间复杂度为O(N3) 或者 优化后O(N2)
但如果我们从每个字母的贡献度来考虑的话,比如:
ABCA
第一个A可以贡献的次数为: A,AB,ABC,ABCA
B可以贡献的次数为:AB,B,BC,BCA
class Solution { public int uniqueLetterString(String s) { int[] left = new int[s.length()]; int[] right = new int[s.length()]; int[] lastPos = new int[26]; Arrays.fill(lastPos, -1); for(int i=0;i<s.length();i++){ char c = s.charAt(i); left[i] = lastPos[c-'A']; lastPos[c-'A'] = i; } Arrays.fill(lastPos, s.length()); for(int i=s.length()-1;i>=0;i--){ char c = s.charAt(i); right[i] = lastPos[c-'A']; lastPos[c-'A'] = i; } int sum = 0; for(int i=0;i<s.length();i++){ sum += (i-left[i])*(right[i]-i); } return sum; } }
795. Number of Subarrays with Bounded Maximum
Given an integer array nums and two integers left and right, return the number of contiguous non-empty subarrays such that the value of the maximum array element in that subarray is in the range [left, right].
The test cases are generated so that the answer will fit in a 32-bit integer.
Example 1:
Input: nums = [2,1,4,3], left = 2, right = 3 Output: 3 Explanation: There are three subarrays that meet the requirements: [2], [2, 1], [3].
Example 2:
Input: nums = [2,9,2,5,6], left = 2, right = 8 Output: 7
Constraints:
1 <= nums.length <= 1050 <= nums[i] <= 1090 <= left <= right <= 109
解法:
1. 计算每个元素可以作为最大元素的subarray的个数- 贡献次数
2. 过滤满足条件的元素(在left和right范围内的) 对贡献次数进行累加
跟907 非常类似,看每一个数字可以贡献的次数
3 pass
1st pass: 求出左侧最后一个大于等于该元素的位置 preGreaterEqual[]
2nd pass: 求出右侧第一个大于该元素的位置 postGreater[]
3rd pass: 根据左右侧个数
0 1 2 3 2, 1, 4, 3 pregreater:-1 0 -1 2 posgreater 2 2 4 4
注意点: 若干相同元素的时候,可能会重复计算,因此要使用preGreaterEqual, 而不是 preGreater
比如: 5,5,5 每个5都会左右边界算一次 ,就会重复计算
class Solution { public int numSubarrayBoundedMax(int[] nums, int left, int right) { int len = nums.length; //calculate the pre greater Stack<Integer> stack = new Stack(); int[] preGE = new int[len]; for(int i = 0; i < len; i++){ while(!stack.isEmpty() && nums[stack.peek()] <= nums[i]){ stack.pop(); } preGE[i] = stack.isEmpty() ? -1 : stack.peek(); stack.push(i); } //calculate the post greater stack.clear(); int[] postG = new int[len]; for(int i = len - 1; i >= 0; i--){ while(!stack.isEmpty() && nums[stack.peek()] < nums[i]){ stack.pop(); } postG[i] = stack.isEmpty() ? len : stack.peek(); stack.push(i); } //caluclate the result int result = 0; for(int i = 0; i < len; i++){ if(nums[i] >= left && nums[i] <= right) result += (i - preGE[i]) * (postG[i] - i); } return result; } }
You are given a binary string s.
Return the number of substrings with dominant ones.
A string has dominant ones if the number of ones in the string is greater than or equal to the square of the number of zeros in the string.
Example 1:
Input: s = "00011"
Output: 5
Explanation:
The substrings with dominant ones are shown in the table below.
| i | j | s[i..j] | Number of Zeros | Number of Ones |
|---|---|---|---|---|
| 3 | 3 | 1 | 0 | 1 |
| 4 | 4 | 1 | 0 | 1 |
| 2 | 3 | 01 | 1 | 1 |
| 3 | 4 | 11 | 0 | 2 |
| 2 | 4 | 011 | 1 | 2 |
Example 2:
Input: s = "101101"
Output: 16
Explanation:
The substrings with non-dominant ones are shown in the table below.
Since there are 21 substrings total and 5 of them have non-dominant ones, it follows that there are 16 substrings with dominant ones.
| i | j | s[i..j] | Number of Zeros | Number of Ones |
|---|---|---|---|---|
| 1 | 1 | 0 | 1 | 0 |
| 4 | 4 | 0 | 1 | 0 |
| 1 | 4 | 0110 | 2 | 2 |
| 0 | 4 | 10110 | 2 | 3 |
| 1 | 5 | 01101 | 2 | 3 |
Constraints:
1 <= s.length <= 4 * 104sconsists only of characters'0'and'1'.
class Solution { private Queue<Integer> que = new LinkedList<>(); private int len = 0; public int numberOfSubstrings(String s) { //1. 记录所有0的位置放入queue for(int i = 0; i < s.length(); i++) { if(s.charAt(i) == '0') que.offer(i); } len = s.length(); // 末尾也需要放入 que.offer(s.length()); //2. 从0~len-1作为起始位置开始统计 int result = 0; for(int i = 0; i < s.length(); i++) { // 已经在当前游标前的0不需要了,直接移除 while(que.peek() < i) que.poll(); // 计算当前游标向右的所有元素 result += count(que, i); } return result; } // 0 1 2 3 4 5 // 1 0 1 1 0 1| // ^ private int count(Queue<Integer> que, int start) { int result = 0; int zero = 0;//到目前0的个数 int lastCalPos = start;//上次计算位置 for(int pos : que) { // 关键点1: the number of ones in the string is greater than or equal to the square of the number of zeros if(zero * zero > len) break; // 满足valid的substring需要的最小end index int minInd = Math.max(start + zero + zero * zero - 1, lastCalPos); // 累加到result result += Math.max(0, pos - minInd); // 关键点2: 更新计算的最后位置 lastCalPos = pos; zero++; } return result; } }
You are given an integer array nums and two integers minK and maxK.
A fixed-bound subarray of nums is a subarray that satisfies the following conditions:
- The minimum value in the subarray is equal to
minK. - The maximum value in the subarray is equal to
maxK.
Return the number of fixed-bound subarrays.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [1,3,5,2,7,5], minK = 1, maxK = 5 Output: 2 Explanation: The fixed-bound subarrays are [1,3,5] and [1,3,5,2].
Example 2:
Input: nums = [1,1,1,1], minK = 1, maxK = 1 Output: 10 Explanation: Every subarray of nums is a fixed-bound subarray. There are 10 possible subarrays.
Constraints:
2 <= nums.length <= 1051 <= nums[i], minK, maxK <= 106
class Solution { /** 思路: 记录minK和maxK和超出(minK,maxK)最后一次出现为位置 1. 如果minK,maxK都出现了,那么可以计算以当前元素为结尾的满足条件的个数:Math.min(preMin, preMax) - preBad, preBad 有可能出现在preMin, preMax之后 则不满足,所以Math.max(Math.min(preMin, preMax) - preBad, 0) */ public long countSubarrays(int[] nums, int minK, int maxK) { int preMin = -1;//记录min最后一次出现的位置 int preMax = -1;//记录max最后一次出现的位置 int preBad = -1;//记录超出范围的最后一次出现的位置 long result = 0; for(int i = 0; i < nums.length; i++) { if(nums[i] == minK){ //更新min的最后出现位置 preMin = i; } if(nums[i] == maxK){ //更新max的最后出现位置 preMax = i; } if(nums[i] > maxK || nums[i] < minK){ //更新bad的最后出现位置 preBad = i; } //如果截止当前位置,min和max都已经找到,那么可以计算出以当前i位置结尾能产生个数:Math.min(preMin, preMax) - preBad if(preMin >=0 && preMax >=0){ result += Math.max(Math.min(preMin, preMax) - preBad, 0); } } return result; } }
You are given a string s of length n and an integer array order, where order is a permutation of the numbers in the range [0, n - 1].
Starting from time t = 0, replace the character at index order[t] in s with '*' at each time step.
A substring is valid if it contains at least one '*'.
A string is active if the total number of valid substrings is greater than or equal to k.
Return the minimum time t at which the string s becomes active. If it is impossible, return -1.
Note:
- A permutation is a rearrangement of all the elements of a set.
- A substring is a contiguous non-empty sequence of characters within a string.
Example 1:
Input: s = "abc", order = [1,0,2], k = 2
Output: 0
Explanation:
t | order[t] | Modified s | Valid Substrings | Count | Active (Count >= k) |
|---|---|---|---|---|---|
| 0 | 1 | "a*c" |
"*", "a*", "*c", "a*c" |
4 | Yes |
The string s becomes active at t = 0. Thus, the answer is 0.
Example 2:
Input: s = "cat", order = [0,2,1], k = 6
Output: 2
Explanation:
t | order[t] | Modified s | Valid Substrings | Count | Active (Count >= k) |
|---|---|---|---|---|---|
| 0 | 0 | "*at" |
"*", "*a", "*at" |
3 | No |
| 1 | 2 | "*a*" |
"*", "*a", ", ", "*" |
5 | No |
| 2 | 1 | "***" |
All substrings (contain '*') |
6 | Yes |
The string s becomes active at t = 2. Thus, the answer is 2.
Example 3:
Input: s = "xy", order = [0,1], k = 4
Output: -1
Explanation:
Even after all replacements, it is impossible to obtain k = 4 valid substrings. Thus, the answer is -1.
Constraints:
1 <= n == s.length <= 105order.length == n0 <= order[i] <= n - 1sconsists of lowercase English letters.orderis a permutation of integers from 0 ton - 1.1 <= k <= 109
区间计数 + 二分猜答案
class Solution: def minTime(self, s: str, order: List[int], k: int) -> int: # 区间计数,计算active的个数 def countValid(curr): cnt = 0 starPos = -1 for i in range(len(curr)): if curr[i] == '*': starPos = i cnt += starPos + 1 return cnt # 二分猜答案 left = 0 right = len(s) - 1 result = -1 while left <= right: mid = (left + right) // 2 temp = list(s) for i in range(0, mid + 1): temp[order[i]] = '*' # print(mid, temp, countValid(temp)) if countValid(temp) >= k: result = mid right = mid - 1 else: left = mid + 1 return result

浙公网安备 33010602011771号