今日头条2018笔试编程题-第二题最大乘积和

import java.util.*;
import java.lang.*;

/*
input
3
6 2 1
output
36
*/
public class toutiaoB {
	/*
	*滑动窗口法
	迭代窗口大小,设计队列模拟窗口,且队列能快速取出当前窗口内最小值
	*/
	public static int solution(int n, int[] nums) {

		//preSum[i] 表示 sum[0]~sum[i]的和
		int[] preSum = new int[n];
		preSum[0] = nums[0];
		for (int i = 1; i < n; i++) {
			preSum[i] = preSum[i - 1] + nums[i];
		}

		int retMax = 0;
		//range length is L
		for (int L = 1; L <= n; L++) {
			//滑动窗口,保持最小
			Deque<Integer> Q = new ArrayDeque<Integer>();

			for (int j = 0; j < n; j++) {
				//remove numbers out of range
				while( !Q.isEmpty() && Q.peekFirst() < j - L + 1) {
					Q.pollFirst();
				}

				//remove smaller numbers which are unuseless.
				while( !Q.isEmpty() && nums[Q.peekLast()] >= nums[j] ) {
					Q.pollLast();
				}
				Q.offerLast(j);

				if (j >= L - 1) {
					retMax = Math.max( retMax, nums[Q.peekFirst()] * getSumInRange(preSum, j - L + 1, j) );
				}
			}
		}
		return retMax;
	}

	/*
	* 单调栈法
	以第nums[i]为最小数,找到nums[left],nums[right], 
	使得min( nums[left]~nums[right] ) = nums[i], 且区间[left, right]最大, 其中left < i < right
	*/
	public static int solution2(int n, int[] nums) {
		//preSum[i] 表示 sum[0]~sum[i]的和
		int[] preSum = new int[n];
		preSum[0] = nums[0];
		for (int i = 1; i < n; i++) {
			preSum[i] = preSum[i - 1] + nums[i];
		}

		int retMax = 0;
		//单增栈
		Stack<Integer> stIdx = new Stack<Integer>();
		for (int i = 0; i < n; i++) {
			// System.out.printf("==i:%d==\n", i);
			while( !stIdx.empty() && nums[stIdx.peek()] >= nums[i] ) {
				int curIndex = stIdx.pop();
				int curMinNum = nums[curIndex];
				int preIndex = stIdx.empty() ? -1 : stIdx.peek();

				retMax = Math.max( retMax, curMinNum * getSumInRange(preSum, preIndex + 1, i - 1) );
				// System.out.printf("retMax:%d stSize:%d curIndex:%d curMinNum:%d [left,right]:[%d,%d]\n", 
				// 	retMax, stIdx.size(), curIndex, curMinNum, preIndex + 1, i - 1);
			}
			stIdx.push(i);
		}

		if ( !stIdx.empty() ) {
			int Rindex = stIdx.peek() + 1;
			while( !stIdx.empty() ) {
				int curIndex = stIdx.pop();
				int curMinNum = nums[curIndex];
				int preIndex = stIdx.empty() ? -1 : stIdx.peek();

				retMax = Math.max( retMax, curMinNum * getSumInRange(preSum, preIndex + 1, Rindex - 1) );
				// System.out.printf("retMax:%d stSize:%d curIndex:%d curMinNum:%d [left,right]:[%d,%d]\n", 
				// 	retMax, stIdx.size(), curIndex, curMinNum, preIndex + 1, Rindex - 1);
			}
		}

		return retMax;
	}

	public static int getSumInRange(int[] preSum, int leftIdx, int rightIdx) {
		if (leftIdx == 0)
			return preSum[rightIdx];
		else
			return preSum[rightIdx] - preSum[leftIdx - 1];	
	}


	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int[] nums = new int[n];
		for (int i = 0; i < n; i++) {
			nums[i] = sc.nextInt();
		}

		System.out.println( solution2(n, nums) );
	}
}

#字节跳动#
全部评论
膜拜,厉害厉害
点赞 回复 分享
发布于 2017-08-23 16:40
ac了吗
点赞 回复 分享
发布于 2017-08-23 16:05
import java.util.*; public class Main4 { public static void main(String args[]) { Scanner sc = new Scanner(System.in); while(sc.hasNext()) { int n = sc.nextInt(); int a[] = new int[n]; for(int i=0;i<n;i++) { a[i] = sc.nextInt(); } int max = 0; for(int i=1;i<=n;i++) { Deque<Integer> q = new LinkedList<>(); int sum = 0; for(int j=0;j<n;j++) { sum = sum+a[j]; if(j-i>=0) { sum = sum - a[j - i]; } while(!q.isEmpty()&&a[j]<=a[q.peekLast()]) { q.pollLast(); } q.addLast(j); if(!q.isEmpty()&&q.peekFirst()<=j-i) { q.pollFirst(); } if(j-i>=-1) { int x = q.peekFirst(); max = Math.max(max,sum*a[x]); } } } System.out.println(max); } } } //可以帮我看下么 这个只通过30%的测试用例 窗口的长度改为1~n/100+1 通过 //60%的测试用例
点赞 回复 分享
发布于 2017-08-23 15:37

相关推荐

09-01 21:40
已编辑
同济大学 Java
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

更多
正在热议
更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务