Find the maximum sum of three non overlapping subarrays in the array

Posted by Shellfishman on Thu, 09 Dec 2021 05:51:21 +0100

problem

Give you an integer array nums and an integer k, find three sub arrays with length k, non overlapping and 3 * k items and the largest sum, and return these three sub arrays.

The result is returned in the form of an array of subscripts. Each item in the array indicates the starting position of each sub array (subscript starts from 0). If there are multiple results, the one with the smallest dictionary order is returned.

Example 1:
Input: nums = [1,2,1,2,6,7,5,1], k = 2
 Output:[0,3,5]
Explanation: subarray [1, 2], [2, 6], [7, 5] The corresponding starting subscript is [0, 3, 5]. 
You can also take [2, 1], But the result [1, 3, 5] Larger in dictionary order.
Example 2:
Input: nums = [1,2,1,2,1,2,1,2,1], k = 2
 Output:[0,2,4]
Tips:
1 <= nums.length <= 2 * 104
1 <= nums[i] < 216
1 <= k <= floor(nums.length / 3)

Train of thought analysis

To calculate the maximum sum of three non overlapping sub arrays, we can enumerate the positions of the third sub array and maintain the maximum sum and positions of the first two non overlapping sub arrays.
To calculate the maximum sum of two non overlapping subarrays, we can enumerate the positions of the second subarray while maintaining the maximum sum and position of the first subarray.
Therefore, we first solve the maximum sum problem of a single sub array, then solve the maximum sum problem of two non overlapping sub arrays, and finally solve the maximum sum problem of three non overlapping sub arrays.
The official uses three sliding windows to solve this problem.
The code is as follows

Answer code

package december;
import java.util.Arrays;
public class Eight {
	 public static int[] maxSumOfThreeSubarrays(int[] nums, int k) {
		       //Initializes an int array of length 3
		        int[] ans = new int[3];
		        //Sum1, sum2 and sum3 are the maximum sum of three non overlapping subarrays respectively
		        //Starting subscripts of the first and second arrays corresponding to maxsum12idx1 and maxsum12idx2
		        int sum1 = 0, maxSum1 = 0, maxSum1Idx = 0;
		        int sum2 = 0, maxSum12 = 0, maxSum12Idx1 = 0, maxSum12Idx2 = 0;
		        int sum3 = 0, maxTotal = 0;
		        //Starting from the i = k * 2 subscript, ensure that there must be two arrays of equal length and non overlapping
		        for (int i = k * 2; i < nums.length; ++i) {
		            sum1 += nums[i - k * 2];
		            sum2 += nums[i - k];
		            sum3 += nums[i];
		            //When i satisfies three sizes with length k 
		            if (i >= k * 3 - 1) {
		                if (sum1 > maxSum1) {
		                    maxSum1 = sum1;
		                    maxSum1Idx = i - k * 3 + 1;
		                }
		                if (maxSum1 + sum2 > maxSum12) {
		                    maxSum12 = maxSum1 + sum2;
		                    maxSum12Idx1 = maxSum1Idx;
		                    maxSum12Idx2 = i - k * 2 + 1;
		                }
		                if (maxSum12 + sum3 > maxTotal) {
		                    maxTotal = maxSum12 + sum3;
		                    ans[0] = maxSum12Idx1;
		                    ans[1] = maxSum12Idx2;
		                    ans[2] = i - k + 1;
		                }
		                sum1 -= nums[i - k * 3 + 1];
		                sum2 -= nums[i - k * 2 + 1];
		                sum3 -= nums[i - k + 1];
		            }
		        }
		        return ans;
		    }
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] nums = {1,2,1,2,6,7,5,3,4,4,5};
	    int k = 3;
	    //System.out.println() cannot directly output an int array, so it needs to be converted;
	    String str=Arrays.toString(maxSumOfThreeSubarrays(nums,k));
	    System.out.println(str);
	}

}

expand

Principle and basic application of sliding window

Recently, there is a need to count the access times of a key in a unit time. For example, if a key in redis is accessed more than 100 times every 5 seconds, the key will be taken out and processed separately.

For such unit time statistics, it is obvious that we all know that there is a boundary problem, such as the limit of 100 times in 5 seconds. Just before 4.99 seconds, the access was 0, 100 times in the last 0.01 seconds and 100 times in 5.01 seconds. In other words, there is obvious burr during access. In order to weaken this burr, we can use sliding window.

sliding window

The main principle of sliding window is relatively simple. It is to split this unit time. For example, the statistical range of 5 seconds is divided into 5 1 seconds.
When the request comes in, first judge which of the five 1-second time slices the current request belongs to, then add 1 to the corresponding statistical value of the corresponding time slice, and then judge whether the sum of the current times plus the first four time slices has exceeded the set threshold.
When the time has reached the sixth time slice, kill the first time slice, because no matter how many statistics the first slice has, it will no longer participate in the subsequent calculation.
In this way, with the passage of time, the statistical values are continuously counted with the rolling of each time slice.
The specific number of slices per unit time should be determined according to the actual situation. Of course, there is no doubt that the smaller the slitting, the less the burr phenomenon. The more accurate the system statistics are, the larger the memory consumption will be, because the array of your window will be larger.

The idea of code implementation is to define the number of slices. Each slice has an independent counter, and all slices are combined into an array. When the request comes, judge which partition the request should be divided into according to the partition rules. To determine whether the threshold is exceeded, add the first N statistical values and compare the defined threshold.

import java.util.concurrent.atomic.AtomicInteger;

/**
 * Slide the window. The same key in this window is calculated by single thread.
 *
 * @author wuweifeng wrote on 2019-12-04.
 */
public class SlidingWindow {
	/**
	 * Circular queue is used to install multiple windows, which is twice the windowSize
	 */
	private AtomicInteger[] timeSlices;
	/**
	 * Total length of queue
	 */
	private int timeSliceSize;
	/**
	 * The duration of each time slice, in milliseconds
	 */
	private int timeMillisPerSlice;
	/**
	 * How many time slices are there (i.e. window length)
	 */
	private int windowSize;
	/**
	 * Maximum threshold allowed to pass in a full window period
	 */
	private int threshold;
	/**
	 * The start creation time of the sliding window, that is, the first data
	 */
	private long beginTimestamp;
	/**
	 * Timestamp of the last data
	 */
	private long lastAddTimestamp;
	public static void main(String[] args) {
//One time slice per second, 5 windows in total
		SlidingWindow window = new SlidingWindow(100, 4, 8);
		for (int i = 0; i < 100; i++) {
			System.out.println(window.addCount(2));
			window.print();
			System.out.println("--------------------------");
			try {
				Thread.sleep(102);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public SlidingWindow(int duration, int threshold) {
//For more than 10 minutes, press 10 minutes
		if (duration > 600) {
			duration = 600;
		}
//It requires detection in 5 seconds,
		if (duration <= 5) {
			this.windowSize = 5;
			this.timeMillisPerSlice = duration * 200;
		} else {
			this.windowSize = 10;
			this.timeMillisPerSlice = duration * 100;
		}
		this.threshold = threshold;
// Ensure that it is stored in at least two window s
		this.timeSliceSize = windowSize * 2;
		reset();
	}
	public SlidingWindow(int timeMillisPerSlice, int windowSize, int threshold) {
		this.timeMillisPerSlice = timeMillisPerSlice;
		this.windowSize = windowSize;
		this.threshold = threshold;
// Ensure that it is stored in at least two window s
		this.timeSliceSize = windowSize * 2;
		reset();
	}
	/**
	 * initialization
	 */
	private void reset() {
		beginTimestamp = SystemClock.now();
//Number of windows
		AtomicInteger[] localTimeSlices = new AtomicInteger[timeSliceSize];
		for (int i = 0; i < timeSliceSize; i++) {
			localTimeSlices[i] = new AtomicInteger(0);
		}
		timeSlices = localTimeSlices;
	}

	private void print() {
		for (AtomicInteger integer : timeSlices) {
			System.out.print(integer + "-");
		}
	}
	/**
	 * Calculate the position of the current time slice
	 */
	private int locationIndex() {
		long now = SystemClock.now();
//If the current key has exceeded a whole time slice, it can be initialized directly without calculation
		if (now - lastAddTimestamp > timeMillisPerSlice * windowSize) {
			reset();
		}
		return (int) (((now - beginTimestamp) / timeMillisPerSlice) % timeSliceSize);
	}

	/**
	 * Increase count quantity
	 */
	public boolean addCount(int count) {
//Which small time window is your current location
		int index = locationIndex();
// System.out.println("index:" + index);
//Then empty the data of the data grid between windowSize and 2*windowSize in front of you
//For example, if there are four windows in one second, the array has a total of eight windows
//When the current index is 5, 6, 7, 8 and 1 are cleared. Then add up 2, 3, 4 and 5 to be the sum in the window
		clearFromIndex(index);
		int sum = 0;
// Continue + 1 in the current time slice
		sum += timeSlices[index].addAndGet(count);
//Plus the previous time slices
		for (int i = 1; i < windowSize; i++) {
			sum += timeSlices[(index - i + timeSliceSize) % timeSliceSize].get();
		}
		System.out.println(sum + "---" + threshold);
		lastAddTimestamp = SystemClock.now();
		return sum >= threshold;
	}
	private void clearFromIndex(int index) {
		for (int i = 1; i <= windowSize; i++) {
			int j = index + i;
			if (j >= windowSize * 2) {
				j -= windowSize * 2;
			}
			timeSlices[j].set(0);
		}
	}
}
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
 * Used to solve high and issue System.currentTimeMillis Caton
 * 
 * @author lry
 */
public class SystemClock {
	private final int period;
	private final AtomicLong now;
	private static class InstanceHolder {
		private static final SystemClock INSTANCE = new SystemClock(1);
	}
	private SystemClock(int period) {
		this.period = period;
		this.now = new AtomicLong(System.currentTimeMillis());
		scheduleClockUpdating();
	}
	private static SystemClock instance() {
		return InstanceHolder.INSTANCE;
	}
	private void scheduleClockUpdating() {
		ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
			@Override
			public Thread newThread(Runnable runnable) {
				Thread thread = new Thread(runnable, "System Clock");
				thread.setDaemon(true);
				return thread;
			}
		});
		scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), period, period, TimeUnit.MILLISECONDS);
	}
	private long currentTimeMillis() {
		return now.get();
	}
	/**
	 * Used to replace the original System.currentTimeMillis()
	 */
	public static long now() {
		return instance().currentTimeMillis();
	}
}
Reference code main Method by modifying the time, the number of windows and the threshold of each time slice.

This is a simple implementation.

--------
Extended reference:
Copyright notice: This is the original article of CSDN blogger "leg Taibai", which follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this notice for reprint.
Original link: https://blog.csdn.net/weixin_42355294/article/details/114687837
Title Source: LeetCode
Link: https://leetcode-cn.com/problems/maximum-sum-of-3-non-overlapping-subarrays
The copyright belongs to Lingkou network. For commercial reprint, please contact the official authorization, and for non-commercial reprint, please indicate the source.
Please inform us of the infringement and delete it, thank you!

Topics: Java Algorithm Back-end