iterative algorithm for combination generation [duplicate] - algorithm

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Algorithm to return all combinations of k elements from n
Is there any iterative algorithm to generate combinations of N numbers taking 'r' at a time ?

Yes there is.
Here is code from the wrong answer Library.
void generate_combos(int n, int k) {
int com[100];
for (int i = 0; i < k; i++) com[i] = i;
while (com[k - 1] < n) {
for (int i = 0; i < k; i++)
cout << com[i] << " ";
cout << endl;
int t = k - 1;
while (t != 0 && com[t] == n - k + t) t--;
com[t]++;
for (int i = t + 1; i < k; i++) com[i] = com[i - 1] + 1;
}
}
This generates the combinations in lexicographic order.

Related

find all common part between vector

I have n vectors with unique integers. I want to find all the common part between them. Is there any specific algorithm or data struct for this problem?
example:
std::vector<int> a = {0,1,2,3,4,5,6,7,8,9,10,11,12,13};
std::vector<int> b = {1,7,8,9,2,10,11,12};
std::vector<int> c = {4,9,8,7,0,1,2,3};
result:
ignore result with only one interge
7,8,9 between a and b
10,11,12 bewteen a and b
0,1,2,3 between a and c
if you want all common subarrays with a length greater than 1, then for each element from the first array iterate over all elements in the second array if you match two elements then go to the next element in the first and second array, and so on.
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (arr1[i] == arr2[j]) {
int ii = i, jj = j, cnt = 0;
std::vector<int> res;
res.push_back(arr1[ii]);
while (++ii < n and ++jj < m and arr1[ii] == arr2[jj])res.push_back(arr1[ii]);
if (res.size() > 1) {
for (auto x: res)std::cout << x << " ";
}
}
}
}
time complexity:O(n^3)
and this another way by LCS.
memset(dp, 0, sizeof dp);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = 0;
if (arr1[i] == arr2[j]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
std::cout << dp[i][j] << " ";
}
std::cout << "\n";
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (dp[i][j] > 1) {
for (int ii = i, jj = j, k = dp[i][j]; k; ii--, jj--, k--) {
std::cout << arr1[ii] << " ";
}
std::cout << "\n";
}
}
}
O(n^3)
It seems to me that you are looking for Longest Common Subsequence
These images are calculated by a diff like program which compares lines (unordered), like shortest edit distance
Blue lines : Deleted lines to come from left to right
Red lines : Changed lines
Green lines: Inserted lines
Lines without color are unchanged = longest common subsequence. Diff result looks pretty much the same as the given results.
Reference:
A Fast Algorithm for computing longest common subsequences
by James W. Hunt and Thomas G. Szymanski
from Communications of the ACM May 1977 Volume 20 no. 5

Largest sum of all increasing subsequences of length k

I am currently stuck with the classic longest increasing subsequence problem, but there is a slight twist to it. Instead of just finding the longest increasing subsequence, I need to find the largest sum of all increasing subsequences that are of length k.
I have the following pseudo code implemented:
input = [4,13,5,14] k = 2
n = size of input
opt = array of size n which stores the highest increasing subsequence sum up to this index
counts = array of size n which stores the amount of values in the subsequence up to this index
highestSum = -1
FOR i in range(0, n)
high = new data object(value = 0, sum = 0, count = 0)
FOR j in range(i-1, 0, -1)
IF high.sum < opt[j] AND opt[j] < opt[i] AND counts[j] < k
high.value = input[j]
high.sum = opt[j]
high.count = counts[j]
opt[i] = high.sum + input[i]
counts[i] = high.count + 1
IF counts[i] == k
highestSum = higher value between (highestSum, opt[i])
return highestSum
This dynamic programming approach works in most cases, but for the list I outlined above it does not return the optimal subsequence sum. The optimal subsequence sum with length 2 should be 27 (13-14), but 18 is returned (4-14). This is due to the opt and counts array looking like this:
k = 2
input: 0 4 13 5 14
opt: 0 4 17 9 18
counts: 0 1 2 2 2
Due to 13 already having a subsequence of 4-13, and thus its count value (2) is no longer less than k, 14 is unable to accept 13 as a correct subsequence due to its count value.
Are there any suggestions as to what I can change?
You'll need k+1 sorted data structures, one for each possible length of subsequence currently found.
Each structure contains, by the last entry in an optimal subsequence, the current sum. That is, we only care about a subsequence that can lead to the best possible solution. (Technical note. Of those that can lead to the best solution, pick the one whose positions are lexicographically first.) Which will be sorted by increasing last entry, and decreasing sum.
In pseudocode it works like this.
initialize optimal[0..k]
optimal[0][min(sequence) - 1] = 0 # empty set.
for entry in sequence:
for i in k..1:
entry_prev = biggest < entry in optimal[i-1]
if entry_prev is not None:
this_sum = optimal[i-1][entry_prev] + entry
entry_smaller = biggest <= entry in optimal[i-1]
if entry_smaller is None or optimal[i][entry_smaller] < this_sum:
delete (e, v) from optimal[i] where entry <= e and ​v <= this_sum
​ insert (entry, this_sum) into optimal[i]
return optimal[k][largest entry in optimal[k]]
But you need this kind of 2-d structure to keep track of what might happen from here.
The total memory needed is O(k n) and running time will be O(k n log(n)).
It is possible to also reconstruct the optimal subsequence, but that requires a more complex data structure.
Here is a working solution in C++ that runs in O(logn * n * k) time with O(n*k) space. I think you can not make it faster but let me know if you find a faster solution. This is a modification of the solution for from https://stackoverflow.com/questions/16402854/number-of-increasing-subsequences-of-length-k. The key difference here is that we keep track of the maximum sum for each subsequences of different legths instead of accumulating the number of subsequences and we are iterating from the back of the array (since for increasing subsequences that have length larger than k the best k-length subarray will be at the end).
An other trick is that we use the array sums to map index + length combinations to maximum sums.
maxSumIncreasingKLenSeqDP function is the simple dynamic programming solution with O(n * n * k) time complexity.
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <limits.h>
using namespace std;
#include <random>
int maxSumIncreasingKLenSeq(int arr[], size_t n, int k){
// inverse compression: assign N-1, N-2, ... , 1 to smallest, ..., largest
size_t N = 1;
size_t compArr[n];
{
for(size_t i = 0; i<n; ++i)
compArr[i] = arr[i];
// descending order
sort(compArr, compArr + n, greater<int>());
unordered_map<int, size_t> compMap;
for(int val : compArr){
if(compMap.find(val) == compMap.end()){
compMap[val] = N;
++N;
}
}
for(size_t i = 0; i<n; ++i)
compArr[i] = compMap[arr[i]];
}
int sums[n * (k - 1) + n]; // key is combined from index and length by n * (length - 1) + index
for(size_t i = 0; i < n * (k - 1) + n; ++i)
sums[i] = -1;
for(size_t i = 0; i < n; ++i)
sums[i] = arr[i]; // i, 1
int BIT[N];
for(size_t len = 2; len <= k; ++len){
for(size_t i = 0; i<N; ++i)
BIT[i] = INT_MIN;
for(size_t i = 0; i < len - 1; ++i)
sums[n * (len - 1) + i] = INT_MIN;
for(int i = n - len; i >= 0; --i){
int val = sums[n * (len - 2) + i + 1]; // i + 1, len - 1
int idx = compArr[i + 1];
while(idx <= N){
BIT[idx] = max(val, BIT[idx]);
idx += (idx & (-idx));
}
// it does this:
//BIT[compArr[i + 1]] = sums[n * (len - 2) + i + 1];
idx = compArr[i] - 1;
int maxSum = INT_MIN;
while(idx > 0){
maxSum = max(BIT[idx], maxSum);
idx -= (idx & (-idx));
}
sums[n * (len - 1) + i] = maxSum;
// it does this:
//for(int j = 0; j < compArr[i]; ++j)
// sums[n * (len - 1) + i] = max(sums[n * (len - 1) + i], BIT[j]);
if(sums[n * (len - 1) + i] > INT_MIN)
sums[n * (len - 1) + i] += arr[i];
}
}
int maxSum = INT_MIN;
for(int i = n - k; i >= 0; --i)
maxSum = max(maxSum, sums[n * (k - 1) + i]); // i, k
return maxSum;
}
int maxSumIncreasingKLenSeqDP(int arr[], int n, int k){
int sums[n * (k - 1) + n]; // key is combined from index and length by n * (length - 1) + index
for(size_t i = 0; i < n; ++i)
sums[i] = arr[i]; // i, 1
for(int i = 2; i <= k; ++i)
sums[n * (i - 1) + n - 1] = INT_MIN; // n - 1, i
// moving backward since for increasing subsequences it will be the last k items
for(int i = n - 2; i >= 0; --i){
for(size_t len = 2; len <= k; ++len){
int idx = n * (len - 1) + i; // i, length
sums[idx] = INT_MIN;
for(int j = n - 1; j > i; --j){
if(arr[i] < arr[j])
sums[idx] = max(sums[idx], sums[n * (len - 2) + j]); // j, length - 1
}
if(sums[idx] > INT_MIN)
sums[idx] += arr[i];
}
}
int maxSum = INT_MIN;
for(int i = n - k; i >= 0; --i)
maxSum = max(maxSum, sums[n * (k - 1) + i]); // i, k
return maxSum;
}
int main(){
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(1,10);
for(int len = 3; len < 10; ++len){
for(int i = 0; i < 10000; ++i){
int arr[100];
for(int n = 0; n < 100; ++n)
arr[n] = dist(rng);
int res = maxSumIncreasingKLenSeqDP(arr, 100, len);
int fastRes = maxSumIncreasingKLenSeq(arr, 100, len);
if(res != fastRes)
cout << "failed" << endl;
else
cout << "passed" << endl;
}
}
return 0;
}

Will this Selection Sort Code work in O(n) for best case?

I search everywhere on the internet for the best case time complexity of selection sort that is o(n^2). But i write and tested this below code of selection sort that can work in O(n) for best case (that is array is already sorted). Please find the mistake in this program
This is my code:
#include <bits/stdc++.h>
using namespace std;
/* Function to print an array */
void printArray(int arr[], int size)
{
int i;
for (i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}
void swap(int *xp, int *yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
void selectionSort(int arr[], int n)
{
int i, j, max_idx;
// One by one move boundary of unsorted subarray
for (i = 0; i < n - 1; i++)
{
cout << endl;
printArray(arr, n);
// Find the minimum element in unsorted array
max_idx = 0;
int count = 0;
for (j = 1; j < n - i; j++)
{
if (arr[j] >= arr[max_idx])
{
max_idx = j;
count++;
}
}
if (count != n - i - 1)
{ //swap only if not already sorted
// Swap the found minimum element with the first element
swap(&arr[max_idx], &arr[n - i - 1]);
}
else //already Sorted so returning
{
return;
}
//cout << "Sorted array: \n";
printArray(arr, n);
}
}
// Driver program to test above functions
int main()
{
int arr[] = {2, 1, 4, 3, 6, 5, 8, 7};
int n = sizeof(arr) / sizeof(arr[0]);
selectionSort(arr, n);
cout << "Sorted array: \n";
printArray(arr, n);
return 0;
}
// This is code is contributed by www.bhattiacademy.com
Yes, your algorithm has a best case running time of Θ(n), because if the array is already in ascending order then count will equal n - 1 on the first iteration of the outer loop, so the algorithm will terminate early.
Your algorithm is different to the standard selection sort algorithm, which looks like this:
for(int i = 0; i < n - 1; i++) {
int min_idx = i;
for(int j = i + 1; j < n; j++) {
if(arr[j] < arr[min_idx]) {
min_idx = j;
}
}
swap(&arr[i], &arr[min_idx]);
}
The selection sort algorithm iteratively searches for the minimum remaining element and swaps it into place. This doesn't create an opportunity to detect that the array is already in increasing order, so there's no opportunity to terminate early, and selection sort's best case running time is therefore Θ(n2).
Selection Sort: Idea Given an array of n items
1.Find the largest item x, in the range of [0…n−1]
2.Swap x with the (n−1)th item
3.Reduce n by 1 and go to Step 1
Selection sort function you can use following algorithm has hint to write the code:

Go through all the major diagonals in matrix, including principal

How do I go through all the diagonals in the matrix? There were similar questions, like this one, but they just calculate the sum. I need to perform certain operations going through all the diagonals, not just summing. To be clear, I need to traverse through it in way like in the picture:
I've came up with this solution, but it is awful:
for(int j = 0; j < m; j++) {
for(int i = 0; i < n && i + j < m; i++) {
cout << matrix[i][i + j] << " ";
}
cout << endl;
}
for(int i = 1; i < n; i++) {
for(int j = 0; j < m && i + j < n; j++) {
cout << matrix[j + i][j] << " ";
}
cout << endl;
}
For the matrix n*m I first go through every diagonal right from the main one, and then left from the main one, but this solution seems ugly to me.
You can use a simpler iteration at the cost of a modulo operation:
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << a[(i+j)%n][j] << " ";
}
cout << endl;
}
You need a first loop to find the starting point of each diagonal, and a second loop to follow the diagonal.
Here is a pseudo-code, assuming the point (0, 0) is the lower one.
(i_start, j_start) = (1, 0)
While (1)
If (i_start, j_start) out of bound: break
(i, j) = (i_start, j_start)
While (1)
If (i, j) out of bound: break
Write matrix[i][j]
i--, j++
End while
If (i_start not max) i_start++
Else j_start++
End while

Number of heaps using n distinct integers- Time complexity

I am solving the problem to find the maximum number of max heaps that can be formed using n distinct integers (say 1..n). I have solved it using the following
recurrence with some help from this: https://www.quora.com/How-many-Binary-heaps-can-be-made-from-N-distinct-elements :
T(N) = N-1 (C) L * T(L) * T(R). where L is the number of nodes in the left subtree and R is the number of nodes in the right subtree. I have also implemented it in c++ using dynamic programming. But I am stuck in find the time complexity of it. Can someone help me with this?
#include <iostream>
using namespace std;
#define MAXN 105 //maximum value of n here
int dp[MAXN]; //dp[i] = number of max heaps for i distinct integers
int nck[MAXN][MAXN]; //nck[i][j] = number of ways to choose j elements form i elements, no order */
int log2[MAXN]; //log2[i] = floor of logarithm of base 2 of i
//to calculate nCk
int choose(int n, int k)
{
if (k > n)
return 0;
if (n <= 1)
return 1;
if (k == 0)
return 1;
if (nck[n][k] != -1)
return nck[n][k];
int answer = choose(n-1, k-1) + choose(n-1, k);
nck[n][k] = answer;
return answer;
}
//calculate l for give value of n
int getLeft(int n)
{
if (n == 1)
return 0;
int h = log2[n];
//max number of elements that can be present in the hth level of any heap
int numh = (1 << h); //(2 ^ h)
//number of elements that are actually present in last level(hth level)
//(2^h - 1)
int last = n - ((1 << h) - 1);
//if more than half-filled
if (last >= (numh / 2))
return (1 << h) - 1; // (2^h) - 1
else
return (1 << h) - 1 - ((numh / 2) - last);
}
//find maximum number of heaps for n
int numberOfHeaps(int n)
{
if (n <= 1)
return 1;
if (dp[n] != -1)
return dp[n];
int left = getLeft(n);
int ans = (choose(n-1, left) * numberOfHeaps(left)) * (numberOfHeaps(n-1-left));
dp[n] = ans;
return ans;
}
//function to intialize arrays
int solve(int n)
{
for (int i = 0; i <= n; i++)
dp[i] = -1;
for (int i = 0; i <= n; i++)
for (int j = 0; j <=n; j++)
nck[i][j] = -1;
int currLog2 = -1;
int currPower2 = 1;
//for each power of two find logarithm
for (int i = 1; i <= n; i++)
{
if (currPower2 == i)
{
currLog2++;
currPower2 *= 2;
}
log2[i] = currLog2;
}
return numberOfHeaps(n);
}
//driver function
int main()
{
int n=10;
cout << solve(n) << endl;
return 0;
}

Resources