Two integers x and y form a magical pair, if the result of their Bitwise And equals 0.
Given an array of integers, find for every array element whether it forms a magical pair with some other array element or not.
Input
First line of the input contains a single integer T denoting the number of test cases.
The first line of each test case has an integer N denoting the number of elements in the given array.
The second line contains N single space-separated integers a1,a2,...an denoting the elements of the given array.
Output
For each test case ,print N space separated integers in a line.
If ai forms a magical pair with any other element of the given array , then ans'i should be equal to 1. Otherwise ans'i is 0.
Constraints
1<=N,Ai<=10^6
I tried brute force. For each element I checked if the bitwise AND of this number is zero or not with any other element present in the array. Obviously, it had a time complexity of O(N^2) and most of my test cases timed out
This problem is here: https://www.hackerearth.com/challenges/test/netapp-codenet-2017/algorithm/d2d1f6a92c6740278682e88ed42068a4/
Can anyone suggest me a better approach or algorithm so it passes the time limit?
Brute force code:
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++)
cin >> a[i];
int ans[n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (a[i] & a[j] == 0)
ans[i] = 1;
for (int i = 0; i < n; i++)
cout << ans[i] << " ";
One way to do it would be to create a binary tree for all the numbers like a Trie.
For example, if you have array 3 6 2 9 10, binary array would look like
arr = 11, 110, 10, 1001, 1010, and the tree would like
root
/ \
0 1
\ / \
1 0 1
/ \ /
0 1 0
\ \
1 1
If we iterate through each element in binary array, the number(answer) matching the condition should have 0 for every set bit in the element and either 0 or 1 for unset bit in the element.
Now, we only need to traverse these bits into the tree. And if we are able to do it, then there exists at least one number satisfying the condition.
Time complexity O(N).
Reason:- There are n numbers. Each number is of 32 bit binary length. New node creation will take O(1). Therefore, O(32N) => O(N). Same time for inv_arr.
Note: Try converting the numbers into 32 bit binary numbers as it will cover all the numbers specified in the range. Otherwise it will result in a problem. Here 6 and 9 forms a magical pair, but 0110 in the inv_arr cannot be traversed and will result in no magical pair present as traversal of leftmost 0 cannot be done. If all numbers will be represented with same length binary, tree traversal will give correct answer.
Code
public class BinaryNode {
char c;
public BinaryNode left;
public BinaryNode right;
public BinaryNode(char c) {
this.c = c;
}
}
public class BinaryTree {
public BinaryNode root;
public BinaryTree(char c) {
root = new BinaryNode(c);
}
public void addToTree(String s) {
BinaryNode node = this.root;
int length = s.length();
for (int i = s.length()-1; i >= 0; i--) {
BinaryNode newNode;
if (s.charAt(i) == '0') {
newNode = addCharToTree(node.left, s.charAt(i));
node.left = newNode;
} else {
newNode = addCharToTree(node.right, s.charAt(i));
node.right = newNode;
}
node = newNode;
}
}
private BinaryNode addCharToTree(BinaryNode node, char c) {
if (node == null)
return new BinaryNode(c);
return node;
}
}
public class Solution {
private static void findMagicalPairs(List<Integer> list) {
// for creating 32 char long binary string list
List<String> binaryNumberList = list.stream()
.map(num -> Long.toBinaryString( Integer.toUnsignedLong(num) | 0x100000000L ).substring(1))
.collect(Collectors.toList());
// dummy character as root
BinaryTree binaryTree = new BinaryTree('c');
binaryNumberList.forEach(binaryTree::addToTree);
List<Boolean> booleanList = binaryNumberList.stream()
.map(s -> hasMagicalPair(s, binaryTree.root))
.collect(Collectors.toList());
}
private static boolean hasMagicalPair(String s, BinaryNode node) {
if (s == null || s.length() == 0)
return true;
if (node == null)
return false;
String substring = s.substring(0, s.length() - 1);
if (s.charAt(s.length()-1) == '1')
return hasMagicalPair(substring, node.left) ;
return hasMagicalPair(substring, node.left) || hasMagicalPair(substring, node.right);
}
}
First of all, sorry for the long answer :)
Problem: I think the problem with your brute force is that you are performing each checking twice (in both directions). Moreover, a lot of checkings are unnecessary.You can easily reduce the number of iterations by doing every checking only once (and only the necessary ones).
Key idea: You should not start the inner loop from 0.
Note: The first of the following sections only introduce the second, but the second section is the one that answers your question.
The whole code provided here is only meant to illustrate the stated ideas, nothing more.
1 - Find all possible magical pairs
Here we are trying to find all possible magical pairs in the given vector avoiding to check multiple times the same pair.
A solution could be:
std::vector<std::pair<int, int>> magical_pairs(const std::vector<int> & data)
{
std::vector<std::pair<int, int>> result;
for(size_t i = 0; i < data.size()-1; ++i) // Stop at second to last
{
for(size_t j = i+1; j < data.size(); ++j) // Start from i+1 and not 0
{
if((data[i] & data[j]) == 0)
result.push_back(std::make_pair(data[i], data[j]));
}
}
return result;
}
This way, you check all possible pairs only once.
According to me, if you want to get all possible magical pairs, you cannot reduce the complexity less than what it takes to check all possible pairs only once.But if someone has a better solution, I will be very interested to hear it (read it).
You can run an example this way:
std::vector<int> input_array {3, 12, -6, 27, 8, 18, -66, 47, 11}; // input example
for(const std::pair<int, int> & mp : magical_pairs(input_array))
std::cout << mp.first << " : " << mp.second << std::endl;
The results for this example:
3 : 12
3 : 8
12 : 18
8 : 18
2 - Check whether a number has a magical pair or not
Now that we know how to avoid to check already checked pairs, we will reuse the same principle to realize the function you want.
You want to check for every number in the array whether they have a magical pair in the array or not.In this case, we don't want to check all possible magical pairs, only one match is sufficient to determine if a number has a pair. Moreover, when we find a match, we can set two results at a time (one for each number of the pair).You can see that this way, we will be able to significantly reduce the number of iterations.
It leads us to proceed as follows:
Check every pair only once
Stop evaluation of a number at first match
Determine two results per match --> don't perform the search if already set
Knowing this, a solution could be:
std::vector<bool> has_magical_pair(const std::vector<int> & data)
{
std::vector<bool> result(data.size(), false);
for(size_t i = 0; i < data.size()-1; ++i) // From 0 to second to last
{
if(!result[i]) // search for a magical pair only if not already found
{
for(size_t j = i+1; j < data.size(); ++j) // From i+1 to last
{
if((data[i] & data[j]) == 0)
{
// Set two results at a time
result[i] = true;
result[j] = true;
break; // Exit the inner loop at first match
}
}
}
}
return result;
}
This way, you will be much more efficient than the brute force method.
You can run an example this way:
std::vector<int> input_array {3, 12, -6, 27, 8, 18, -66, 47, 11};
for(bool hmp : has_magical_pair(input_array))
std::cout << hmp << ", ";
std::cout << std::endl;
The results for this example:
1, 1, 0, 0, 1, 1, 0, 0, 0,
I think you will be able to adapt the code of this example to your use case quite easily.
I hope it can help you.
You have to save the operations you do first.
In the example you have 3 6 2 9 10
When you do it by brute force you first do
3 & 6
And after doing all the
3 & y
you repeat
6 & 3
. If you find how to avoid repeating this, you'll solve the problem.
Related
I am working on a C++ code to find out the number of leave node in a binary tree using array input
my code is:
int leaf(int data[],int size) {
int result = 0;
for (int i = 0; i <= size; i++) {
if (data[i] == -1)
i++;
if (((data[(2*i)+1] == -1) && (data[(2 * i) +2] == -1)) || ((data[(2 * i) +1] == NULL) && (data[(2 * i) +2] == NULL)))
result++;
}
return result;
}
int main(){
int data[]= { 1,9, 6, 8 ,12, 2,-1 ,10, -1 ,-1 ,-1, 5 };
int size = 12;
cout << "count of leave node: " << leaf(data, size)<< endl;
}
In the array, the element -1 is the empty node.
The tree is like:
1
/ \
9 6
/ \ /
8 12 2
/ /
10 5
The total number of the leave node should be 3 which is (12,10,5), but the result of my code is 2.
Can I know what wrong with my code and how to fix it.
Big Thanks!
Some issues:
When the for loop variable gets to equal size you will have an out of bounds index-access to data. The loop should exit in that case -- size is an invalid index, so use i < size as loop condition.
Your for loop increments the loop variable with i++; there should be no reason to increment i on top of that when you find a -1 value in the data. What if i will be out of bounds by doing that? What if the next data element also has a -1 value? In either case your code goes wrong. Instead use data[i] != -1 as a condition for the rest of the logic in the loop's body.
You should check that the index you use for data is not out of bounds, before actually making that index access. It is not safe to compare an out of bounds data entry with NULL: the value of an out of bounds access is undefined and int should never have to be compared with NULL. NULL is used in the context of pointers.
You should also foresee the case where the left child is -1 and the right child is out of bounds.
Here is a fix for those issues:
int leaf(int data[], int size) {
int result = 0;
for (int i = 0; i < size; i++) {
if ( data[i] != -1 &&
(2*i+1 >= size || data[2*i+1] == -1) &&
(2*i+2 >= size || data[2*i+2] == -1) )
result++;
}
return result;
}
This logic assumes that the array will be organised like a complete tree. Some array encodings like this will not have two -1 entries for filling up the "children" of another -1 entry, but just omit them, making the formula 2*i+1 and 2*i+2 invalid.
Take for example this tree:
1
\
2
\
3
If the encoding is a complete tree encoding, then it will be {1, -1, 2, -1, -1, -1, 3}. If it is the more compact encoding where -1 entries will not have children entries, then it will be {1, -1, 2, -1, 3}.
Your example does not show which of the two encodings you are dealing with as it would turn out to be the same array for your example tree. If it is the later encoding, you need a different algorithm altogether.
How to divide elements in an array into a minimum number of arrays such that the difference between the values of elements of each of the formed arrays does not differ by more than 1?
Let's say that we have an array: [4, 6, 8, 9, 10, 11, 14, 16, 17].
The array elements are sorted.
I want to divide the elements of the array into a minimum number of array(s) such that each of the elements in the resulting arrays do not differ by more than 1.
In this case, the groupings would be: [4], [6], [8, 9, 10, 11], [14], [16, 17]. So there would be a total of 5 groups.
How can I write a program for the same? Or you can suggest algorithms as well.
I tried the naive approach:
Obtain the difference between consecutive elements of the array and if the difference is less than (or equal to) 1, I add those elements to a new vector. However this method is very unoptimized and straight up fails to show any results for a large number of inputs.
Actual code implementation:
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
int main() {
int num = 0, buff = 0, min_groups = 1; // min_groups should start from 1 to take into account the grouping of the starting array element(s)
cout << "Enter the number of elements in the array: " << endl;
cin >> num;
vector<int> ungrouped;
cout << "Please enter the elements of the array: " << endl;
for (int i = 0; i < num; i++)
{
cin >> buff;
ungrouped.push_back(buff);
}
for (int i = 1; i < ungrouped.size(); i++)
{
if ((ungrouped[i] - ungrouped[i - 1]) > 1)
{
min_groups++;
}
}
cout << "The elements of entered vector can be split into " << min_groups << " groups." << endl;
return 0;
}
Inspired by Faruk's answer, if the values are constrained to be distinct integers, there is a possibly sublinear method.
Indeed, if the difference between two values equals the difference between their indexes, they are guaranteed to belong to the same group and there is no need to look at the intermediate values.
You have to organize a recursive traversal of the array, in preorder. Before subdividing a subarray, you compare the difference of indexes of the first and last element to the difference of values, and only subdivide in case of a mismatch. As you work in preorder, this will allow you to emit pieces of the groups in consecutive order, as well as detect to the gaps. Some care has to be taken to merge the pieces of the groups.
The worst case will remain linear, because the recursive traversal can degenerate to a linear traversal (but not worse than that). The best case can be better. In particular, if the array holds a single group, it will be found in time O(1). If I am right, for every group of length between 2^n and 2^(n+1), you will spare at least 2^(n-1) tests. (In fact, it should be possible to estimate an output-sensitive complexity, equal to the array length minus a fraction of the lengths of all groups, or similar.)
Alternatively, you can work in a non-recursive way, by means of exponential search: from the beginning of a group, you start with a unit step and double the step every time, until you detect a gap (difference in values too large); then you restart with a unit step. Here again, for large groups you will skip a significant number of elements. Anyway, the best case can only be O(Log(N)).
I would suggest encoding subsets into an offset array defined as follows:
Elements for set #i are defined for indices j such that offset[i] <= j < offset[i+1]
The number of subsets is offset.size() - 1
This only requires one memory allocation.
Here is a complete implementation:
#include <cassert>
#include <iostream>
#include <vector>
std::vector<std::size_t> split(const std::vector<int>& to_split, const int max_dist = 1)
{
const std::size_t to_split_size = to_split.size();
std::vector<std::size_t> offset(to_split_size + 1);
offset[0] = 0;
size_t offset_idx = 1;
for (std::size_t i = 1; i < to_split_size; i++)
{
const int dist = to_split[i] - to_split[i - 1];
assert(dist >= 0); // we assumed sorted input
if (dist > max_dist)
{
offset[offset_idx] = i;
++offset_idx;
}
}
offset[offset_idx] = to_split_size;
offset.resize(offset_idx + 1);
return offset;
}
void print_partition(const std::vector<int>& to_split, const std::vector<std::size_t>& offset)
{
const std::size_t offset_size = offset.size();
std::cout << "\nwe found " << offset_size-1 << " sets";
for (std::size_t i = 0; i + 1 < offset_size; i++)
{
std::cout << "\n";
for (std::size_t j = offset[i]; j < offset[i + 1]; j++)
{
std::cout << to_split[j] << " ";
}
}
}
int main()
{
std::vector<int> to_split{4, 6, 8, 9, 10, 11, 14, 16, 17};
std::vector<std::size_t> offset = split(to_split);
print_partition(to_split, offset);
}
which prints:
we found 5 sets
4
6
8 9 10 11
14
16 17
Iterate through the array. Whenever the difference between 2 consecutive element is greater than 1, add 1 to your answer variable.
`
int getPartitionNumber(int arr[]) {
//let n be the size of the array;
int result = 1;
for(int i=1; i<n; i++) {
if(arr[i]-arr[i-1] > 1) result++;
}
return result;
}
`
And because it is always nice to see more ideas and select the one that suites you best, here the straight forward 6 line solution. Yes, it is also O(n). But I am not sure, if the overhead for other methods makes it faster.
Please see:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
using Data = std::vector<int>;
using Partition = std::vector<Data>;
Data testData{ 4, 6, 8, 9, 10, 11, 14, 16, 17 };
int main(void)
{
// This is the resulting vector of vectors with the partitions
std::vector<std::vector<int>> partition{};
// Iterating over source values
for (Data::iterator i = testData.begin(); i != testData.end(); ++i) {
// Check,if we need to add a new partition
// Either, at the beginning or if diff > 1
// No underflow, becuase of boolean shortcut evaluation
if ((i == testData.begin()) || ((*i) - (*(i-1)) > 1)) {
// Create a new partition
partition.emplace_back(Data());
}
// And, store the value in the current partition
partition.back().push_back(*i);
}
// Debug output: Copy all data to std::cout
std::for_each(partition.begin(), partition.end(), [](const Data& d) {std::copy(d.begin(), d.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << '\n'; });
return 0;
}
Maybe this could be a solution . . .
How do you say your approach is not optimized? If your is correct, then according to your approach, it takes O(n) time complexity.
But you can use binary-search here which can optimize in average case. But in worst case this binary search can take more than O(n) time complexity.
Here's a tips,
As the array sorted so you will pick such a position whose difference is at most 1.
Binary search can do this in simple way.
int arr[] = [4, 6, 8, 9, 10, 11, 14, 16, 17];
int st = 0, ed = n-1; // n = size of the array.
int partitions = 0;
while(st <= ed) {
int low = st, high = n-1;
int pos = low;
while(low <= high) {
int mid = (low + high)/2;
if((arr[mid] - arr[st]) <= 1) {
pos = mid;
low = mid + 1;
} else {
high = mid - 1;
}
}
partitions++;
st = pos + 1;
}
cout<< partitions <<endl;
In average case, it is better than O(n). But in worst case (where the answer would be equal to n) it takes O(nlog(n)) time.
I am currently struggling with a homework problem for my Algorithms Class. A summary of the instruction:
The user enters an integer 'n' to determine the number of test cases.
The user individually enters another integer 'num' to determine the # of elements in each test case.
The user enters the elements of the individual array.
The algorithm has to process the array and determine whether it can be partitioned into two subsequences, each of which is in strictly increasing order. If the result is positive, the program prints "Yes", otherwise it prints "No".
I have 24 hours to complete this assignment but am struggling with the primary problem - I cannot properly process the user input. (come up with an algorithm to split the two subsequences)
update: I got to this solution. It passes 4/5 tests but fails the time constraint in the last test.
#include<iostream>
#include<string>
using namespace std;
bool run(){
int numbers;
int *arr;
cin >> numbers;
arr = new int[numbers];
for (int i = 0; i < numbers; i++)
cin >> arr[i];
long long int MAX = 0;
long long int MAX2 = 0;
string stra = "";
string strb = "";
string result = "";
string total = "";
long long int sum = 0;
for (int i = 0; i < numbers; i++){
if (arr[i] >= MAX && arr[i] != arr[i - 1]){
stra += to_string(arr[i]);
MAX = arr[i];
}
else
if (arr[i] >= MAX2 && MAX2 != MAX){
strb += to_string(arr[i]);
MAX2 = arr[i];
}
}
for (int i = 0; i < numbers; i++){
result = to_string(arr[i]);
total += result;
}
long long int len1 = stra.length();
long long int len2 = strb.length();
sum += len1 + len2;
delete[] arr;
if (sum != total.length())
return false;
else
return true;
}
int main()
{
int test;
cin >> test;
while (test > 0)
{
if (run())
cout << "Yes\n";
else
cout << "No\n";
test--;
}
system("pause");
}
Example input:
2
5
3 1 5 2 4
5
4 8 1 5 3
Example output:
Yes
No
Explanation: For the array 3 1 5 2 4, the two strictly increasing subsequences are: 3 5 and 1 2 4.
It seems that the existence of any equal or decreasing subsequence of at least three elements means the array cannot be partitioned into two subsequences, each with strictly increasing order, since once we've placed the first element in one part and the second element in the other part, we have no place to place the third.
This seems to indicate that finding the longest decreasing or equal subsequence is a sure solution. Since we only need one of length 3, we can record in O(n) for each element if it has a greater or equal element to the left. Then perform the reverse. If any element has both a greater or equal partner on the left and a smaller or equal partner on the right, the answer is "no."
We can visualise the O(n) time, O(1) space method by plotting along value and position:
A choosing list B here
A x would be wrong
x
value B z
^ B x
| x
| A
| x
|
| B
| x
- - - - - - - -> position
We notice that as soon as a second list is established (with the first decrease), any element higher than the absolute max so far must be assigned to the list that contains it, and any element lower than it can, in any case, only be placed in the second list if at all.
If we were to assign an element higher than the absolute max so far to the second list (that does not contain it), we could arbitrarily construct a false negative by making the next element lower than both the element we just inserted into the second list and the previous absolute max, but greater than the previous max of the second list (z in the diagram). If we had correctly inserted the element higher than the previous absolute max into that first list, we'd still have room to insert the new, arbitrary element into the second list.
(The JavaScript code below technically uses O(n) space in order to show the partition but notice that we only rely on the last element of each part.)
function f(A){
let partA = [A[0]];
let partB = [];
for (let i=1; i<A.length; i++){
if (A[i] > partA[partA.length-1])
partA.push(A[i]);
else if (partB.length && A[i] <= partB[partB.length-1])
return false;
else
partB.push(A[i]);
}
return [partA, partB];
}
let str = '';
let examples = [
[30, 10, 50, 25, 26],
[3, 1, 5, 2, 4],
[4, 8, 1, 5, 3],
[3, 1, 1, 2, 4],
[3, 4, 5, 1, 2],
[3, 4, 1],
[4, 1, 2, 7, 3]
];
for (e of examples)
str += JSON.stringify(e) + '\n' + JSON.stringify(f(e)) + '\n\n';
console.log(str);
I would go over the entire array once and check two maximal values. If the actual array value is smaller than both maxima, it is not possible, otherwise the proper maximum is increased.
The algorithm does not have to traverse the whole array, if the split condition is violated before.
Here is my code
#include <algorithm>
#include <iostream>
#include <vector>
bool isAddable(const int item, int &max1, int &max2) {
if (max2 > item) {
return false;
}
else {
if (max1 > item) {
max2 = item;
}
else {
max1 = item;
}
return true;
}
}
void setStartValue(int &max1, int &max2, const std::vector<int> &vec) {
max1 = *std::min_element(vec.begin(), vec.begin() + 3);
max2 = *std::max_element(vec.begin(), vec.begin() + 3);
}
bool isDiviableIntoTwoIncreasingArrays(const std::vector<int> &vec) {
if (vec.size() < 3) {
return true;
}
int max1, max2;
setStartValue(max1, max2, vec);
for (int i = 2; i < vec.size(); ++i) {
if (max1 > max2) {
if (!isAddable(vec[i], max1, max2)) {
return false;
}
}
else {
if (!isAddable(vec[i], max2, max1)) {
return false;
}
}
}
return true;
}
int main() {
std::vector<int> userVec;
int tmp1;
while (std::cin >> tmp1) {
userVec.emplace_back(tmp1);
}
const std::vector<int> v1{3, 1, 5, 2, 4};
const std::vector<int> v2{4, 8, 1, 5, 3};
const std::vector<int> v3{3, 4, 1};
for (const std::vector<int> &vec : {userVec, v1, v2, v3}) {
if (isDiviableIntoTwoIncreasingArrays(vec)) {
std::cout << "Yes\n";
}
else {
std::cout << "No\n";
}
}
}
I think you could resort to using a brute force solution. Notice here I use vectors(I think you should as well) to store the data and I use recursion to exhaust out all possible combinations. Keep the problem in mind, solve it and then focus on trivial tasks like parsing the input and matching the way your coursework expects you to enter data. I have added inline comments to make this understandable.
bool canPartition(vector<int>& nums) {
if(nums.empty()) return false;
vector<int> part1 = {}, part2 = {}; // two partitions
auto ans = canPart(nums, part1, part2, 0); // pass this to our recursive function
return ans;
}
bool canPart(vector<int>& nums, vector<int>& part1, vector<int>& part2, int i)
{
if(i >= nums.size()) // we are at the end of the array is this a solution?
{
if(!part1.empty() && !part2.empty()) // only if the partitions are not empty
{
//if you want you could print part1 and part2 here
//to see what the partition looks like
return true;
}
return false;
}
bool resp1empty = false, resp2empty = false, resp1 = false, resp2 = false;
if(part1.empty()) // first partition is empty? lets add something
{
part1.push_back(nums[i]);
resp1empty = canPart(nums, part1, part2, i + 1);
part1.pop_back(); // well we need to remove this element and try another one
}
else if(nums[i] > part1.back()) // first partition is not empty lets check if the sequence is increasing
{
part1.push_back(nums[i]);
resp1 = canPart(nums, part1, part2, i + 1);
part1.pop_back();
}
if(part2.empty()) // is partition two empty? lets add something
{
part2.push_back(nums[i]);
resp2empty = canPart(nums, part1, part2, i + 1);
part2.pop_back();
}
else if(nums[i] > part2.back()) // check if sequence is increasing
{
part2.push_back(nums[i]);
resp2 = canPart(nums, part1, part2, i + 1);
part2.pop_back();
}
//if any of the recursive paths returns a true we have an answer
return resp1empty || resp2empty || resp1 || resp2;
}
You can now try this out with a main function:
vector<int> v = {3,1,5,2,4};
cout << canPartition(v);
The key take away is make a small test case, add a few more non trivial test cases, solve the problem and then look into parsing inputs for other test cases
I think this comes down to whether you have an option for a number to appear in the first list or second list or not.
So, we will keep adding numbers to list 1 and if we can't add any element, we will make it as the start of the new list.
Let's say, we have both the lists going. If we come across an element to whom we can't add to any of the lists, we return false.
There does arise a situation where we could add an element to any of the 2 lists. In this scenario, we adopt a greedy approach as to add to which list.
We prepare an array of minimum values from the right. For example, for [30,10,50,25,26], we will have an array of minimums as [10,25,25,26,(empty here since last)].
Now, let's trace how we could divide them into 2 lists properly.
30 => List A.
10 => List B. (since you can't add it first list, so make a new one from here)
50 => List A.
Here, 50 applies to come after either 30 or 10. If we choose 10, then we won't be able to accommodate the next 25 in either of the 2 lists and our program would fail here itself, since our lists would look like [30] and [10,50]. However, we could continue further if we add 50 to 30 by checking for the minimum stored for it in our minimums array, which is 25.
25 => List B.
26 => List B.
So, our final lists are [30,50] and [10,25,26].
Time complexity: O(n), Space complexity: O(n) and you can print the 2 lists as well.
If we come across a sorted array which is strictly increasing, we return true for them anyway.
I'm given a number say N and its corresponding positions in an Array.
Say the positions (indices) given are:
4 5 8 11 13 15 21 28
I'm given two positions (indices) say x and y. Let x=7 and y=13.
I need to find how many occurrences of number is there between x and y (both included, y>=x). Like in above example the number exists at positions 8,11 and 13 which lies between positions x and y and thus answer is 3.
A simple approach would be the naive O(n) algorithm but I want to take advantage of fact that the poistions will always be given in ascending order. I think applying binary search in a modified manner can help but I'm facing facing trouble.
// P is the array that stores positions(indices) of number
int start=0,End=n-1; // n is the size of array P
int mid=(start+End)/2;
int pos1=0,pos2=0;
while(End>start)
{
mid=(start+End)/2;
if(P[mid]>=x && P[mid-1]<x && flag1!=0)
{
pos1=mid;
flag1=0
}
if(P[mid]<=y && P[mid+1]>y && flag2!=0)
{
pos2=mid;
flag2=0;
}
else if (P[mid]<x)
start=mid;
else
End=mid;
}
int Number_Of_Occurence=(pos2-pos1);
Can you please suggest where my code may go wrong?
You can take the advantage of STL library. std::lower_bound or std::upper_bound comes to mind.
Both have logarithmic complexity on sorted containers with random iterators.
For example:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {4, 5, 7, 8, 11, 13, 15, 21, 28};
int low_value = 7;
int high_value = 13;
auto low = std::lower_bound(v.begin(), v.end(), low_value);
auto high = std::upper_bound(v.begin(), v.end(), high_value);
std::cout << std::distance(low, high) << " elements in interval ["
<< low_value << ", " << high_value << "]" << std::endl;
return 0;
}
I'm boldly assuming this isn't a homework problem... you need to find the indices of both endpoints however your code only has one "mid" variable. Assuming you reimplement the binary search for both endpoints correctly and you are worried about number of operations, you can re-order the conditional in the if statements so that they short-circuit on flag!=0 before checking two other conditions. ie:
if( !flag1 && P[mid1]>=x && P[mid1-1]<x ) {...}
is technically faster than
if( P[mid1]>=x && P[mid1-1]<x && !flag1 ) {...}
Next, division can be an expensive operation ... and you are dividing by 2. Use a bit shift instead:
jump_size = jump_size >> 2
Now throwing away the flag entirely, we might rewrite the code to look more like this:
// n is the size of array P
// start int the middle
int pos1=pos2=n>>2;
// jump size is how far we jump up or down looking for our index
int jump_size=pos1>>2;
while(jump_size)
{
if(P[pos1]>x) { pos1 -= jump_size; }
else if(P[pos1]<x) { pos1+=jump_size; }
// similar for y and pos2
jump_size=jump_size>>2;
}
you can use floor(x)-ceil(y) to find it in O(log N) time .
below is code for finding ceil()..
int ceilSearch(int arr[], int low, int high, int x)
{
int i;
/* If x is smaller than or equal to first element,
then return the first element */
if(x <= arr[low])
return low;
/* Otherwise, linearly search for ceil value */
for(i = low; i < high; i++)
{
if(arr[i] == x)
return i;
/* if x lies between arr[i] and arr[i+1] including
arr[i+1], then return arr[i+1] */
if(arr[i] < x && arr[i+1] >= x)
return i+1;
}
/* If we reach here then x is greater than the last element
of the array, return -1 in this case */
return -1;
}
You can easily modify it to make floor() function .
Another method is to use lower_bound() and upper_bound() as you are using c++ .
I have a sorted std::vector<int> and I would like to find the longest 'streak of consecutive numbers' in this vector and then return both the length of it and the smallest number in the streak.
To visualize it for you :
suppose we have :
1 3 4 5 6 8 9
I would like it to return: maxStreakLength = 4 and streakBase = 3
There might be occasion where there will be 2 streaks and we have to choose which one is longer.
What is the best (fastest) way to do this ? I have tried to implement this but I have problems with coping with more than one streak in the vector. Should I use temporary vectors and then compare their lengths?
No you can do this in one pass through the vector and only storing the longest start point and length found so far. You also need much fewer than 'N' comparisons. *
hint: If you already have say a 4 long match ending at the 5th position (=6) and which position do you have to check next?
[*] left as exercise to the reader to work out what's the likely O( ) complexity ;-)
It would be interesting to see if the fact that the array is sorted can be exploited somehow to improve the algorithm. The first thing that comes to mind is this: if you know that all numbers in the input array are unique, then for a range of elements [i, j] in the array, you can immediately tell whether elements in that range are consecutive or not, without actually looking through the range. If this relation holds
array[j] - array[i] == j - i
then you can immediately say that elements in that range are consecutive. This criterion, obviously, uses the fact that the array is sorted and that the numbers don't repeat.
Now, we just need to develop an algorithm which will take advantage of that criterion. Here's one possible recursive approach:
Input of recursive step is the range of elements [i, j]. Initially it is [0, n-1] - the whole array.
Apply the above criterion to range [i, j]. If the range turns out to be consecutive, there's no need to subdivide it further. Send the range to output (see below for further details).
Otherwise (if the range is not consecutive), divide it into two equal parts [i, m] and [m+1, j].
Recursively invoke the algorithm on the lower part ([i, m]) and then on the upper part ([m+1, j]).
The above algorithm will perform binary partition of the array and recursive descent of the partition tree using the left-first approach. This means that this algorithm will find adjacent subranges with consecutive elements in left-to-right order. All you need to do is to join the adjacent subranges together. When you receive a subrange [i, j] that was "sent to output" at step 2, you have to concatenate it with previously received subranges, if they are indeed consecutive. Or you have to start a new range, if they are not consecutive. All the while you have keep track of the "longest consecutive range" found so far.
That's it.
The benefit of this algorithm is that it detects subranges of consecutive elements "early", without looking inside these subranges. Obviously, it's worst case performance (if ther are no consecutive subranges at all) is still O(n). In the best case, when the entire input array is consecutive, this algorithm will detect it instantly. (I'm still working on a meaningful O estimation for this algorithm.)
The usability of this algorithm is, again, undermined by the uniqueness requirement. I don't know whether it is something that is "given" in your case.
Anyway, here's a possible C++ implementation
typedef std::vector<int> vint;
typedef std::pair<vint::size_type, vint::size_type> range;
class longest_sequence
{
public:
const range& operator ()(const vint &v)
{
current = max = range(0, 0);
process_subrange(v, 0, v.size() - 1);
check_record();
return max;
}
private:
range current, max;
void process_subrange(const vint &v, vint::size_type i, vint::size_type j);
void check_record();
};
void longest_sequence::process_subrange(const vint &v,
vint::size_type i, vint::size_type j)
{
assert(i <= j && v[i] <= v[j]);
assert(i == 0 || i == current.second + 1);
if (v[j] - v[i] == j - i)
{ // Consecutive subrange found
assert(v[current.second] <= v[i]);
if (i == 0 || v[i] == v[current.second] + 1)
// Append to the current range
current.second = j;
else
{ // Range finished
// Check against the record
check_record();
// Start a new range
current = range(i, j);
}
}
else
{ // Subdivision and recursive calls
assert(i < j);
vint::size_type m = (i + j) / 2;
process_subrange(v, i, m);
process_subrange(v, m + 1, j);
}
}
void longest_sequence::check_record()
{
assert(current.second >= current.first);
if (current.second - current.first > max.second - max.first)
// We have a new record
max = current;
}
int main()
{
int a[] = { 1, 3, 4, 5, 6, 8, 9 };
std::vector<int> v(a, a + sizeof a / sizeof *a);
range r = longest_sequence()(v);
return 0;
}
I believe that this should do it?
size_t beginStreak = 0;
size_t streakLen = 1;
size_t longest = 0;
size_t longestStart = 0;
for (size_t i=1; i < len.size(); i++) {
if (vec[i] == vec[i-1] + 1) {
streakLen++;
}
else {
if (streakLen > longest) {
longest = streakLen;
longestStart = beginStreak;
}
beginStreak = i;
streakLen = 1;
}
}
if (streakLen > longest) {
longest = streakLen;
longestStart = beginStreak;
}
You can't solve this problem in less than O(N) time. Imagine your list is the first N-1 even numbers, plus a single odd number (chosen from among the first N-1 odd numbers). Then there is a single streak of length 3 somewhere in the list, but worst case you need to scan the entire list to find it. Even on average you'll need to examine at least half of the list to find it.
Similar to Rodrigo's solutions but solving your example as well:
#include <vector>
#include <cstdio>
#define len(x) sizeof(x) / sizeof(x[0])
using namespace std;
int nums[] = {1,3,4,5,6,8,9};
int streakBase = nums[0];
int maxStreakLength = 1;
void updateStreak(int currentStreakLength, int currentStreakBase) {
if (currentStreakLength > maxStreakLength) {
maxStreakLength = currentStreakLength;
streakBase = currentStreakBase;
}
}
int main(void) {
vector<int> v;
for(size_t i=0; i < len(nums); ++i)
v.push_back(nums[i]);
int lastBase = v[0], currentStreakBase = v[0], currentStreakLength = 1;
for(size_t i=1; i < v.size(); ++i) {
if (v[i] == lastBase + 1) {
currentStreakLength++;
lastBase = v[i];
} else {
updateStreak(currentStreakLength, currentStreakBase);
currentStreakBase = v[i];
lastBase = v[i];
currentStreakLength = 1;
}
}
updateStreak(currentStreakLength, currentStreakBase);
printf("maxStreakLength = %d and streakBase = %d\n", maxStreakLength, streakBase);
return 0;
}