Find the Xor value between two integers who value is 2 - algorithm

Given an array consisting of N integers. Is it possible to find the number
of (a[i],a[j]) pairs such that 1 <= i < j< = N and the bitwise Xor value is exactly 2 with a time complexity less than O(n^2) or is there any mathematical formula to find the number of pairs like a[i] ^ a[j] == 2.
Constraints
1≤N≤10^5
1≤Ai≤10^6

An efficient solution of this problem can be of O(n) time complexity. The idea is based on the fact that arr[i] ^ arr[j] is equal to 2 if and only if arr[i] ^ 2 is equal to arr[j].
1) Initialize result as 0.
2) Create an empty hash set "s".
3) Do following for each element arr[i] in arr[]
(a) If 2 ^ arr[i] is in "s", then increment result by 1.
(b) Insert arr[i] into the hash set "s".
3) return result.
Here is C++ implementation:
int xorPairCount(vector<int>& arr) {
int n= (int)arr.size();
int result = 0;
unordered_set<int> s;
for (int i = 0; i < n ; i++) {
// If there exist an element in set s
// with XOR equals to 2^arr[i], that means
// there exist an element such that the
// XOR of element with arr[i] is equal to
// 2, then increment count.
if (s.find(2^arr[i]) != s.end())
result++;
// Make element visited
s.insert(arr[i]);
}
return result;
}
Note that, for this solution, I assumed there is no duplicate in the array. If duplicate allowed, then the solution will be a bit different. Let me know.
Update
If there are duplicates in the array, use an hashmap instead of hashset to count the frequency of each number, because for each occurrence, there will be one count. Here is the update of the above code:
int xorPairCount(vector<int>& arr) {
int n= (int)arr.size();
int result = 0;
unordered_map<int, int> m;
for (int i = 0; i < n ; i++) {
int curr_xor = 2^arr[i];
if (m.find(curr_xor) != m.end())
result += m[curr_xor];
m[arr[i]]++;
}
return result;
}

Related

Looking for largest sum inside array

I have a given array [-2 -3 4 -1 -2 1 5 -3] so the largest sum would be 7 (numbers from 3rd to 7th index). This array is just a simple example, the program should be user input elements and length of the array.
My question is, how to determine which sum would be largest?
I created a sum from all numbers and the sum of only positive numbers and yet the positive sum would be great but I didn't used the -1 and -2 after that 3rd index because of the "IF statement" so my sum is 10 and the solution is not good.
I assume your questions is to find the contiguous subarray(containing at least one number) which has the largest sum. Otherwise, the problem is pretty trivial as you can just pick all the positive numbers.
There are 3 solutions that are better than the O(N^2) brute force solution. N is the length of the input array.
Dynamic programming. O(N) runtime, O(N) space
Since the subarray contains at least one number, we know that there are only N possible candidates: subarray that ends at A[0], A[1]...... A[N - 1]
For the subarray that ends at A[i], we have the following optimal substructure:
maxSum[i] = max of {maxSum[i - 1] + A[i], A[i]};
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
if(nums == null || nums.length == 0) {
return max;
}
int[] maxSum = new int[nums.length + 1];
for(int i = 1; i < maxSum.length; i++) {
maxSum[i] = Math.max(maxSum[i - 1] + nums[i - 1], nums[i - 1]);
}
for(int i = 1; i < maxSum.length; i++) {
max = Math.max(maxSum[i], max);
}
return max;
}
}
Prefix sum, O(N) runtime, O(1) space
Maintain a minimum sum variable as you iterate through the entire array. When visiting each number in the input array, update the prefix sum variable currSum. Then update the maximum sum and minimum sum shown in the following code.
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int maxSum = Integer.MIN_VALUE, currSum = 0, minSum = 0;
for(int i = 0; i < nums.length; i++) {
currSum += nums[i];
maxSum = Math.max(maxSum, currSum - minSum);
minSum = Math.min(minSum, currSum);
}
return maxSum;
}
}
Divide and conquer, O(N * logN) runtime
Divide the original problem into two subproblems and apply this principle recursively using the following formula.
Let A[0,.... midIdx] be the left half of A, A[midIdx + 1, ..... A.length - 1] be the right half of A. leftSumMax is the answer of the left subproblem, rightSumMax is the answer of the right subproblem.
The final answer will be one of the following 3:
1. only uses numbers from the left half (solved by the left subproblem)
2. only uses numbers from the right half (solved by the right subproblem)
3. uses numbers from both left and right halves (solved in O(n) time)
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0)
{
return 0;
}
return maxSubArrayHelper(nums, 0, nums.length - 1);
}
private int maxSubArrayHelper(int[] nums, int startIdx, int endIdx){
if(startIdx == endIdx){
return nums[startIdx];
}
int midIdx = startIdx + (endIdx - startIdx) / 2;
int leftMax = maxSubArrayHelper(nums, startIdx, midIdx);
int rightMax = maxSubArrayHelper(nums, midIdx + 1, endIdx);
int leftIdx = midIdx, rightIdx = midIdx + 1;
int leftSumMax = nums[leftIdx], rightSumMax = nums[rightIdx];
int leftSum = nums[leftIdx], rightSum = nums[rightIdx];
for(int i = leftIdx - 1; i >= startIdx; i--){
leftSum += nums[i];
leftSumMax = Math.max(leftSumMax, leftSum);
}
for(int j = rightIdx + 1; j <= endIdx; j++){
rightSum += nums[j];
rightSumMax = Math.max(rightSumMax, rightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax + rightSumMax);
}
}
Try this:
locate the first positive number, offset i.
add the following positive numbers, giving a sum of sum, last offset is j. If this sum is greater than your current best sum, it becomes the current best sum with offsets i to j.
add the negative numbers that follow until you get another positive number. If this negative sum is greater in absolute value than sum, start a new sum at this offset, otherwise continue with the current sum.
go back to step 2.
Stop this when you get to the end of the array. The best positive sum has been found.
If no positive sum can be found, locate the least negative value, this single entry would be your best non-trivial sum.

Find the subarray within an array (containing at least TWO number) which has the largest sum

Find the subarray within an array (containing at least TWO number) which has the largest sum.
For example, given the array [-2,-1,-3,-4,-1],
the contiguous subarray [-2,-1] has the largest sum = -3.
try to do it in O(n) time
Followup, if input is stream, how to solve it
public int maxSubArray(int[] nums) {}
For an Array of size (N). Let us call it A
You can create another array B where you will store the sum so Far.
Now traverse through the parent Array.
int max = Integer.MIN;
B[0] = A[0];
for(i=1;i<A.length;i++)
{
if(A[i] > 0){
B[i]=B[i-1] + A[i];
}else if(A[i]+B[i-1] > max){
B[i] = A[i]+B[i-1]
max = A[i]+B[i-1]
}
else{
B[i] = A[i];
}
Now the max number in Array B has the max possible sum of the consecutive sub Array but you don't know the Sub Array.
You can use Kadane's Algorithm in modified fashion.
You can find Kadane' Algorithm here. (You will store the ends of the subarray too).
How can we modify it?
-> Just keep in track of the window size you are taking i.e. RIGHT-LEFT>=1
I think this should help for all set of numbers including negative.
Still for all negative numbers (which you can check in an O(n) go). Just loop FROM o to N : maximum = max(arr[i]+arr[i+1],maximum);
Just to ensure if the case gets covered.
Something like this should work:
int maxvalue = int.MIN_VALUE;
for (int i = 0; i < N; i++)
for (int j = i + 1; j < N; j++) {
int value = 0;
for (int x = i; x <= j; x++)
value += array[x];
if (value > maxvalue)
maxvalue = value;
}
return maxvalue;

Sort a given array whose elements range from 1 to n , in which one element is missing and one is repeated

I have to sort this array in O(n) time and O(1) space.
I know how to sort an array in O(n) but that doesn't work with missing and repeated numbers. If I find the repeated and missing numbers first (It can be done in O(n)) and then sort , that seems costly.
static void sort(int[] arr)
{
for(int i=0;i<arr.length;i++)
{
if(i>=arr.length)
break;
if(arr[i]-1 == i)
continue;
else
{
while(arr[i]-1 != i)
{
int temp = arr[arr[i]-1];
arr[arr[i]-1] = arr[i];
arr[i] = temp;
}
}
}
}
First, you need to find missing and repeated numbers. You do this by solving following system of equations:
Left sums are computed simultaneously by making one pass over array. Right sums are even simpler -- you may use formulas for arithmetic progression to avoid looping. So, now you have system of two equations with two unknowns: missing number m and repeated number r. Solve it.
Next, you "sort" array by filling it with numbers 1 to n left to right, omitting m and duplicating r. Thus, overall algorithm requires only two passes over array.
void sort() {
for (int i = 1; i <= N; ++i) {
while (a[i] != a[a[i]]) {
std::swap(a[i], a[a[i]]);
}
}
for (int i = 1; i <= N; ++i) {
if (a[i] == i) continue;
for (int j = a[i] - 1; j >= i; --j) a[j] = j + 1;
for (int j = a[i] + 1; j <= i; ++j) a[j] = j - 1;
break;
}
}
Explanation:
Let's denote m the missing number and d the duplicated number
Please note in the while loop, the break condition is a[i] != a[a[i]] which covers both a[i] == i and a[i] is a duplicate.
After the first for, every non-duplicate number i is encountered 1-2 time and moved into the i-th position of the array at most 1 time.
The first-found number d is moved to d-th position, at most 1 time
The second d is moved around at most N-1 times and ends up in m-th position because every other i-th slot is occupied by number i
The second outer for locate the first i where a[i] != i. The only i satisfies that is i = m
The 2 inner fors handle 2 cases where m < d and m > d respectively
Full implementation at http://ideone.com/VDuLka
After
int temp = arr[arr[i]-1];
add a check for duplicate in the loop:
if((temp-1) == i){ // found duplicate
...
} else {
arr[arr[i]-1] = arr[i];
arr[i] = temp;
}
See if you can figure out the rest of the code.

Longest positive sum substring

I was wondering how could I get the longest positive-sum subsequence in a sequence:
For example I have -6 3 -4 4 -5, so the longest positive subsequence is 3 -4 4. In fact the sum is positive (3), and we couldn't add -6 neither -5 or it would have become negative.
It could be easily solvable in O(N^2), I think could exist something much more faster, like in O(NlogN)
Do you have any idea?
EDIT: the order must be preserved, and you can skip any number from the substring
EDIT2: I'm sorry if I caused confusion using the term "sebsequence", as #beaker pointed out I meant substring
O(n) space and time solution, will start with the code (sorry, Java ;-) and try to explain it later:
public static int[] longestSubarray(int[] inp) {
// array containing prefix sums up to a certain index i
int[] p = new int[inp.length];
p[0] = inp[0];
for (int i = 1; i < inp.length; i++) {
p[i] = p[i - 1] + inp[i];
}
// array Q from the description below
int[] q = new int[inp.length];
q[inp.length - 1] = p[inp.length - 1];
for (int i = inp.length - 2; i >= 0; i--) {
q[i] = Math.max(q[i + 1], p[i]);
}
int a = 0;
int b = 0;
int maxLen = 0;
int curr;
int[] res = new int[] {-1,-1};
while (b < inp.length) {
curr = a > 0 ? q[b] - p[a-1] : q[b];
if (curr >= 0) {
if(b-a > maxLen) {
maxLen = b-a;
res = new int[] {a,b};
}
b++;
} else {
a++;
}
}
return res;
}
we are operating on input array A of size n
Let's define array P as the array containing the prefix sum until index i so P[i] = sum(0,i) where `i = 0,1,...,n-1'
let's notice that if u < v and P[u] <= P[v] then u will never be our ending point
because of the above we can define an array Q which has Q[n-1] = P[n-1] and Q[i] = max(P[i], Q[i+1])
now let's consider M_{a,b} which shows us the maximum sum subarray starting at a and ending at b or beyond. We know that M_{0,b} = Q[b] and that M_{a,b} = Q[b] - P[a-1]
with the above information we can now initialise our a, b = 0 and start moving them. If the current value of M is bigger or equal to 0 then we know we will find (or already found) a subarray with sum >= 0, we then just need to compare b-a with the previously found length. Otherwise there's no subarray that starts at a and adheres to our constraints so we need to increment a.
Let's make a naive implementation and then improve it.
We move from the left to the right calculating partial sums and for each position we find the most-left partial sum such as the current partial sum is greater than that.
input a
int partialSums[len(a)]
for i in range(len(a)):
partialSums[i] = (i == 0 ? 0 : partialSums[i - 1]) + a[i]
if partialSums[i] > 0:
answer = max(answer, i + 1)
else:
for j in range(i):
if partialSums[i] - partialSums[j] > 0:
answer = max(answer, i - j)
break
This is O(n2). Now the part of finding the left-most "good" sum could be actually maintained via BST, where each node would be represented as a pair (partial sum, index) with a comparison by partial sum. Also each node should support a special field min that would be the minimum of indices in this subtree.
Now instead of the straightforward search of an appropriate partial sum we could descend the BST using the current partial sum as a key following the next three rules (assuming C is the current node, L and R are the roots of the left and the right subtrees respectively):
Maintain the current minimal index of "good" partial sums found in curMin, initially +∞.
If C.partial_sum is "good" then update curMin with C.index.
If we go to R then update curMin with L.min.
And then update the answer with i - curMin, also add the current partial sum to the BST.
That would give us O(n * log n).
We can easily have a O(n log n) solution for longest subsequence.
First, sort the array, remember their indexes.
Pick all the largest numbers, stop when their sum are negative, and you have your answer.
Recover their original order.
Pseudo code
sort(data);
int length = 0;
long sum = 0;
boolean[] result = new boolean[n];
for(int i = n ; i >= 1; i--){
if(sum + data[i] <= 0)
break;
sum += data[i];
result[data[i].index] = true;
length++;
}
for(int i = 1; i <= n; i++)
if(result[i])
print i;
So, rather than waiting, I will propose a O(n log n) solution for longest positive substring.
First, we create an array prefix which is the prefix sum of the array.
Second, we using binary search to look for the longest length that has positive sum
Pseudocode
int[]prefix = new int[n];
for(int i = 1; i <= n; i++)
prefix[i] = data[i];
if(i - 1 >= 1)
prefix[i] += prefix[i - 1];
int min = 0;
int max = n;
int result = 0;
while(min <= max){
int mid = (min + max)/2;
boolean ok = false;
for(int i = 1; i <= n; i++){
if(i > mid && pre[i] - pre[i - mid] > 0){//How we can find sum of segment with mid length, and end at index i
ok = true;
break;
}
}
if(ok){
result = max(result, mid)
min = mid + 1;
}else{
max = mid - 1;
}
}
Ok, so the above algorithm is wrong, as pointed out by piotrekg2 what we need to do is
create an array prefix which is the prefix sum of the array.
Sort the prefix array, and we need to remember the index of the prefix array.
Iterate through the prefix array, storing the minimum index we meet so far, the maximum different between the index is the answer.
Note: when we comparing value in prefix, if two indexes have equivalent values, so which has smaller index will be considered larger, this will avoid the case when the sum is 0.
Pseudo code:
class Node{
int val, index;
}
Node[]prefix = new Node[n];
for(int i = 1; i <= n; i++)
prefix[i] = new Node(data[i],i);
if(i - 1 >= 1)
prefix[i].val += prefix[i - 1].val;
sort(prefix);
int min = prefix[1].index;
int result = 0;
for(int i = 2; i <= n; i ++)
if(prefix[i].index > min)
result = max(prefix[i].index - min + 1, result)
min = min(min, prefix[i].index);

longest nondecreasing subsequence in O(nlgn)

I have the following algorithm which works well
I tried explaining it here for myself http://nemo.la/?p=943 and it is explained here http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/ as well and on stackoverflow as well
I want to modify it to produce the longest non-monotonically increasing subsequence
for the sequence 30 20 20 10 10 10 10
the answer should be 4: "10 10 10 10"
But the with nlgn version of the algorithm it isn't working. Initializing s to contain the first element "30" and starting at the second element = 20. This is what happens:
The first step: 30 is not greater than or equal to 20. We find the smallest element greater than 20. The new s becomes "20"
The second step: 20 is greater than or equal to 20. We extend the sequence and s now contains "20 20"
The third step: 10 is not greater than or equal to 20. We find the smallest element greater than 10 which is "20". The new s becomes "10 20"
and s will never grow after that and the algorithm will return 2 instead of 4
int height[100];
int s[100];
int binary_search(int first, int last, int x) {
int mid;
while (first < last) {
mid = (first + last) / 2;
if (height[s[mid]] == x)
return mid;
else if (height[s[mid]] >= x)
last = mid;
else
first = mid + 1;
}
return first; /* or last */
}
int longest_increasing_subsequence_nlgn(int n) {
int i, k, index;
memset(s, 0, sizeof(s));
index = 1;
s[1] = 0; /* s[i] = 0 is the index of the element that ends an increasing sequence of length i = 1 */
for (i = 1; i < n; i++) {
if (height[i] >= height[s[index]]) { /* larger element, extend the sequence */
index++; /* increase the length of my subsequence */
s[index] = i; /* the current doll ends my subsequence */
}
/* else find the smallest element in s >= a[i], basically insert a[i] in s such that s stays sorted */
else {
k = binary_search(1, index, height[i]);
if (height[s[k]] >= height[i]) { /* if truly >= greater */
s[k] = i;
}
}
}
return index;
}
To find the longest non-strictly increasing subsequence, change these conditions:
If A[i] is smallest among all end candidates of active lists, we will start new active list of length 1.
If A[i] is largest among all end candidates of active lists, we will clone the largest active list, and extend it by A[i].
If A[i] is in between, we will find a list with largest end element that is smaller than A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list.
to:
If A[i] is smaller than the smallest of all end candidates of active lists, we will start new active list of length 1.
If A[i] is largest among all end candidates of active lists, we will clone the largest active list, and extend it by A[i].
If A[i] is in between, we will find a list with largest end element that is smaller than or equal to A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list.
The fourth step for your example sequence should be:
10 is not less than 10 (the smallest element). We find the largest element that is smaller than or equal to 10 (that would be s[0]==10). Clone and extend this list by 10. Discard the existing list of length 2. The new s becomes {10 10}.
Your code nearly works except a problem in your binary_search() function, this function should return the index of the first element that's greater than the target element(x) since you want the longest non-decreasing sequence. Modify it to this, it'll be OK.
If you use c++, std::lower_bound() and std::upper_bound() will help you get rid of this confusing problem. By the way, the if statement"if (height[s[k]] >= height[i])" is superfluous.
int binary_search(int first, int last, int x) {
while(last > first)
{
int mid = first + (last - first) / 2;
if(height[s[mid]] > x)
last = mid;
else
first = mid + 1;
}
return first; /* or last */
}
Just apply the longest increasing sub-sequence algorithm to ordered pair (A[i], i), by using a lexicographic compare.
My Java version:
public static int longestNondecreasingSubsequenceLength(List<Integer> A) {
int n = A.size();
int dp[] = new int[n];
int max = 0;
for(int i = 0; i < n; i++) {
int el = A.get(i);
int idx = Arrays.binarySearch(dp, 0, max, el);
if(idx < 0) {
idx = -(idx + 1);
}
if(dp[idx] == el) { // duplicate found, let's find the last one
idx = Arrays.binarySearch(dp, 0, max, el + 1);
if(idx < 0) {
idx = -(idx + 1);
}
}
dp[idx] = el;
if(idx == max) {
max++;
}
}
return max;
}
A completely different solution to this problem is the following. Make a copy of the array and sort it. Then, compute the minimum nonzero difference between any two elements of the array (this will be the minimum nonzero difference between two adjacent array elements) and call it δ. This step takes time O(n log n).
The key observation is that if you add 0 to element 0 of the original array, δ/n to the second element of the original array, 2δ/n to the third element of the array, etc., then any nondecreasing sequence in the original array becomes a strictly increasing sequence in the new array and vice-versa. Therefore, you can transform the array this way, then run a standard longest increasing subsequence solver, which runs in time O(n log n). The net result of this process is an O(n log n) algorithm for finding the longest nondecreasing subsequence.
For example, consider 30, 20, 20, 10, 10, 10, 10. In this case δ = 10 and n = 7, so δ / n &approx; 1.42. The new array is then
40, 21.42, 22.84, 14.28, 15.71, 17.14, 18.57
Here, the LIS is 14.28, 15.71, 17.14, 18.57, which maps back to 10, 10, 10, 10 in the original array.
Hope this helps!
I have my simple solution for the longest non-decreasing subsequence using upper bound function in c++.
Time complexity (nlogn)
int longest(vector<long long> a) {
vector<long long> s;
s.push_back(a[0]);
int n = a.size();
int len = 1;
for (int i = 1; i < n; i++) {
int idx = upper_bound(s.begin(), s.end(), a[i]) - s.begin();
int m = s.size();
if (m > idx) {
s[idx] = a[i];
} else {
s.push_back(a[i]);
}
}
return s.size();
}
If you know the algorithm for LIS, then changing inequalities in the code, gives the Longest Non-Decreasing subsequence.
Code for LIS:
public int ceilIndex(int []a, int n, int t[], int ele){
int l=-1, r=n+1;
while(r-l>1){
int mid=l+(r-l)/2;
if(a[t[mid]]<ele) l=mid;
else r=mid;
}
return r;
}
public int lengthOfLIS(int[] a) {
int n=a.length;
int index[]=new int[n];
int len=0;
index[len]=0;
int reversePath[]=new int[n];
for(int i=0;i<n;i++) reversePath[i]=-1;
for(int i=1;i<n;i++){
if(a[index[0]]>=a[i]){
index[0]=i;
reversePath[i]=-1;
}else if(a[index[len]]<a[i]){
reversePath[i]=index[len];
len++;
index[len]=i;
}else{
int idx=ceilIndex(a, len, index, a[i]);
reversePath[i]=index[idx-1];
index[idx]=i;
}
}
for(int i=0;i<n;i++) System.out.print(reversePath[i]+" ");
System.out.println();
// printing the LIS in reverseFashion
// we iterate the indexes in reverse
int idx=index[len];
while(idx!=-1){
System.out.print(a[idx]+" ");
idx=reversePath[idx];
}
return len+1;
}
Code for Longest Non-Decreasing subsequence:
public int ceilIndex(int []a, int n, int t[], int ele){
int l=-1, r=n+1;
while(r-l>1){
int mid=l+(r-l)/2;
if(a[t[mid]]<=ele) l=mid;
else r=mid;
}
return r;
}
public int lengthOfLongestNonDecreasingSubsequence(int[] a) {
int n=a.length;
int index[]=new int[n];
int len=0;
index[len]=0;
int reversePath[]=new int[n];
for(int i=0;i<n;i++) reversePath[i]=-1;
for(int i=1;i<n;i++){
if(a[index[0]]>a[i]){
index[0]=i;
reversePath[i]=-1;
}else if(a[index[len]]<=a[i]){
reversePath[i]=index[len];
len++;
index[len]=i;
}else{
int idx=ceilIndex(a, len, index, a[i]);
reversePath[i]=index[idx-1];
index[idx]=i;
}
}
for(int i=0;i<n;i++) System.out.print(reversePath[i]+" ");
System.out.println();
// printing the LIS in reverseFashion
// we iterate the indexes in reverse
int idx=index[len];
while(idx!=-1){
System.out.print(a[idx]+" ");
idx=reversePath[idx];
}
return len+1;
}

Resources