Rod-cutting problem(there is a rod of length n where n > 0, n is an integer, and we want to cut it into pieces of integer lengths such that the total price is maximized), p is the list of price, n is the length of the rod. I want to cut the rod, in order to get the maximum price, at the meantime, we also need to ensure that the length is unqiue, that is if we already cut a piece length = 3, we cannot cut another piece length = 3.
For example vector p = {1, 5, 8, 9, 10, 12, 17, 20}; Gives me max price: 21 and length are: 2,3,3. As stated, there shouldn't be double 3. So the result should be 20 and length is 8 instead of 2,3,3
How could I modify my code, and maintain the time complexity O(n^2) Thanks.
int n = 8;
vector<int> p = {1,5,8,9,10,12,17,20};
void cut_rod(vector<int>& p, int n){
int r[n+1];
int s[n+1];
r[0] = 0;
for (int j = 1; j<=n; j++){
int q = INT_MIN;
for (int i = 1; i <= j; i++){
if(q < p[i-1] + r[j-i]){
q = p[i-1] + r[j-i];
s[j] = i;
}
}
r[j] = q;
}
return r[n];
}
You could use a n + 1 by n + 1 matrix when you store the pieces for a given length. This way you can check if you have a same sized piece in constant time and copying a row costs linear time, so in total the complexity is still O(n^2), but now your space complexity is O(n^2).
I modified the code by geeksforgeeks below.
// A Dynamic Programming solution for Rod cutting problem
#include<stdio.h>
#include<limits.h>
using namespace std;
// A utility function to get the maximum of two integers
int max(int a, int b) { return (a > b)? a : b;}
/* Returns the best obtainable price for a rod of length n and
price[] as prices of different pieces */
int cutRod(int price[], int n)
{
int pieces[n+1][n+1];
int val[n+1];
val[0] = 0;
int i, j;
// Build the table val[] in bottom up manner and return the last entry
// from the table
for (i = 1; i<=n; i++)
{
int max_val = INT_MIN, ind = -1;
for (j = 1; j <= i; j++) {
if (max_val < price[j - 1] + val[i-j]) {
if (pieces[i-j][j] != 1) {
max_val = price[j - 1] + val[i-j];
ind = j;
}
}
}
val[i] = max_val;
for (int k = 0; k <= n; ++k) { // Copy the pieces
pieces[i][k] = pieces[i-ind][k];
}
pieces[i][ind] = 1; // Add the piece of length ind (which is the max j)
}
return val[n];
}
/* Driver program to test above functions */
int main()
{
int arr[] = {1,5,8,9,10,12,17,20};
int size = sizeof(arr)/sizeof(arr[0]);
printf("Maximum Obtainable Value is %dn", cutRod(arr, size));
getchar();
return 0;
}
The DP algorithm saves in the i-th position of the array val, that goes from 0 to n, the maximum price for a rod with length i. We save the cuts of a rod of length i in pieces[i] which is an array that goes from 0 to n, if we have 1 at the position j that means to get the max value val[i] you must have a piece of length j. Now, the DP algorithm for some length i makes a cut of length j and calculates the sum of the price of a price of length j and the max price of the remainder piece of length i-j which is already calculated. This sum will have a max value for some j, meaning there will be some j that price[j - 1] + val[i-j] will be max (where j isn't an already existing cut). So now for length i we have a piece of length j and the pieces for length i - j which we have saved at pieces[i - j]. Now to get pieces[i] we have to copy the pieces pieces[i - j] and add the piece of length j.
You can get the length of the pieces like that
for (int i = 0; i <= n; ++i)
if (pieces[n][i] == 1) cout << i << ' ';
Related
Given an integer n and array a. Finding maximum of (a[i]+a[j])*(j-i) with 1<=i<=n-1 and i+1<=j<=n
Example:
Input
5
1 3 2 5 4
Output
21
Explanation :With i=2 and j=5, we have the maximum of (a[i]+a[j])*(j-i) is (3+4)*(5-2)=21
Constraints:
n<=10^6
a[i]>0 with 1<=i<=n
I can solve this problem with n<=10^4, but what should I do if n is too large, like the constraints?
First, let's reference the "brute force" force algorithm. This will have some issues, that I will call out below, but it is a correct solution.
struct Result
{
size_t i;
size_t j;
int64_t value;
};
Result findBestBruteForce(const vector<int>& a)
{
size_t besti = 0;
size_t bestj = 0;
int64_t bestvalue = INT64_MIN;
for (size_t i = 0; i < a.size(); i++)
{
for (size_t j = i + 1; j < a.size(); j++)
{
// do the math in 64-bit space to avoid overflow
int64_t value = (a[i] + (int64_t)a[j]) * (j - i);
if (value > bestvalue)
{
bestvalue = value;
besti = i;
bestj = j;
}
}
}
return { besti, bestj, bestvalue };
}
The problem with the above code is that it runs at O(N²). Or more precisely, for the the N iterations of the outer for-loop (where i goes from 0 to N), there are an average of N/2 iterations on the inner for-loop. If N is small, this isn't a problem.
On my PC, with full optimizations turned on. When is N under 20000, the run time is less than a second. Once N approaches 100000, it takes several seconds to process the 5 billion iterations. Let's just go with a "billion operations per second" as an expected rate. If N were to 1000000, the maximum as the OP outlined, it would probably take 500 seconds. Such is the nature of a N-squared algorithm.
So how can we speed it up? Here's an interesting observation. Let's say our array was this:
10 5 4 15 13 100 101 6
On the first iteration of the outer loop above, where i=0, we'd be computing this on each iteration of the inner loop:
for each j: (a[0]+a[j])(j-0)
for each j: (10+a[j])(j-0)
for each j: [15*1, 14*2, 25*3, 23*4, 1000*5, 1010*6, 16*6]
= [15, 28, 75, 92, 5000, 6060, 96]
Hence, for when i=0, a[i] = 15 and the largest value computed from that set is 6060.
Since A[0] is 15, and we're tracking a current "best" value, there's no incentive to iterate all the values again for i=1 since a[1]==14 is less than 15. There's no j index that would compute a value of (a[1]+a[j])*(j-1) larger than what's already been found. Because (14+a[j])*(j-1) will always be less than (15+a[j])*(j-1). (Assumes all values in the array are non-negative).
So to generalize, the outer loop can skip over any index of i where A[best_i] > A[i]. And that's a real simple alteration to our above code:
Result findBestOptimized(const std::vector<int>& a)
{
if (a.size() < 2)
{
return {0,0,INT64_MIN};
}
size_t besti = 0;
size_t bestj = 0;
int64_t bestvalue = INT64_MIN;
int minimum = INT_MIN;
for (size_t i = 0; i < a.size(); i++)
{
if (a[i] <= minimum)
{
continue;
}
for (size_t j = i + 1; j < a.size(); j++)
{
int64_t value = (a[i] + (int64_t)a[j]) * (j - i);
if (value > bestvalue)
{
bestvalue = value;
besti = i;
bestj = j;
minimum = a[i];
}
}
}
return { besti, bestj, bestvalue };
}
Above, we introduce a minimum value for A[i] to be before considering doing the full inner loop enumeration.
I benchmarked this with build optimizations on. On a random array of a million items, it runs in under a second.
But wait... there's another optimization!
If the inner loop fails to find an index j such that value > bestvalue, then we already know that the current A[i] is greater than minimum. Hence, we can increment minimum to A[i] regardless at the end of the inner loop.
Now, I'll present the final solution:
Result findBestOptimizedEvenMore(const std::vector<int>& a)
{
if (a.size() < 2)
{
return { 0,0,INT64_MIN };
}
size_t besti = 0;
size_t bestj = 0;
int64_t bestvalue = INT64_MIN;
int minimum = INT_MIN;
for (size_t i = 0; i < a.size(); i++)
{
if (a[i] <= minimum)
{
continue;
}
for (size_t j = i + 1; j < a.size(); j++)
{
int64_t value = (a[i] + (int64_t)a[j]) * (j - i);
if (value > bestvalue)
{
bestvalue = value;
besti = i;
bestj = j;
}
}
minimum = a[i]; // since we know a[i] > minimum, we can do this
}
return { besti, bestj, bestvalue };
}
I benchmarked the above solution on different array sizes from N=100 to N=1000000. It does all iterations in under 25 milliseconds.
In the above solution, there's likely a worst case runtime of O(N²) again when all the items in the array are in ascending order. But I believe the average case should be on the order of O(N lg N) or better. I'll do some more analysis later if anyone is interested.
Note: Some notation for variables and the Result class in the code have been copied from #selbie's excellent answer.
Here's another O(n^2) worst-case solution with (likely provable) O(n) expected performance on random permutations and room for optimization.
Suppose [i, j] are our array bounds for an optimal pair. By the problem definition, this means all elements left of i must be strictly less than A[i], and all elements right of j must be strictly less than A[j].
This means we can compute the left-maxima of A: all elements strictly greater than all previous elements, as well as the right-maxima of A. Then, we only need to consider left endpoints from the left-maxima and right endpoints from the right-maxima.
I don't know the expectation of the product of the sizes of left and right maxima sets, but we can get an upper bound. The size of left maxima is at most the size of the longest increasing subsequence (LIS) of A. The right maxima are at most the size of the longest decreasing subsequence. These aren't independent, but I'm taking as an (unproven) assumption that the LIS and LDS lengths are inversely correlated with each other for random permutations. The right-maxima must start after the left-maxima end, so this seems like a safe assumption.
The length of the LIS for random permutations follows the Tracy-Widom distribution, so it has mean sqrt(2N) and standard deviation N^(-1/6). The expected square of the size is therefore 2N + 1/(N^1/3) so ~2N. This isn't exactly the proof we wanted, since you'd need to sum over the partial density function to be rigorous, but the LIS is already an upper bound on the left-maxima size, so I think the conclusion is still true.
C++ code (Result class and some variable names taken from selbie's post, as mentioned):
struct Result
{
size_t i;
size_t j;
int64_t value;
};
Result find_best_sum_size_product(const std::vector<int>& nums)
{
/* Given: list of positive integers nums
Returns: Tuple with (best_i, best_j, best_product)
where best_i and best_j maximize the product
(nums[i]+nums[j])*(j-i) over 0 <= i < j < n
Runtime: O(n^2) worst case,
O(n) average on random permutations.
*/
int n = nums.size();
if (n < 2)
{
return {0,0,INT64_MIN};
}
std::vector<int> left_maxima_indices;
left_maxima_indices.push_back(0);
for (int i = 1; i < n; i++){
if (nums.at(i) > nums.at(left_maxima_indices.back())) {
left_maxima_indices.push_back(i);
}
}
std::vector<int> right_maxima_indices;
right_maxima_indices.push_back(n-1);
for (int i = n-1; i >= 0; i--){
if (nums.at(i) > nums.at(right_maxima_indices.back())) {
right_maxima_indices.push_back(i);
}
}
size_t best_i = 0;
size_t best_j = 0;
int64_t best_product = INT64_MIN;
int i = 0;
int j = 0;
for (size_t left_idx = 0;
left_idx < left_maxima_indices.size();
left_idx++)
{
i = left_maxima_indices.at(left_idx);
for (size_t right_idx = 0;
right_idx < right_maxima_indices.size();
right_idx++)
{
j = right_maxima_indices.at(right_idx);
if (i == j) continue;
int64_t value = (nums.at(i) + (int64_t)nums.at(j)) * (j - i);
if (value > best_product)
{
best_product = value;
best_i = i;
best_j = j;
}
}
}
return { best_i, best_j, best_product };
}
I started from the two excellent answers by #selbie and #kcsquared.
Their solutions gave impressive results for random inputs. What was not clear is the worst case behavior.
What sequence would correspsond to the worst case?
I finally found a critial sequence for these two answers, a triangle sequence: this sequence slightly increases up to a max, and then slightly decrease. With such a sequence and n=10^5 for example, these answers take more than 10s.
My solutions starts from #selbie solution and add two improvements:
I add #kcsquared's trick: on the right (of j), they can be only lower elements
When considering a new left element a[i], it is useless to start from i + 1 to get the second element. We can start from the current best_j
With these tricks, I was able to improve the two posted answer performances a little bit. However, it still
fails to solve the triangle sequence issue: about 10s for n = 10^5.
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <chrono>
struct Result {
size_t i;
size_t j;
int64_t value;
};
void print (const Result& res, const std::string& prefix = "") {
std::cout << prefix;
std::cout << "(" << res.i << ", " << res.j << ") -> " << res.value << std::endl;
}
Result findBest(const std::vector<int>& a) {
if (a.size() < 2) {
return { 0, 0, INT64_MIN };
}
int n = a.size();
std::vector<int> next_max(n, -1);
int current_max = n-1;
for (int i = n-1; i >= 0; --i) {
if (a[i] > a[current_max]) {
current_max = i;
}
next_max[i] = current_max;
}
size_t besti = 0;
size_t bestj = 0;
int64_t bestvalue = INT64_MIN;
int minimum = INT_MIN;
for (size_t i = 0; i < a.size(); i++) {
if (a[i] <= minimum) {
continue;
}
minimum = a[i];
size_t jmin = (bestj > i) ? bestj : i+1;
for (size_t j = jmin; j < a.size(); j++) {
j = next_max[j];
value = (a[i] + (int64_t)a[j]) * (j - i);
if (value > bestvalue) {
bestvalue = value;
besti = i;
bestj = j;
}
}
}
return { besti, bestj, bestvalue };
}
int main() {
int n = 1000000;
int vmax = 100000000;
std::vector<int> A (n);
std::srand(std::time(0));
for (int i = 0; i < n; ++i) {
A[i] = rand() % vmax + 1;
}
std::cout << "n = " << n << std::endl;
auto t0 = std::chrono::high_resolution_clock::now();
auto res = findBest (A);
auto t1 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count();
print (res, "Random: ");
std::cout << "time = " << duration/1000 << " ms" << std::endl;
int i_max = n/2;
for (int i = 0; i < i_max; ++i) A[i] = i+1;
A[i_max] = 10 * i_max;
for (int i = i_max+1; i < n; ++i) {
A[i] = 2*i_max - i;
}
t0 = std::chrono::high_resolution_clock::now();
res = findBest (A);
t1 = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count();
print (res, "Triangle sequence: ");
std::cout << "time = " << duration/1000 << " ms" << std::endl;
return 0;
}
Good morning, I have problems to solve:
You have a vector of size n, you want to find a sub-vector of size m and that the sum of its elements is minimal
An example of how this works is:
see example of operation
where the minimum sub-vector is: {1,3,1} with sum 5
I need to analyze this problem both by brute force (sliding windows explained below), and by the technique of divide and conquer. Then I will write a comparative report and explain that with sliding windows it works much better. This paper is for a university project on algorithm comparison. But I need to build it explicitly with D&C.
I have it done as follows, but I have problems with base cases and returning the minimum sum sub-vector.
// Function to find the minimum between two numbers
int min(int a, int b) { return (a < b)? a : b; }
// Function to find the minimum between three numbers
int min(int a, int b, int c) { return min(min(a, b), c); }
// Function to find the minimum sum that passes through the center of the vector
int minSumCenter(int v[], int l, int center, int h)
{
// Elements to the left of the center
int sum = 0;
int left_sum = INT_MAX;
for (int i = center; i >= l; i--)
{
sum = sum + v[i];
if (sum < left_sum)
left_sum = sum;
}
// Elements to the right of centre
sum = 0;
int right_sum = INT_MAX;
for (int i = center+1; i <= h; i++)
{
sum = sum + v[i];
if (sum < right_sum)
right_sum = sum;
}
// Return de los elementos que están tanto a la izquierda como a la derecha
return left_sum + right_sum;
}
// Minimum sum sub-vector size m, size v is h-l
int subvectorMinDyV(int v[], int l, int h, int m){
// Base Case 1
if ((h-l) <= m) {
int sum = 0;
for(int i=0; i<m; i++)
sum += v[i];
return sum;
// Base Case 2
}else if(m*2-1 <= (h-l)){
int sum=0;
int sumMin = INT_MAX;
for(int i=0; i<(l+h)-m;i++){
sum=0;
for(int j=i; j<m; j++)
sum += v[j];
if(sum < sumMin)
sumMin = sum;
}
return sumMin;
}
int center = (l + h)/2;
/* Possible cases
a) minimum sum sub-vector is on the left
b) minimum sum sub-vector is on the right
c) minimum sum sub-vector is a in the middle */
return min(subvectorMinDyV(v, l, center, m),
subvectorMinDyV(v, center+1, h, m),
minSumCenter(v, l, center, h));
}
int main(){
int v[] = {6,10,4,2,14,1};
int n = sizeof(v)/sizeof(v[0]);
int sumMin = subvectorMinDyV(v, 0, n-1, 3);
cout << "The minimum amount with DyV is: " << sumMin << endl;
return 0;
}
Thank you very much.
I'm not sure what you mean by divide-and-conquer exactly. The sliding window approach, as pointed out by others, is O(n). (You can't do any better, since you need to look at every element at least once.)
The solution you have is close, except that you are recomputing the sums needlessly. This should do the job
void subvectorMin(int* v, int n, int m)
{
if (n < m)
{
std::cout << "Cannot calculate sub-vector m. (m<n)";
return; // return early
}
// compute the sum of first m elements
int sum = 0;
for(int i = 0; i < m; ++i)
sum += v[i];
// assume answer is at position 0
int pos = 0;
int min_sum = sum;
// check if there is a minimum sum somewhere else
for(int i = m; i < n; ++i)
{
sum = sum + v[i] - v[i - m]; // THIS is the sliding window that
// avoids the sum being recomputed
// if smaller sum is found, update the position
if(sum < min_sum)
{
min_sum = sum;
pos = i - m + 1;
}
}
std::cout << "The minimum component sum is: " << min_sum
<< " , subvector: {";
for(int i = pos; i < pos + m; ++i)
std::cout << " " << v[i];
std::cout << " }" <<std::endl;
}
If you observe your example then u will find out that how the array is partitioned.
for n = 6, m = 3
v = 6|10|4|2|14|1
---------------
p = 0|1 |2|3|4 |5
g1: 0 1 2
g2: 1 2 3 (1 2 sum already calculated)
g3: 2 3 4 (2 3 sum already calculated)
g4: 3 4 5 (3 4 sum already calculated)
When you go from left to right after collecting m element u need to do subtract c-mth position element. wherec` is current position
void subvectorMin(int* v, int n, int m, int p, int sum){
if (p >= n) {
return sum;
}
int tmp = sum - v[p-m]+ v[p];
return Min(sum, Min(tmp, subvector(v, n, m, p+1, tmp)));
}
main() {
for (i = 0; i < m; i++)
sum += v[i];
subvectorMin(v, n, m, m,sum);
I have implemented an algorithm that solves the problem of finding the kth smallest element in an unsorted array. I have used the heap structure, and optimized the code by relying on this formula,
k1 = n - k + 1
k1 being the k1th largest element, so I go for the smaller of k and k1.
Still, I couldn't pass the time limit error on an online judge. I don't know if there will be any further more better complexity having in mind that I have to create an array no more than the size of k; maybe less than k possible? Or there is another way to solve this problem other than using the heap structure.
1 <= k <= n <= 105
The code:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
void minHeapify(int arr[], int n, int i)
{
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
if (l < n && arr[l] < arr[largest])
largest = l;
if (r < n && arr[r] < arr[largest])
largest = r;
if (largest != i) {
swap(arr[i], arr[largest]);
minHeapify(arr, n, largest);
}
}
void maxHeapify(int arr[], int n, int i)
{
int smallest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
if (l < n && arr[l] > arr[smallest])
smallest = l;
if (r < n && arr[r] > arr[smallest])
smallest = r;
if (smallest != i) {
swap(arr[i], arr[smallest]);
maxHeapify(arr, n, smallest);
}
}
void buildMinHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
minHeapify(a, n, i);
}
void buildMaxHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
maxHeapify(a, n, i);
}
int kthsmallest(int minHeap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> minHeap[i];
buildMaxHeap(minHeap, k);
for (i = k; i < n; i++)
{
cin >> temp;
if (temp < minHeap[0])
{
minHeap[0] = temp;
maxHeapify(minHeap, k, 0);
}
}
return minHeap[0];
}
int kthlargest(int minHeap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> minHeap[i];
buildMinHeap(minHeap, k);
for (i = k; i < n; i++)
{
cin >> temp;
if (temp > minHeap[0])
{
minHeap[0] = temp;
minHeapify(minHeap, k, 0);
}
}
return minHeap[0];
}
int main() {//kth smallest element
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, k, k1;
cin >> n >> k;
k1 = n - k + 1;//kth smallest element is the same as k1th largest element
if (k < k1) {
int *minHeap = new int[k];
cout << kthsmallest(minHeap, k, n);
}
else {
int *minHeap = new int[k1];
cout << kthlargest(minHeap, k1, n);
}
return 0;
}
Please if you could help finding a better time complexity?
Problem:
Find the kth largest element of an array
Memory limit: 256 MBs
Time limit: 1 s
Input: input.txt
Output: output.txt
Task:
You are given an array of n integers and a natural k.
You have to find the kth largest element of the array.
You can't create array consisting of more than k elements.
Input:
The first line contains a natural n (1 ≤ n≤105) – the
quantity of elements of the array, and the natural k.
The second line contains n numbers – the elements of the array.
Output:
The kth largest element of the array.
Example:
Input | Output
-------------+-----------
6 2 | 7
7 4 6 3 9 1 |
The time complexity is optimal, but you can make your code a tiny bit more efficient:
Don't use recursion, but an iterative solution
Don't use swap, but keep the original value in memory while copying child values to their parents and only store the initial value once you have reached the appropriate slot.
Don't perform twice 2 * i: the other child node is just the next one.
Let the heapify functions take an extra argument, which can be either the current value at index i, or the replacement value for it. This saves one assignment.
Here is how that would look for two heapify functions:
void minHeapify(int arr[], int n, int i, int key) { // add key as parameter
while (true) { // iterative
int child = 2 * i + 1; // do this only for left child, and limit number of variables
if (child+1 < n && arr[child] > arr[child+1]) // get child with least value
child++; // the right child is just one index further
if (child >= n || key <= arr[child]) break;
arr[i] = arr[child]; // don't swap, just copy child value to parent
i = child; // move down
}
arr[i] = key; // finally put the original value in the correct place
}
void maxHeapify(int arr[], int n, int i, int key) { // add key as parameter
while (true) { // iterative
int child = 2 * i + 1; // do this only for left child, and limit number of variables
if (child+1 < n && arr[child] < arr[child+1]) // get child with greatest value
child++; // the right child is just one index further
if (child >= n || key >= arr[child]) break;
arr[i] = arr[child]; // don't swap, just copy child value to parent
i = child; // move down
}
arr[i] = key; // finally put the original value in the correct place
}
void buildMinHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
minHeapify(a, n, i, a[i]); // pass a[i] also
}
void buildMaxHeap(int a[], int n) {
for (int i = n / 2; i >= 0; i--)
maxHeapify(a, n, i, a[i]); // pass a[i] also
}
int kthsmallest(int heap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> heap[i];
buildMaxHeap(heap, k);
for (i = k; i < n; i++) {
cin >> temp;
if (temp < heap[0])
maxHeapify(heap, k, 0, temp); // pass temp
}
return heap[0];
}
int kthlargest(int heap[], int k, int n) {
int i, temp;
for (i = 0; i < k; i++)
cin >> heap[i];
buildMinHeap(heap, k);
for (i = k; i < n; i++) {
cin >> temp;
if (temp > heap[0])
minHeapify(heap, k, 0, temp); // pass temp
}
return heap[0];
}
In main function you could make a special case for when k == 1 or k == n, so no heap is needed, just min() or max().
One strange thing is that the challenge you link to speaks of "kth largest" while you speak of "kth smallest". Maybe you mixed up.
So here is the code when the job is to return the kth smallest. But please check the challenge whether you should not have done it for kth largest:
int main() {//kth smallest element
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, k, k1;
cin >> n >> k;
k1 = n - k + 1;//kth smallest element is the same as k1th largest element
if (k == 1) {
int curr, next;
cin >> curr;
for (int i = 1; i < n; i++) {
cin >> next;
curr = min(curr, next);
}
cout << curr;
} else if (k1 == 1) {
int curr, next;
cin >> curr;
for (int i = 1; i < n; i++) {
cin >> next;
curr = max(curr, next);
}
cout << curr;
} else if (k < k1) {
int *heap = new int[k];
cout << kthsmallest(heap, k, n);
} else {
int *heap = new int[k1];
cout << kthlargest(heap, k1, n);
}
return 0;
}
You're making the assumption that using a smaller heap is always the best choice. You might want to re-think that.
For example, imagine you want to select the 96th smallest number from a list of 100. If you use a heap of size 96, then you'll do:
Build a heap with 96 items. buildHeap is O(n), and in this case n is 96.
Do up to 4 insertions into a heap of 96 items. That'll be 4*log(96).
If you use a heap of size 4, then you'll do:
Build a heap with 4 items.
Do up to 96 insertions into a heap of 4 items. That'll be 96*log(4).
The first option is 96 + 4*log(96). The base-2 log of 96 is about 6.58. So the insertions will cost 26.32, for a total of 122.32.
The second option, with the smaller heap, is 4 + 96*log(4). log(4) is 2, so you end up with 4 + 196, or a total of 196.
The smaller heap is a big loser here.
In general, you want to use the larger heap when (k + (n-k)*log(k)) < ((n-k) + k*log(n-k)).
Also:
The real-world running time of the heap selection algorithm is kind of sensitive to the order in which items are presented. For example, if you're looking for 1000th smallest number in an array of 100,000, it's going to run much faster if the array is in ascending order than if it's in descending order. The reason?
Because in the ascending case, you build your initial heap with the first 1,000 items and then you never have to modify the heap again because there is none of the following items are smaller than the largest item on the heap.
But if the array is in descending order, then every item you look at will be smaller than the largest item on the heap, which means you'd be doing a heap insertion for all 99,000 remaining items.
Imagine how your code would perform if one of the test cases is a large array in descending order.
Unless you've already proven that your way of selecting which heap size to use is clearly better, you might want to consider just going with "select kth smallest," using a maxheap of size k, regardless.
I know that there are many implementations of merge sort but this is one which I have read in the book "Introduction to algorithms". The following code is an implementation of merge sort which is not working correctly:
#include <iostream>
using namespace std;
void merge(int*a, int p, int q, int r) { //function to merge two arrays
int n1 = (q - p); // size of first sub array
int n2 = (r - q); // size of second subarray
int c[n1], d[n2];
for (int i = 0; i <= n1; i++) {
c[i] = a[p + i];
}
for (int j = 0; j <= n2; j++) {
d[j] = a[q + j];
}
int i = 0, j = 0;
for (int k = p; k < r; k++) { // merging two arrays in ascending order
if (c[i] <= d[j]) {
a[k++] = c[i++];
} else {
a[k++] = d[j++];
}
}
}
void merge_sort(int*a, int s, int e) {
if (s < e) {
int mid = (s + e) / 2;
merge_sort(a, s, mid);
merge_sort(a, mid + 1, e);
merge(a, s, mid, e);
}
}
int main() {
int a[7] { 10, 2, 6, 8, 9, 10, 15 };
merge_sort(a, 0, 6);
for (auto i : a)
cout << i << endl;
}
This code is not working correctly. What's wrong in this code? How can it be fixed?
First of all you should be correctly set for the size of the array.
void merge(int*a, int p, int q, int r) { //function to merge two arrays
/* If i am not wrong , p is the starting index of the first sub array
q is the ending index of it also q+1 is the starting index of second
sub array and r is the end of it */
/* size of the sub array would be (q-p+1) think about it*/
int n1 = (q - p); // size of first sub array
/* This is right n2 = (r-(q+1)+1)*/
int n2 = (r - q); // size of second subarray
int c[n1], d[n2];
for (int i = 0; i < n1; i++) {
c[i] = a[p + i];
}
for (int j = 0; j < n2; j++) {
d[j] = a[q + 1 + j];
}
.
.
.
}
Now , after this you have copies the both arrays in locally defined arrays. Until this, it is correct .
Now the main part is merging of the two arrays which you are doing in the for loop. You are just comparing the ith element of first sub array with jth element of the second, but what you are missing here is that there may be a time when you have updated all the values of the first( or second) sub array in the main array but still some elements are remaining int the second ( first) one.
For example, take these two subarrays
sub1={2,3,4,5};
sub2={7,8,9,10};
in this case you should break from the loop as soon as you have traversed either of the array completely and copy the rest of the elements of the other array in the same order.
Also in the for loop you increasing k two times in a loop , one in the for statement and another while updating a value, Check that too.
Hope this may solve the problem.
There are couple of things gone wrong in the implementation of your logic. I have indicated them clearly below:
void merge(int*a,int p,int q,int r){ //function to merge two arrays
int n1= (q-p); // size of first sub array
int n2= (r-q); // size of second subarray
int c[n1+1],d[n2]; //you need to add 1 otherwise you will lose out elements
for(int i=0;i<=n1;i++){
c[i]=a[p+i];
}
for(int j=0;j<n2;j++){
d[j]=a[q+j+1];//This is to ensure that the second array starts after the mid element
}
int i=0,j=0;
int k;
for( k=p;k<=r;k++){ // merging two arrays in ascending order
if( i<=n1 && j<n2 ){//you need to check the bounds else may get unexpected results
if( c[i] <= d[j] )
a[k] = c[i++];
else
a[k] = d[j++];
}else if( i<=n1 ){
a[k] = c[i++];
}else{
a[k] = d[j++];
}
}
}
I have an unsorted array. I have numerous queries in which I give a range (expressed as two array indexes) and then the maximum value from that range (that is, from the specified slice of the array) has to be returned.
For example:
array[]={23,17,9,45,78,2,4,6,90,1};
query(both inclusive): 2 6
answer: 78
Which algorithm or data structure do I construct to quickly retrieve maximum value from any range. (There are a lot of queries)
EDIT:
I am using C++
I think that some preprocessing is allowed. It is Range Minimum Query problem (maximum here).
Good review of this problem at TopCoder.
Suitable data structures: Segment tree and Sqrt-decomposition:
#include <cstdio>
#include <iostream>
#include <algorithm>
#define N int(3e4)
using namespace std;
int act[N], len, sz, res[N];
int answer(int l, int r) {
int ret = -1, i;
for (i = l; i % sz && i <= r; i++)
ret = max(ret, act[i]);
for (; i + sz <= r + 1; i += sz)
ret = max(ret, res[i / sz]);
for (; i <= r; i++)
ret = max(ret, act[i]);
return ret;
}
int main() {
int i, m;
cin >> m;
for (i = 0; ; i++) {
cin >> act[i];
if (act[i] == -1)
break;
}
len = i;
for (sz = 1; sz * sz < len; sz++);
for (int j = i + 1; j < sz * sz; j++)
act[j] = -1;
for (int i = 0; i < sz * sz; i++)
res[i / sz] = max(res[i / sz], act[i]);
for (int i = 0; i + m <= len; i++)
cout << answer(i, i + m - 1) << endl;
return 0;
}
mergesort n get the last index value of range as will me max.
array[]={23,17,9,45,78,2,4,6,90,1};
query(both inclusive): 2 6
mergesort return 6th index var (index = 1 .. n)
answer: 78
Let say this is your array array[]={23,17,9,45,78,2,4,6,90,1};
If your array is not that big, I would offer you preprocess the array and get another array like that:
{0,0} = 23; //between arr[0] and arr[0]
{0,1} = 23;
{0,2} = 23;
{0,3} = 45;
{9,9} = 1;
So your new array is going to be newArr = {23,23,23,45,....., 1}
You can find search in O(1), for example, max between 4-5 is newArr[4*array.length+5)-1];
In total, for n queries you will have O(n).
The space is if you have 10000(10^4) integer, then your newArr = 10^8 * 4B = 400MB, so if you have more than 10000 int, then this wouldnt work
EDIT: I thought of something but it is same as algorithm in Topcoder that MBo mentions.