记录在猿辅导笔试时遇到的一道题目。
问题
给定一个正整型数组,要求找出最长的连续元素个数,且这些元素之和小于或等于给定的某个数s。
- 例如:数组 5 1 1 1 2 7,给定最大5
那么应返回4,即1 1 1 2。
问题分析
第一眼,就觉得是动态规划,可以设置一个数组nums,存储以每个元素作为结尾时最长的连续元素个数,且和不超过给定的数。设置一个value数组存储对应的元素和。这个思路没有问题,但是有一个易错点。即如果前一个元素的最长连续子数组之和加上当前元素大于了给定数,且此时当前元素值不大于给定数,那么这时不能够将nums设为1,应该要从此元素位置向前遍历,直到找到刚好大于给定数的位置之前,这个才是此元素作为结尾的最长连续子数组。对于如果当前元素大于了给定数,那么设置value数组在这个下标处为0,nums数组在这个下标处为0。
解法二
解法二和第一个解法思路一致,都是计算以当前元素作为结尾最长的连续子数组长度,但是使用另外一种不消耗内存的方法,即双指针法。简单地说就是固定左指针,动右指针,当两指针之间的元素和大于了给定数,则移动右指针,直到两指针内部元素之和小于或等于了给定数为止。代码如下:
作者:我是一个莫得感情的笔试机器
链接:https://www.nowcoder.com/discuss/261376?type=all&order=time&pos=&page=0
来源:牛客网
对原作者的代码进行了一定修改,更加准确。
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int s = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
int num = 0;
int sum = arr[0];
int i = 0;
int j = 1;
for(int _i=0;_i<n;_i++)
{
i = _i;
j = _i+1;
if(arr[_i]<=s)
{
sum = arr[_i];
num = 1;
break;
}
}
while (j < n) {
if (sum + arr[j] <= s) {
sum += arr[j++];
num = Math.max(num, j - i);
} else {
sum += arr[j++];
while (i <= j && sum > s) {
sum -= arr[i];
i++;
}
}
}
System.out.println(num);
}
}
总结
对于一些题目并没有那么复杂是我们想得太复杂了。通过此题目复习了双指针方法解决实际面试题目。