This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021
The median in the data stream
41. Median in data stream
Difficulty: difficulty
Topic: leetcode-cn.com/problems/sh…
How do I get a median in a data stream? If an odd number of values are read from the data stream, the median is the number in the middle of all values sorted. If an even number of values are read from the data stream, the median is the average of the middle two numbers sorted by all the values.
For example,
The median for [2,3,4] is 333
The median of [2,3] is (2+3)/2=2.5(2+3)/2 =2.5(2+3)/2 =2.5
Design a data structure that supports the following two operations:
- Void addNum(int num) – Adds an integer from the data stream to the data structure
- Double findMedian() – Returns the current median for all elements.
Example 1:
Input: [" MedianFinder ", "addNum", addNum ""," findMedian ", "addNum", "findMedian"] [[], [1], [2], [], [3], []] output: [null, null, null, 1.50000, null, 2.00000]Copy the code
Example 2:
Input: [" MedianFinder ", "addNum", "findMedian", "addNum", "findMedian"] [[], [2], [], [3], []] output: [null, null, 2.00000, null, 2.50000]Copy the code
Limit: Up to 50000 calls to addNum and findMedian
Answer key
Method one direct method
Sort all elements first, calculate the median, and then extract the median.
/** * initialize your data structure here. */
var MedianFinder = function () {
this.result = [];
};
/ * * *@param {number} num
* @return {void}* /
MedianFinder.prototype.addNum = function (num) {
this.result.push(num);
};
/ * * *@return {number}* /
MedianFinder.prototype.findMedian = function () {
const len = this.result.length;
if(! len)return null;
this.result.sort((a, b) = > a - b);
const mid = Math.floor((len - 1) / 2); // round down
if (len % 2) {
return this.result[mid];
}
return (this.result[mid] + this.result[mid + 1) /2;
};
/** * Your MedianFinder object will be instantiated and called as such: * var obj = new MedianFinder() * obj.addNum(num) * var param_2 = obj.findMedian() */
Copy the code
- Time complexity: O(NlogNNlogNNlogN), sort uses quicksort
- Space complexity: O(NlogNNlogNNlogN)
Method 2 binary search
Keep the array in order before each element is added, and use binary lookup to find the correct location and insert its new element.
var MedianFinder = function () {
this.result = [];
};
MedianFinder.prototype.addNum = function (num) {
const len = this.result.length;
if(! len) {this.result.push(num);
return;
}
let l = 0,
r = len - 1;
while (l <= r) {
let mid = Math.floor((l + r) / 2);
if (this.result[mid] === num) {
this.result.splice(mid, 0, num);
return;
} else if (this.result[mid] > num) {
r = mid - 1;
} else {
l = mid + 1; }}this.result.splice(l, 0, num);
};
MedianFinder.prototype.findMedian = function () {
const len = this.result.length;
if(! len)return null;
const mid = Math.floor((len - 1) / 2);
if (len % 2) {
return this.result[mid];
}
return (this.result[mid] + this.result[mid + 1) /2;
};
Copy the code
- Time complexity: O(NNN), binary search requires O(logNlogNlogN), move requires O(NNN), so O(NNN)
- Space complexity: O(NNN)
Method 3 Priority queue (heap)
With the size heap, the maximum heap holds the smaller half of the data stream, and the minimum heap holds the larger one of the data stream, keeping the two heaps equal in size or the maximum heap = the minimum heap + 1. (Odd and even)
When findMedian is called, the median is either the top element of the largest heap or (top of the largest heap + top of the smallest heap) / 2. (Odd and even)
The practice of maintaining equality:
- Num is placed in the maximum heap, the top element of the maxHeap, and the minimum heap minHeap.
- If the size of the maximum heap is less than the size of the minimum heap, take the top element of the minHeap and place it in the maxHeap.
JavaScript does not have a heap function, you need to write their own, the following is the binary heap implementation code:
const defaultCmp = (x, y) = > x > y;// It is used to control the judgment, so as to realize the maximum heap and the minimum heap switch
const swap = (arr, i, j) = > ([arr[i], arr[j]] = [arr[j], arr[i]]);// It is used to swap two nodes
class Heap {
constructor(cmp = defaultCmp){
this.container = []; // It is used to store data
this.cmp = cmp;
}
push_heap(data) { // Used to add a node
const { container, cmp } = this;
container.push(data); // First insert the value into the last bit of the binary heap
let index = container.length - 1;// Data coordinates
while(index){
let parent = Math.floor((index - 1) / 2); // The parent node of data
if(! cmp(container[index], container[parent])){For example, if the child node is smaller than the parent node, return the maximum heap.
return;
}
swap(container, index, parent);// If the child is larger than the parent, switch
index = parent;// Continue the recursive comparison}}pop_heap() { // It is used to eject the node. After eject the heap top element, the heap needs to be adjusted and the heap top value is returned.
const { container, cmp } = this;
if(! container.length){return null;
}
swap(container, 0, container.length - 1);// Swap the top element with the tail element
const res = container.pop();// Pop the tail element
const length = container.length;
let index = 0, exchange = index * 2 + 1;// Exchange is the left node subscript
while(exchange < length) {
let right = index * 2 + 2;
// In the maximum heap case, if there is a right node, and the value of the right node is greater than the value of the left node
if(right < length && cmp(container[right], container[exchange])) {
exchange = right;
}
if(! cmp(container[exchange], container[index])) {break;
}
swap(container, exchange, index);
index = exchange;
exchange = index * 2 + 1;
}
return res;
}
top() { // Output the top value of the heap
if(this.container.length) return this.container[0];
return null; }}Copy the code
Now that we have the heap implementation, let’s look at the problem:
var MedianFinder = function() {
this.maxHeap = new Heap();
this.minHeap = new Heap((x, y) = > x < y);
};
MedianFinder.prototype.addNum = function(num) {
this.maxHeap.push_heap(num);
this.minHeap.push_heap(this.maxHeap.pop_heap());
if(this.maxHeap.container.length < this.minHeap.container.length){
this.maxHeap.push_heap(this.minHeap.pop_heap()); }}; MedianFinder.prototype.findMedian =function() {
return this.maxHeap.container.length > this.minHeap.container.length ? this.maxHeap.top() : (this.maxHeap.top() + this.minHeap.top()) / 2;
};
Copy the code
- Time complexity: O(logNlogNlogN)
- Space complexity: O(NNN)
Maximum sum of contiguous subarrays
Sword finger Offer 42. Maximum sum of contiguous subarrays
Difficulty: Easy
Topic: leetcode-cn.com/problems/li…
Enter an integer array in which one or more consecutive integers form a subarray. Find the maximum sum of all subarrays.
The required time complexity is O(NNN)
Example 1:
Input: nums = [-- 2, 1, 3, 4, 1, 2, 1, 5, 4] output: 6: continuous subarray and maximum of [4, 1, 2, 1], is 6.Copy the code
Tip:
- 1 <= arr.length <= 10^5
- -100 <= arr[i] <= 100
Answer key
Method 1 dynamic programming DP
Create an array dp[I] that “records the maximum sum of contiguous subarrays with subscripts [0, I] in numS”.
Ideas:
- The initial value
dp[0] = nums[0]
- if
dp[i - 1] > 0
,dp[i] = nums[i] + dp[i - 1]
- if
dp[i - 1] <= 0
,dp[i] = nums[i]
/ * * *@param {number[]} nums
* @return {number}* /
var maxSubArray = function (nums) {
const dp = [];
dp[0] = nums[0]
let max = dp[0];
for (let i = 1; i < nums.length; i++) {
dp[i] = nums[i];
if (dp[i - 1] > 0) {
dp[i] += dp[i - 1];
}
max = max > dp[i] ? max : dp[i];
}
return max;
};
Copy the code
- Time complexity: O(NNN)
- Space complexity: O(NNN)
Method two dynamic programming space optimization
Method 1 opens up an array, and we can further optimize it to operate on the original array.
var maxSubArray = function(nums) {
let max = nums[0];
for(let i = 1; i < nums.length; i++){
if(nums[i - 1] > 0){
nums[i] += nums[i - 1];
}
max = max > nums[i] ? max : nums[i];
}
return max;
}
Copy the code
- Time complexity: O(NNN)
- Space complexity: O(111)
Method 3 uses the reduce function
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
The callback function takes four arguments:
- accumulator: The return value of the accumulator’s cumulative callback; It is the cumulative value returned when the callback was last called, or
initialValue
. - CurrentValue: The element being processed in the array.
- index(Optional) : Index of the current element being processed in the array. If provided
initialValue
, the start index is 0; otherwise, the index starts from 1. - Array (Optional) : Array to call reduce().
- initialValue(Optional) : As the first call
callback
The value of the first argument to the function. If no initial value is provided, the first element in the array is used. Calling reduce on an empty array with no initial value will report an error.
The return value is the cumulative processing result of the function.
// Borrow the idea of dynamic programming
var maxSubArray = function(nums) {
let max = -Infinity;
nums.reduce((total, cur, i) = > {
if(total > 0){
total += cur;
}else{
total = cur;
}
max = max > total ? max : total;
return total;
},0) // total starts with 0
return max;
};
Copy the code
Law 4 The law of greed
var maxSubArray = function(nums) {
let max = nums[0];
let cur = nums[0];
for(let i = 1; i < nums.length; i++){
cur = Math.max(nums[i], cur + nums[i]);
max = Math.max(max, cur);
}
return max;
}
Copy the code
- Time complexity: O(NNN)
- Space complexity: O(111)
Practice every day! The front end is a new one. I hope I can get a thumbs up