7月算法训练------第六天(滑动窗口)解题报告
题目类型:滑动窗口
题目难度:简单
第一题、643. 子数组最大平均数 I
- 题目链接:643. 子数组最大平均数 I
- 思路分析:
- 穷举法:
将窗口长度固定为k
,将k
个数相加得到和,求和的最大值,然后求平均值。但时间复杂度太高,超出时间限制。
- 代码
class Solution {
public double findMaxAverage(int[] nums, int k) {
if(nums.length == 1 && k == 1){
return (double)nums[0];
}
double ans = 0;
int temp, max = Integer.MIN_VALUE;
for(int i = 0; i <= nums.length - k; i++){
temp = 0;
for(int j = i; j < k + i; j++){
temp += nums[j];
}
if(temp > max){
max = temp;
}
}
ans = max * 1.0 / k;
return ans;
}
}
- 双指针法:
定义左指针l
和右指针r
,当r-l+1<k
时,就让nums[r]
加进sum
中;当r-l+1=k
时,就让sum
求最大值;当r-l+1=k
时,就让l++
。
- 代码:
class Solution {
public double findMaxAverage(int[] nums, int k) {
double ans = 0;
int sum = 0, max = Integer.MIN_VALUE;
int l = 0, r = -1;
while(r < nums.length - 1){
r++;
sum += nums[r];
while(r - l + 1 > k){
sum -= nums[l];
l++;
}
if(r - l + 1 == k){
max = Math.max(max, sum);
}
}
ans = max * 1.0 / k;
return ans;
}
}
第二题、718. 最长重复子数组
- 题目链接:718. 最长重复子数组
- 思路分析:
- 动态规划:
动态规划思路十分巧妙:
我们申请一个二维dp[nums1.length][nums2.length]
例如,我们用题上的例子:
[1,2,3,2,1]
[3,2,1,4,7]
行头表示nums1
,列头表示nums2
当i
或j
其中有一个为0
时,按以下规则赋值:
dp[i][j] = (nums1[i] == nums2[j]) ? 1 : 0;
当i
且j
都不为0
时,按以下规则赋值:
dp[i][j] = (nums1[i] == nums2[j]) ? dp[i-1][j-1] + 1 : 0;
然后每次求一次最大值。
1 | 2 | 3 | 2 | 1 | |
---|---|---|---|---|---|
3 | 0 | 0 | 1 | 0 | 0 |
2 | 0 | 1 | 0 | 2 | 0 |
1 | 1 | 0 | 0 | 0 | 3 |
4 | 0 | 0 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 |
- 代码:
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int[][] dp = new int[nums1.length][nums2.length];
int max = 0;
for(int i = 0; i < nums1.length; i++){
for(int j = 0; j < nums2.length; j++){
if(i == 0 || j == 0){
dp[i][j] = (nums1[i] == nums2[j]) ? 1 : 0;
}else{
dp[i][j] = (nums1[i] == nums2[j]) ? dp[i-1][j-1] + 1 : 0;
}
max = Math.max(max, dp[i][j]);
}
}
return max;
}
}
第三题、978. 最长湍流子数组
- 题目链接:978. 最长湍流子数组
- 思路分析:
- 动态规划:
我们拿题中的例子:arr = [9,4,2,10,7,8,8,1,9]
我们先申请一个比arr.length长度小1的int数组flag,我们按以下规则给flag赋值:- 如果
arr[i]>arr[i+1]
,那么就给flag[i]
赋0
; - 如果
arr[i]<arr[i+1]
,那么就给flag[i]
赋1
; - 如果
arr[i]=arr[i+1]
,那么就给flag[i]
赋2
;
经过这一步,flag={0,0,1,0,1,2,0,1}
;
然后我们声明一个dp[flag.length]
的数组,
给dp[0]
赋初值:- 如果
flag[0]=2
,那么dp[0]=1
; - 如果
flag[0]!=2
,那么dp[0]=2
;
- 如果
- 当
flag[i] = 2
时,dp[i] =1
; - 当
flag[i] != 2
之后,- 当
flag[i] != flag[i-1]
时,dp[i]=dp[i-1]+1
; - 当
flag[i] = flag[i-1]
时,dp[i]=2
;
- 当
- 如果
经过这一步,dp={2,2,3,4,5,1,2,3};
最后,返回dp的最大值。
3. 代码:
class Solution {
public int maxTurbulenceSize(int[] arr) {
if(arr.length < 2) return arr.length;
int[] flag = new int[arr.length - 1];
for(int i = 0; i < flag.length; i++){
if(arr[i] > arr[i+1]){
flag[i] = 0;
}else if(arr[i] < arr[i+1]){
flag[i] = 1;
}else{
flag[i] = 2;
}
}
if(flag.length == 1){
if(flag[0] == 2){
return 1;
}else{
return 2;
}
}
int[] dp = new int[flag.length];
if(flag[0] == 2){
dp[0] = 1;
}else {
dp[0] = 2;
}
for(int i = 1; i < flag.length; i++){
if(flag[i] == 2){
dp[i] = 1;
}else{
if(flag[i] != flag[i-1]){
dp[i] = dp[i-1] + 1;
}else{
dp[i] = 2;
}
}
}
Arrays.sort(dp);
return dp[dp.length - 1];
}
}
第四题、1052. 爱生气的书店老板
- 题目链接:1052. 爱生气的书店老板
- 思路分析:
- 我们先将老板不生气的时候顾客数量加起来,得到一个基础的和
initSum
。 - 然后我们移动这个长度为minutes的窗口,这个窗口内所有老板生气的时候再继续加起来得到第二个和值,得到这个最大值,然后将这个最大值和
initSum
加起来,就是最终的答案。
- 代码:
class Solution {
public int maxSatisfied(int[] customers, int[] grumpy, int minutes) {
int initSum = 0;
for(int i = 0; i < customers.length; i++){
if(grumpy[i] == 0){
initSum += customers[i];
}
}
int[] move = new int[customers.length - minutes + 1];
for(int i = 0; i < customers.length - minutes + 1; i++){
for(int j = i; j <= i + minutes - 1; j++){
if(grumpy[j] == 1){
move[i] += customers[j];
}
}
}
Arrays.sort(move);
return move[move.length - 1] + initSum;
}
}