Find all unique subsets of a set of values - algorithm

I have an algorithm problem. I am trying to find all unique subset of values from a larger set of values.
For example say I have the set {1,3,7,9}. What algorithm can I use to find these subsets of 3?
{1,3,7}
{1,3,9}
{1,7,9}
{3,7,9}
Subsets should not repeat, and order is unimportant, set {1,2,3} is the same as set {3,2,1} for these purposes. Psudocode (or the regular kind) is encouraged.
A brute force approach is obviously possible, but not desired.
For example such a brute force method would be as follows.
for i = 0 to size
for j = i + 1 to size
for k = j + 1 to size
subset[] = {set[i],set[j],set[k]}
Unfortunately this requires an additional loop for each element desired in the subset, which is undesirable if, for example, you want a subset of 8 elements.

Some Java code using recursion.
The basic idea is to try to swap each element with the current position and then recurse on the next position (but we also need startPos here to indicate what the last position that we swapped with was, otherwise we'll get a simple permutation generator). Once we've got enough elements, we print all those and return.
static void subsets(int[] arr, int pos, int depth, int startPos)
{
if (pos == depth)
{
for (int i = 0; i < depth; i++)
System.out.print(arr[i] + " ");
System.out.println();
return;
}
for (int i = startPos; i < arr.length; i++)
{
// optimization - not enough elements left
if (depth - pos + i > arr.length)
return;
// swap pos and i
int temp = arr[pos];
arr[pos] = arr[i];
arr[i] = temp;
subsets(arr, pos+1, depth, i+1);
// swap pos and i back - otherwise things just gets messed up
temp = arr[pos];
arr[pos] = arr[i];
arr[i] = temp;
}
}
public static void main(String[] args)
{
subsets(new int[]{1,3,7,9}, 0, 3, 0);
}
Prints:
1 3 7
1 3 9
1 7 9
3 7 9
A more detailed explanation (through example):
First things first - in the above code, an element is kept in the same position by performing a swap with itself - it doesn't do anything, just makes the code a bit simpler.
Also note that at each step we revert all swaps made.
Say we have input 1 2 3 4 5 and we want to find subsets of size 3.
First we just take the first 3 elements - 1 2 3.
Then we swap the 3 with 4 and 5 respectively,
and the first 3 elements gives us 1 2 4 and 1 2 5.
Note that we've just finished doing all sets containing 1 and 2 together.
Now we want sets of the form 1 3 X, so we swap 2 and 3 and get 1 3 2 4 5. But we already have sets containing 1 and 2 together, so here we want to skip 2. So we swap 2 with 4 and 5 respectively, and the first 3 elements gives us 1 3 4 and 1 3 5.
Now we swap 2 and 4 to get 1 4 3 2 5. But we want to skip 3 and 2, so we start from 5. We swap 3 and 5, and the first 3 elements gives us 1 4 5.
And so on.
Skipping elements here is perhaps the most complex part. Note that whenever we skip elements, it just involves continuing from after the position we swapped with (when we swapped 2 and 4, we continued from after the 4 was). This is correct because there's no way an element can get to the left of the position we're swapping with without having been processed, nor can a processed element get to the right of that position, because we process all the elements from left to right.
Think in terms of the for-loops
It's perhaps the simplest to think of the algorithm in terms of for-loops.
for i = 0 to size
for j = i + 1 to size
for k = j + 1 to size
subset[] = {set[i],set[j],set[k]}
Each recursive step would represent a for-loop.
startPos is 0, i+1 and j+1 respectively.
depth is how many for-loops there are.
pos is which for-loop we're currently at.
Since we never go backwards in a deeper loop, it's safe to use the start of the array as storage for our elements, as long as we revert the changes when we're done with an iteration.

If you are interested only in subsets of size 3, then this can be done using three simple nested for loops.
for ( int i = 0; i < arr.size(); i++ )
for ( int j = i+1; j < arr.size(); j++ )
for ( int k = j+1; k < arr.size(); k++ )
std::cout << "{ " << arr[i] <<"," << arr[j] <<"," << arr[k] <<" }";
For a more general case you will have to use recursion.
void recur( set<int> soFar, set<int> remaining, int subSetSize ) {
if (soFar.size() == subSetSize) {
print soFar;
return;
}
for ( int I = 0; I < remaining.size(); I++ ) {
//take out Ith element from remaining and push it in soFar.
// recur( newSofar, newRemaining, subSetSize);
}
}

Related

Make BITWISE AND positive

I was solving one problem and it stated that we need to find the sum of all minimum number that needs to be added to the elements in the array so that the bitwise AND is greater than 0.
For eg: Given array is [4, 4, 3, 2]
then the output should be 3
(adding one to 1st 2nd and 4th element).
My approach : first I decided to find the position of the right most set in all elements and check for the overall minimum number to be added so that the and is greater than zero. But this is not working.Can anyone help in finding an alternative algo?
Let's solve a bit different problem first:
What minimum min number should be add to value to ensure 1 in kth position (zero based)?
We have two cases here:
if value has 1 at k position we add 0 (do nothing);
if value has 0 at k position we can add
min = 100...000000000 - (value & 11.....11111)
<- k zeroes -> <- k ones ->
Code (C#)
private static long AddToEnsureOne(long value, int position) {
if ((value & (1L << position)) != 0)
return 0;
long shift = 1L << (position);
return shift - (value & (shift - 1));
}
Demo: if we have 3 and we want 1 at 2nd position
0b011
^
we want 1 here
we should add
0b100 - (0b011 & 0b11) == 4 - 3 == 1
let's add: 3 + 1 == 4 == 0b100 which has 1 at 2nd position
Now we can scan all 32 positions (if integer is good old 32 bit integer int); C# code:
private static long MinToAdd(IEnumerable<int> items) {
long best = 0;
for (int i = 0; i < 32; ++i) {
long sum = 0;
foreach (int item in items)
sum += AddToEnsureOne(unchecked((uint)item), i); // uint - get rid of sign
if (i == 0 || sum < best)
best = sum;
}
return best;
}
One can improve the solution looping not for 32 positions but for the leftmost 1 of the maximum item. Here we have 4 as the maximum, which is 0b100, the leftmost 1 is in the 2 position; thus for (int i = 0; i <= 2; ++i) will be enough in the context
Simple test:
Console.Write(MinToAdd(new int[] { 4, 4, 3, 2}));
Outcome:
3

Number of solutions of a linear equation of n variables

// A Dynamic programming based C++ program to find number of
// non-negative solutions for a given linear equation
#include<bits/stdc++.h>
using namespace std;
// Returns counr of solutions for given rhs and coefficients
// coeff[0..n-1]
int countSol(int coeff[], int n, int rhs)
{
// Create and initialize a table to store results of
// subproblems
int dp[rhs+1];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
// Fill table in bottom up manner
for (int i=0; i<n; i++)
for (int j=coeff[i]; j<=rhs; j++)
dp[j] += dp[j-coeff[i]];
return dp[rhs];
}
// Driver program
int main()
{
int coeff[] = {2, 2, 5};
int rhs = 4;
int n = sizeof(coeff)/sizeof(coeff[0]);
cout << countSol(coeff, n, rhs);
return 0;
}
I am new to competitive programming, I just stumbled upon this code. I would like to know the intuition behind this particular snippet, like how does the second for loop help. Thank you.
// Fill table in bottom up manner
for (int i=0; i<n; i++)
for (int j=coeff[i]; j<=rhs; j++)
dp[j] += dp[j-coeff[i]];
This is using a bottom up approach, and
Suppose if j= 3 and j-coeff[i] = 2
so how does d[3] = d[3] + d[2] give the solution? How can a simple addition of a previous result and a current result give the total solution of linear variables?
Imagine that you have unlimited number of coins with value 2,3,5 (your coeff[]) and you want to know number of solutions to make some sum form give coin set.
At the first loop run you fill table with coins 2. Table will be filled
idx 0 1 2 3 4 5 6
num 1 0 1 0 1 0 1
because there is the only way to get even sum with such coins.
At the second loop run you fill table with coins 3 - now you'll have sums that might be composed from coins 2 and 3
idx 0 1 2 3 4 5 6
num 1 0 1 1 1 1 2
Note that cell 5 filled with 2+3 - similar to your question situation, and cell 6 now contains 2 variants: 2+2+2 and 3+3

Print ways to reach the n’th stair

I recently encountered this problem in an interview
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair or 2 stairs at a time.
Print all possible ways person can reach the top.
For example, n=4 Output:
1 2 3 4
1 2 4
1 3 4
2 3 4
2 4
But I couldn't code this properly. How to code up solution for this?
To print the number of ways, you can first understand how to calculate the number of ways, and adjust it so each "count" will print instead of just count:
D(0) = 1
D(-1) = 0
D(i) = D(i-1) + D(i-2)
To adjust it to actual printing, you need to "remember" the choices you have made, and follow the same logic. Pseudo code:
printWays(curr, n, soFar):
if curr > n:
return
soFar.append(curr)
if n == curr:
print soFar
soFar.removeLast()
return
printWays(curr+1,n,soFar)
printWays(curr+2,n,soFar)
soFar.removeLast()
The idea is:
soFar is the current series of steps you did.
curr is the current step you're at.
n is the last stair you need to get to.
At each point, you either climb one stair or two. You check both options.
You can try some recursive solution where you call recursively CanClimb(n-1) and CanClimb(n-2) to visualize the possible ways.
Sample solution in C#:
public static void ClimbWays(int n, int currentIndex, int[] currectClimb)
{
if (n < 0) return;
if (n == 0)
{
for (var i = currentIndex - 1; i >= 0; i--)
{
Console.Write(currectClimb[i] + " ");
}
Console.WriteLine();
return;
}
currectClimb[currentIndex] = n;
ClimbWays(n - 1, currentIndex + 1, currectClimb);
ClimbWays(n - 2, currentIndex + 1, currectClimb);
}
Output for ClimbWays(4, 0, new int[4]);:
1 2 3 4
2 3 4
1 3 4
1 2 4
2 4
If you want to just count them you can use the well known Fibonacci sequence which can be calculated iteratively:
public static int Fibonacci(int n)
{
int a = 0;
int b = 1;
// In N steps compute Fibonacci sequence iteratively.
for (int i = 0; i < n; i++)
{
int temp = a;
a = b;
b = temp + b;
}
return a;
}

Number of contiguous subarrays in which element of array is max

Given an array of 'n' integers, i need to find for each element of the array, the number of continuous subarrays that have that element as its max element.
Elements can repeat.
Is there a way to do it in less than O(n^2).
O(nlogn) or O(n)?
Example-
If array is {1,2,3}. Then-
For '1': 1 Such subarray {1}.
For '2': 2 Such subarrays {2},{1,2}
For '3': 3 Such subarrays {3},{2,3},{1,2,3}
I am having hard time trying to explain my solution in words. I will just add the code. It will explain itself:
#include <iostream>
#include <fstream>
using namespace std;
#define max 10000
int main(int argc, const char * argv[]) {
ifstream input("/Users/appleuser/Documents/Developer/xcode projects/SubArrayCount/SubArrayCount/input.in");
int n, arr[max], before[max]={0}, after[max]={0}, result[max];
input >> n;
for (int i=0; i<n; i++)
input >> arr[i];
for (int i=0;i<n;i++)
for (int j=i-1;j>=0&&arr[j]<arr[i];j-=before[j]+1)
before[i]+=before[j]+1;
for (int i=n-1;i>=0;i--)
for (int j=i+1;j<n&&arr[j]<arr[i];j+=after[j]+1)
after[i]+=after[j]+1;
for (int i=0;i<n;i++)
result[i]= (before[i]+1)*(after[i]+1);
for (int i=0; i<n; i++)
cout << result [i] << " ";
cout << endl;
return 0;
}
Explanation for (before[i]+1)*(after[i]+1):
for each value we need the numbers lies before and less than the value and the numbers lies after and less than the value.
| 0 1 2 3 4 5 .... count of numbers less than the value and appears before.
---------------------
0 | 1 2 3 4 5 6
1 | 2 4 6 8 10 12
2 | 3 6 9 12 15 18
3 | 4 8 12 16 20 24
4 | 5 10 15 20 25 30
5 | 6 12 18 24 30 36
. |
. |
. |
count of numbers less than the value and appears after.
Example: for a number that have 3 values less than it and appears before and have 4 values less than it and appears after. answer is V(3,4) = 20 = (3+1) * (4+1)
please, let me know the results.
Did you manage to find the source link of the problem?
You could store SubArrays sizes in another Array (arr2) to save yourself recalculating them.
arr2 must be the length of the max value in the arr1
i.e -
Take the Array {1,2,4,6,7,8}
arr2 is declared like this:
arr2 = []
for i in range(max(arr1)):
arr2.append(0)
Now, the algorithm goes like this:
Say you hit number 6.
Since 6-1=5 does not exist it has a default value of 0 corresponding to index 5 in arr2, because nothing has been added there yet. So you store 0+1=1 in position 6 of arr2. Then you hit the number 7. You check if 7-1=6 exists in arr2. It does, with a value of 1. Hence add the value of 1+1=2 to position 7 in arr2.
For each value in arr2 we simply add this to the count. We can do so simultaneously with a count variable.
This algorithm is O(n)
Here is my O(N) time java solution using Stack. Basic idea is to move from left to right keeping track of sub arrays ending at "i" and then right to left keeping track of sub arrays starting from "i":
public int[] countSubarrays(int[] arr) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[arr.length];
for(int i = 0; i < arr.length; i++) {
while(!stack.isEmpty() && arr[stack.peek()] < arr[i]) {
ans[i] += ans[stack.pop()];
}
stack.push(i);
ans[i]++;
}
stack.clear();
int[] temp = new int[arr.length];
for(int i = arr.length - 1; i >= 0; i--) {
while(!stack.isEmpty() && arr[stack.peek()] < arr[i]) {
int idx = stack.pop();
ans[i] += temp[idx];
temp[i] += temp[idx];
}
stack.push(i);
temp[i]++;
}
return ans;
}
You haven't specified in which way repeating elements are handled/what that element is (the element at the precise position in the array, or any element in the array with the same value).
Assuming the problem is for the element at a precise index this can be solved easily in linear time:
define ctSubarrays(int[] in , int at)
int minInd = at, maxInd = at;
//search for the minimum-index (lowest index with a smaller element than in[at]
for(; minInd > 0 && in[minInd - 1] < in[at] ; minInd--);
//search for the maximum-index (highest index with a smaller element than in[at]
for(; maxInd < length(at) - 1 && in[maxInd + 1] < in[at] ; maxInd++);
//now we've got the length of the largest subarray meeting all constraints
//next step: get the number of possible subarrays containing in[at]
int spaceMin = at - minInd;
int spaceMax = maxInd - at;
return spaceMin * spaceMax;
Lets look at an example.
{4, 5, 6, 3, 2}
Iterating from the begin till the end we can detect single increasing subarray: {4, 5, 6} and two single elements 3, and 2.
So we're detecting lengths of subarrays 3, 1, and 1.
First subarray {4, 5, 6} gives us 6 possible decisions, i.e. 1 + 2 + 3 = 6. It's a key.
For any length of increasing subarray N we can calculate the number of decisions as N * (N + 1)/2.
Therefore we have 3 * (3 + 1)/2 + 1 * (1 + 1)/2 + 1 * (1 + 1)/2, i.e. 6 + 1 + 1 = 8.
While we need a single iteration only, we have O(N) algorithm.
If the array is sorted,
count = 1;
for (i = 1 to n-1){
if(a[i-1] == a[i]){
count = count + 1;
}else if(a[i-1] + 1 == a[i]){
count of sub arrays for a[i-1] = count;
count = count + 1;
}else{
count of sub arrays for a[i-1] = count;
count = 1;
}
}
count of sub arrays for a[n-1] = count;
If the array is not sorted,
Assumption 3:If the array is like {3,1,2,3} then #sub arrays for 3 is 3
aMin = min(a);//O(n)
aMax = max(a);
len = (aMax - aMin + 1);
create array b of size len;
for (j = 0 to len-1){
b[j] = 0;
}
count = 1;
for (i = 1 to n-1){
if(a[i-1] == a[i]){
count = count + 1;
}else if(a[i-1] + 1 == a[i]){
if(b[a[i-1] - aMin] < count){
b[a[i-1] - aMin] = count;
}
count = count + 1;
}else{
if(b[a[i-1] - aMin] < count){
b[a[i-1] - aMin] = count;
}
count = 1;
}
}
if(b[a[n-1] - aMin] < count){
b[a[n-1] - aMin] = count;
}
for (i = 0 to n-1){
count of sub arrays for a[i] = b[a[i] - aMin];
}
This will work even if the array contains negative integers
If Assumption 3 fails according to your problem, and it is like,
Assumption 4:If the array is like {3,1,2,3} then #sub arrays for 3 is 4
{3}, {1,2,3}, {2,3}, {3}
Modify the above code by replacing
if(b[a[i-1] - aMin] < count){
b[a[i-1] - aMin] = count;
}
with this
b[a[i-1] - aMin] = b[a[i-1] - aMin] + count;
Create a value-to-index map and traverse from bottom to top - maintain an augmented tree of intervals. Each time an index is added, adjust the appropriate interval and calculate the total from the relevant segment. For example:
A = [5,1,7,2,3] => {1:1, 2:3, 3:4, 5:0, 7:2}
indexes interval total sub-arrays with maximum exactly
1 (1,1) 1 => 1
1,3 (3,3) 2 => 1
1,3,4 (3,4) 3 => 2
1,3,4,0 (0,1) 5 => 2
1,3,4,0,2 (0,4) 7 => 3 + 2*3 = 9
Insertion and deletion in augmented trees are of O(log n) time-complexity. Worst-case total time-complexity is O(n log n).
Using JavaScript Not sure the Big O notation. But here i'm looping the list. Then starting 2 loops. One counting down from i, and the other counting up from i+1.
let countArray = []
for(let i = 0; i < arr.length; i++){
let count = 0;
*This will count downwards starting at i*
for(let j = i; j >= 0; j--){
if(arr[j] > arr[i]) {break;}
count++;
}
*This will count upwards starting at i+1 so that you dont get a duplicate of the first value*
for(let j = i+1; j < arr.length; j++){
if(arr[j] >= arr[i]) {break;}
count++;
}
countArray.push(count);
}
return countArray;

Algorithm to compute minimum number of visible buildings?

I have been trying to formulate an algorithm to solve a problem. In this problem, we have a photo containing some buildings. The photo is divided into n vertical regions (called pieces) and the height of a building in each piece is given.
One building may span several consecutive pieces, but each piece can only contain one visible building, or no buildings at all. We are required to find the minimum number of buildings.
e.g.
given ,
3 ( no of pieces)
1 2 3 ( heights) ans = 3
3
1 2 1 ans = 2
6
1 2 3 1 2 3 ans = 5 ( a figure wud help show the overlap.).
Though I feel like I get it, I am unable to get a solid algorithm for it. Any ideas?
You can find the lowest number from the given array and account for all occurances of this number. This will split the array into multiple subarrays and now you need to recursively solve the problem for each of them.
In the example:
1 2 3 1 2 3 (total = 0)
Smallest number is 1:
x 2 3 x 2 3 (total = 1)
Now you have 2 subarrays.
Solve for the first one - the smallest number is 2:
x 3 (total = 2)
Finally you have a single element: total = 3
Solving the other subarray makes it 5.
Here is some code in C#:
int Solve(int[] ar, int start, int end){
//base for the recursion -> the subarray has single element
if(end-start == 1) return 1;
//base for the recursion -> the subarray is empty
if(end-start < 1) return 0;
//find min
int m = int.MaxValue;
for(int i = start; i < end; i++)
if (ar[i] < m) m = ar[i];
int total = 1;
//find the subarrays and their contribution recursively
int subStart = start;
for(int subEnd = start; subEnd < end; subEnd++){
if(ar[subEnd] == m) {
total += Solve(ar, subStart, subEnd);
subStart = subEnd + 1;
}
}
total += Solve(ar, subStart, ar.Length);
return total;
}

Resources