Related
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
Let's say we have given an array of digits, A, and a positive number, B. The problem is to generate all the possible B-digit numbers combined of A's elements.
For example, if A = [0,1,2,3] and B = 2, then the output must be,
[10,11,12,13,20,21,22,23,30,31,32,33]
Generate all possible combinations of 2 digit numbers by multiplying and adding the elements of the array in nested for loops.
Check if the generated numbers are greater than 10 to be a valid two digit number.
`
#include<iostream>
#include<cmath>
int main () {
int A[4] = {0,1,2,3}; int B = 2; int k;
for(size_t i = 0; i < sizeof(A)/sizeof(A[0]); i++)
{
for(size_t j = 0; j < sizeof(A)/sizeof(A[0]); j++)
{
k = (A[i] * pow(10, B-1) + j);
if(k / 10 > 0)
std::cout << k << '\n';
}
}
}
We are given a maze in which we need to visit as many rooms as possible. The specialty of the maze is that once you enter any room it will only lead you to rooms with a higher tag in the direction you move . B and C decide to move in opposite directions trying their luck to maximize the number of rooms they search .(They can start with any room , need not be the same)
We need to find out the maximum number of rooms that can be searched.
1. Access to any room with a higher tag is allowed, not just adjacent rooms or the next room with a higher tag.
2. Tags are unique.
So given the input:
12 11 10 1 2 3 4 13 6 7 8 5 9
the answer is 12: (1,2,3,4,6,7,8,9) for B and (5,10,11,12) for C.
I thought of solving this using longest increasing sub sequence first from right and then from left.And the count of unique elements in above two sub sequence would be the answer.
But my logic seems to fail,how can this be done?
My program below computes the maximum number of rooms searched. This has time complexity of O(n^3). I modified the DP algorithm for computing the longest increasing sequence available online to solve OP's problem. This also addresses OP's concerns on arrays like {1,4,6,2,5}. I rightly get the max value as 5 for the previous example. So, I used the idea from #BeyelerStudios that we need to compute the longest increasing subsequence from both left to right and from right to left. But, there is a caveat. If we compute the Left to right max sequence, the sequence from right to left should be on the remaining elements. Example:
For the array {1, 4, 6, 2, 5}. If the forward rooms selected are {1, 4, 5 }, then the reverse longest increasing sequence should be computed on the left out elements {6, 2}.
Below is my program:
#include <iostream>
using namespace std;
// compute the max increasing sequence from right to left.
int r2lRooms (int arr[], int n)
{
int dp[n];
int i =0, j = 0;
int max = 0;
for ( i = 0; i < n; i++ ) {
dp[i] = 1;
}
for (i = n-2; i >= 0; i--) {
for ( j = n-1; j > i; j-- ) {
if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
}
}
}
for ( i = 0; i < n; i++ ) {
if ( max < dp[i] ) {
max = dp[i];
}
}
return max;
}
// compute max rooms.
int maxRooms( int arr[], int n )
{
int dp[n], revArray[n];
int i =0, j = 0, k = 0;
int currentMax = 0;
int forwardMax = 0, reverseMax = 0;
for ( i = 0; i < n; i++ ) {
dp[i] = 1;
}
// First case is that except for first elem, all others are in revArray
for (i=1; i < n; i++, k++) {
revArray[k] = arr[i];
}
reverseMax = r2lRooms (revArray, k);
forwardMax = 1;
if (currentMax < (forwardMax + reverseMax)) {
currentMax = forwardMax + reverseMax;
}
cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
cout << endl;
for ( i = 1; i < n; i++ ) {
k = 0;
forwardMax = 1;
reverseMax = 0;
cout << "Forward elems for arr[" << i << "]=" << arr[i] << endl;
for ( j = 0; j < i; j++ ) {
if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
forwardMax = dp[i];
cout << arr[j] << " ";
}
else {
// element was not in DP calculation, so put in revArray.
revArray[k] = arr[j];
k++;
}
}
// copy the remaining elements in revArray.
for ( j = i+1; j < n; j++ ) {
revArray[k] = arr[j];
k++;
}
cout << endl;
reverseMax = r2lRooms (revArray, k);
if (currentMax < (forwardMax + reverseMax)) {
currentMax = forwardMax + reverseMax;
}
cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
cout << endl;
}
cout << " Max rooms searched " << currentMax << endl;
return currentMax;
}
int main (void) {
int arr[] = {12, 11, 10, 1, 2, 3, 4, 13, 6, 7, 8, 5, 9 };
int size = sizeof(arr) / sizeof(int);
cout << maxRooms (arr, size);
}
I think the trick is at the intersection, where B and C might share a value or there's options to go around that (say the sequence is 12 11 10 1 2 3 4 <3 5> 13 6 7 8 9 The extra numbers here adds 1 to the solution, but doesn't change the result for either longest increasing sub-sequences.
So the only problem is the one room in the middle, since on both side the values chosen diverge.
What I would do is this: do the longest subsequence in one direction, figure out a solution (any solution), take out the numbers in the solution and do the longest subsequence in the other direction. This way if there's a way around the crossing room in the middle the second pass will prefer it, unless that's the chosen number is really needed. To check for that do the same thing, but build the first subsequence in the opposite direction and the second one (after removing the solution) in the direction chosen initially.
Complexity remains O(N) but with a slightly higher constant factor.
We have an array A with m positive integer numbers, what's an algorithm that will
return true if there's a triple (x,y,z) in A
such that A[x] + A[y] + A[z] = 200
Otherwise return false. Numbers in array are distinct and running time must be O(n).
I came up with O(n^3). Any ideas on how to achieve this with O(n)?
Since elements are unique, this boils down to pre processing the array in O(n) to filter redundant elements - which are larger than 200 (none of them will be in the triplet).
Than, you have an array which its size is no larger than 200.
Checking all triplets in this array is O(200^3)=O(1) (it can be done more efficiently in terms of constants though).
So, this will be O(n) U O(200^3) = O(n)
I think you can solve this problem with bit operation. Such as bitset in C++ STL.
Using 3 bitsets, the first bitset cache all numbers you can get it by add 1 number, the second bitset cache all numbers you can get it by add 2 numbers, the third bitset cache all numbers you can get it by add 3 numbers. Then if a new number is coming, you can maintain the bitsets by simple bit operation.
Here is a sample C++ code:
bitset<256> bs[4];
for (int i = 0; i < 4; ++i)
bs[i].reset();
int N, number;
cin >> N;
while (N--)
{
cin >> number;
bs[3] |= (bs[2] << number);
bs[2] |= (bs[1] << number);
if (number <= 200)
bs[1].set(number);
//cout << "1: " << bs[1] << endl;
//cout << "2: " << bs[2] << endl;
//cout << "3: " << bs[3] << endl;
}
cout << bs[3][200] << endl;
The algorithm complexity is O(n). Because bit operation is quickly, each 64-bit long type can cache 64 number, so if you don't want to use bitset, you can use 4 long type(64 * 4 = 256) to replace it.
I agree with #amit's solution, but there is an question: How can we make it better, in our case just faster.
Here is my solution and it's almost based on amit' idea, but the asymptotic complexity == O(n + sum*(sum+1)/2), where n is a length of input array.
Firstly, we need n steps to filter the input array and put each value, that less the sum into the new array, where index of the value is equal to the value. At the end of this step we have the array, which size is equal to sum and we are able to access any value in O(1).
Finally, to find x,y,z we only need sum*(sum+1)/2 steps.
typedef struct SumATripleResult
{
unsigned int x;
unsigned int y;
unsigned int z;
} SumATripleResult;
SumATripleResult sumATriple(unsigned int totalSum, unsigned int *inputArray, unsigned int n)
{
SumATripleResult result;
unsigned int array[totalSum];
//Filter the input array and put each value into 'array' where array[value] = value
for (size_t i = 0; i<n; i++)
{
unsigned int value = inputArray[i];
if(value<totalSum)
{
array[value] = value;
}
}
unsigned int x;
unsigned int y;
unsigned int z;
for (size_t i = 0; i<totalSum; i++)
{
x = array[i];
for (size_t j = i+1; x>0 && j<totalSum; j++)
{
y = array[j];
if( y==0 || x + y >= totalSum) continue;
unsigned int zIdx = totalSum - (x + y);
if(zIdx == x || zIdx == y) continue;
z = array[zIdx];
if( z != 0)
{
result.x = x;
result.y = y;
result.z = z;
return result;
}
}
}
//nothing found
return result;
}
//Test
unsigned int array[] = {1, 21, 30, 12, 15, 10, 3, 5, 6, 11, 17, 31};
SumATripleResult r = sumATriple(52, array, 12);
printf("result = %d %d %d", r.x, r.y, r.y);
r = sumATriple(49, array, 12);
printf("result = %d %d %d", r.x, r.y, r.y);
r = sumATriple(32, array, 12);
printf("result = %d %d %d", r.x, r.y, r.y);
This is known as 3SUM problem and has no linear solution yet. I am providing a pseudo code running with O(n^2) using binary search algorithm:
sumTriple(А[1...n]: array of integers,sum: integer): bool
sort(A)
for i ← 1 to n-2
j ← i+1
k ← n
while k > j
if A[i]+A[j]+A[k] = sum
print i,j,k
return true
else if A[i]+A[j]+A[k] > sum
k ← k-1
else // A[i]+A[j]+A[k] < sum
j ← j+1
return false
More information and further details for the problem you can find here.
This question already has answers here:
Finding an element in an array that isn't repeated a multiple of three times?
(4 answers)
Closed 7 years ago.
I have been asked this question in an interview.
Given that, there are 3n+1 numbers. n of those numbers occur in triplets, only 1 occurs single time. How do we find the unique number in linear time i.e., O(n) ? The numbers are not sorted.
Note that, if there were 2n+1 numbers, n of which occur in pairs, we could just XOR all the numbers to find the unique one. The interviewer told me that it can be done by bit manipulation.
Count the number of times that each bit occurs in the set of 3n+1 numbers.
Reduce each bit count modulo 3.
What is left is the bit pattern of the single number.
Oh, dreamzor (above) has beaten me to it.
You can invent a 3nary XOR (call it XOR3) operation which operates in base 3 instead of base 2 and simply takes each 3nary digit modulo 3 (when usual XOR takes 2nary digit modulo 2).
Then, if you XOR3 all the numbers (converting them to 3nary first) this way, you will be left with the unique number (in base 3 so you will need to convert it back).
The complexity is not exactly linear, though, because the conversions from/to base 3 require additional logarithmic time. However, if the range of numbers is constant then the conversion time is also constant.
Code on C++ (intentionally verbose):
vector<int> to_base3(int num) {
vector<int> base3;
for (; num > 0; num /= 3) {
base3.push_back(num % 3);
}
return base3;
}
int from_base3(const vector<int> &base3) {
int num = 0;
for (int i = 0, three = 1; i < base3.size(); ++i, three *= 3) {
num += base3[i] * three;
}
return num;
}
int find_unique(const vector<int> &a) {
vector<int> unique_base3(20, 0); // up to 3^20
for (int num : a) {
vector<int> num_base3 = to_base3(num);
for (int i = 0; i < num_base3.size(); ++i) {
unique_base3[i] = (unique_base3[i] + num_base3[i]) % 3;
}
}
int unique_num = from_base3(unique_base3);
return unique_num;
}
int main() {
vector<int> rands { 1287318, 172381, 5144, 566546, 7123 };
vector<int> a;
for (int r : rands) {
for (int i = 0; i < 3; ++i) {
a.push_back(r);
}
}
a.push_back(13371337); // unique number
random_shuffle(a.begin(), a.end());
int unique_num = find_unique(a);
cout << unique_num << endl;
}
byte [] oneCount = new byte [32];
int [] test = {1,2,3,1,5,2,9,9,3,1,2,3,9};
for (int n: test) {
for (int bit = 0; bit < 32; bit++) {
if (((n >> bit) & 1) == 1) {
oneCount[bit]++;
oneCount[bit] = (byte)(oneCount[bit] % 3);
}
}
}
int result = 0;
int x = 1;
for (int bit = 0; bit < 32; bit++) {
result += oneCount[bit] * x;
x = x << 1;
}
System.out.print(result);
Looks like while I was coding, others gave the main idea