I have a sorted (ascending) array of real values, call it a (duplicates possible). I wish to find, given a range of values [x, y], all indices of values (i) for which an index j exists such that:
j>i and
x <= a[j]-a[i] <= y
Or simply put, find values in which exists a “forward difference” within a given range.
The output is a Boolean array of length a.Length.
Since the array is sorted all forward differences, x and y are positive.
The best I’ve managed to do is start from each index looking at the subarray in front of it and perform a binary search for x+a[i] and check if a[j]<=y+a[i]. I think this is O(n log n).
Is there a better approach? Or something I can do to speed things up.
I should note that eventually I want to perform the search for many such ranges [x,y] over the same array a, but the number of ranges is very much smaller than the length of the array (4-6 orders of magnitude smaller) - therefore I’m far more concerned with the complexity of the search.
Example:
a= 0, 1, 46, 100, 185, 216, 285
with range x,y=[99,101] should return:
[true, true, false, false, true, false, false]
For only values 0,1 and 185 have a forward difference within the range.
Code from memory, might have some bugs:
int bin_search_closesmaller(int arr[], int key, int low, int high)
{
if (low > high) return high;
int mid = (high - low)/2;
if (arr[mid] > key) return bin_search_closesmaller(arr, key, low, mid - 1);
if (arr[mid] < key) return bin_search_closesmaller(arr, key, mid + 1, high);
return mid;
}
bool[] findDiffs(int[] a, int x, int y)
{
bool[] result = new bool[a.Length];
for(int i=0; i<a.Length-1;i++)
{
int idx=bin_search_closesmaller(a, y+a[i], i+1, a.Length-1);
if (idx==-1) continue;
if (a[idx]-a[i] >= x) result[i]=true;
}
}
Thanks!
Make two indexes left and right and walk through array. Right index moves until it goes out of range for current left one, then check whether previous element is in range. Indexes move only forward, so algorithm is linear
right=2
for left = 0 to n-1:
while A[right] < A[left] + MaxRangeValue
right++
Result[left] = (A[right - 1] <= A[left] + MinRangeValue)
Another point of view on this algorithm:
-while difference is too low, increment right
-while difference is too high, increment left
As long as the input array is sorted, there is a linear solution to the problem. The key is to use two indexes to traverse of the array a.
bool[] findDiffs(int[] a, int x, int y)
{
bool[] result = new boolean[a.Length];
int j = 0;
for (int i = 0; i < a.Length; ++i) {
while (j < a.Length && a[j] - a[i] < x) {
++j;
}
if (j < a.Length) {
result[i] = a[j] - a[i] <= y;
}
}
return result;
}
With a = [0,100,1000,1100] and (x,y) = (99,100):
i = 0, j = 0 => a[j] - a[i] = 0 < x=99 => ++j
i = 0, j = 1 => a[j] - a[i] = 100 <= y=100 => result[i] = true; ++i
i = 1, j = 1 => a[j] - a[i] = 0 < x=99 => ++j
i = 1, j = 2 => a[j] - a[i] = 900 > y=100 => result[i] = false; ++i
i = 2, j = 2 => a[j] - a[i] = 0 <= x=99 => ++j
i = 2, j = 3 => a[j] - a[i] = 100 <= y=100 => result[i] = true; ++i
i = 3, j = 3 => a[j] - a[i] = 0 <= x=99 => exit loop
Related
Problem statement:
Given an array of non-negative integers, count the number of unordered pairs of array elements, such that their bitwise AND is a power of 2.
Example:
arr = [10, 7, 2, 8, 3]
Answer: 6 (10&7, 10&2, 10&8, 10&3, 7&2, 2&3)
Constraints:
1 <= arr.Count <= 2*10^5
0 <= arr[i] <= 2^12
Here's my brute-force solution that I've come up with:
private static Dictionary<int, bool> _dictionary = new Dictionary<int, bool>();
public static long CountPairs(List<int> arr)
{
long result = 0;
for (var i = 0; i < arr.Count - 1; ++i)
{
for (var j = i + 1; j < arr.Count; ++j)
{
if (IsPowerOfTwo(arr[i] & arr[j])) ++result;
}
}
return result;
}
public static bool IsPowerOfTwo(int number)
{
if (_dictionary.TryGetValue(number, out bool value)) return value;
var result = (number != 0) && ((number & (number - 1)) == 0);
_dictionary[number] = result;
return result;
}
For small inputs this works fine, but for big inputs this works slow.
My question is: what is the optimal (or at least more optimal) solution for the problem? Please provide a graceful solution in C#. 😊
One way to accelerate your approach is to compute the histogram of your data values before counting.
This will reduce the number of computations for long arrays because there are fewer options for value (4096) than the length of your array (200000).
Be careful when counting bins that are powers of 2 to make sure you do not overcount the number of pairs by including cases when you are comparing a number with itself.
We can adapt the bit-subset dynamic programming idea to have a solution with O(2^N * N^2 + n * N) complexity, where N is the number of bits in the range, and n is the number of elements in the list. (So if the integers were restricted to [1, 4096] or 2^12, with n at 100,000, we would have on the order of 2^12 * 12^2 + 100000*12 = 1,789,824 iterations.)
The idea is that we want to count instances for which we have overlapping bit subsets, with the twist of adding a fixed set bit. Given Ai -- for simplicity, take 6 = b110 -- if we were to find all partners that AND to zero, we'd take Ai's negation,
110 -> ~110 -> 001
Now we can build a dynamic program that takes a diminishing mask, starting with the full number and diminishing the mask towards the left
001
^^^
001
^^
001
^
Each set bit on the negation of Ai represents a zero, which can be ANDed with either 1 or 0 to the same effect. Each unset bit on the negation of Ai represents a set bit in Ai, which we'd like to pair only with zeros, except for a single set bit.
We construct this set bit by examining each possibility separately. So where to count pairs that would AND with Ai to zero, we'd do something like
001 ->
001
000
we now want to enumerate
011 ->
011
010
101 ->
101
100
fixing a single bit each time.
We can achieve this by adding a dimension to the inner iteration. When the mask does have a set bit at the end, we "fix" the relevant bit by counting only the result for the previous DP cell that would have the bit set, and not the usual union of subsets that could either have that bit set or not.
Here is some JavaScript code (sorry, I do not know C#) to demonstrate with testing at the end comparing to the brute-force solution.
var debug = 0;
function bruteForce(a){
let answer = 0;
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j < a.length; j++) {
let and = a[i] & a[j];
if ((and & (and - 1)) == 0 && and != 0){
answer++;
if (debug)
console.log(a[i], a[j], a[i].toString(2), a[j].toString(2))
}
}
}
return answer;
}
function f(A, N){
const n = A.length;
const hash = {};
const dp = new Array(1 << N);
for (let i=0; i<1<<N; i++){
dp[i] = new Array(N + 1);
for (let j=0; j<N+1; j++)
dp[i][j] = new Array(N + 1).fill(0);
}
for (let i=0; i<n; i++){
if (hash.hasOwnProperty(A[i]))
hash[A[i]] = hash[A[i]] + 1;
else
hash[A[i]] = 1;
}
for (let mask=0; mask<1<<N; mask++){
// j is an index where we fix a 1
for (let j=0; j<=N; j++){
if (mask & 1){
if (j == 0)
dp[mask][j][0] = hash[mask] || 0;
else
dp[mask][j][0] = (hash[mask] || 0) + (hash[mask ^ 1] || 0);
} else {
dp[mask][j][0] = hash[mask] || 0;
}
for (let i=1; i<=N; i++){
if (mask & (1 << i)){
if (j == i)
dp[mask][j][i] = dp[mask][j][i-1];
else
dp[mask][j][i] = dp[mask][j][i-1] + dp[mask ^ (1 << i)][j][i - 1];
} else {
dp[mask][j][i] = dp[mask][j][i-1];
}
}
}
}
let answer = 0;
for (let i=0; i<n; i++){
for (let j=0; j<N; j++)
if (A[i] & (1 << j))
answer += dp[((1 << N) - 1) ^ A[i] | (1 << j)][j][N];
}
for (let i=0; i<N + 1; i++)
if (hash[1 << i])
answer = answer - hash[1 << i];
return answer / 2;
}
var As = [
[10, 7, 2, 8, 3] // 6
];
for (let A of As){
console.log(JSON.stringify(A));
console.log(`DP, brute force: ${ f(A, 4) }, ${ bruteForce(A) }`);
console.log('');
}
var numTests = 1000;
for (let i=0; i<numTests; i++){
const N = 6;
const A = [];
const n = 10;
for (let j=0; j<n; j++){
const num = Math.floor(Math.random() * (1 << N));
A.push(num);
}
const fA = f(A, N);
const brute = bruteForce(A);
if (fA != brute){
console.log('Mismatch:');
console.log(A);
console.log(fA, brute);
console.log('');
}
}
console.log("Done testing.");
int[] numbers = new[] { 10, 7, 2, 8, 3 };
static bool IsPowerOfTwo(int n) => (n != 0) && ((n & (n - 1)) == 0);
long result = numbers.AsParallel()
.Select((a, i) => numbers
.Skip(i + 1)
.Select(b => a & b)
.Count(IsPowerOfTwo))
.Sum();
If I understand the problem correctly, this should work and should be faster.
First, for each number in the array we grab all elements in the array after it to get a collection of numbers to pair with.
Then we transform each pair number with a bitwise AND, then counting the number that satisfy our 'IsPowerOfTwo;' predicate (implementation here).
Finally we simply get the sum of all the counts - our output from this case is 6.
I think this should be more performant than your dictionary based solution - it avoids having to perform a lookup each time you wish to check power of 2.
I think also given the numerical constraints of your inputs it is fine to use int data types.
I am trying to figure out how to assign points based on adjacent number values in an array. By default, each number is worth one point, and it increases in value if the adjacent numbers are lower than the current number.
For values at the start and the end of the array, the adjacent values are the end and start, so for numbers[0] adjacent values are numbers[5] && numbers[1] and for numbers[5] the values would be numbers[4] && numbers[0]. Consider it going in a circle.
As an example of numbers let's say we have int[] numbers = new int[] { 5, 6, 4, 2, 5, 6 }; after point allocation the output should be something like 1 3 2 1 2 3.
The issue I'm facing is that I don't know how to write the code in such a way that I don't get an error. And I would like to avoid using a lot of if nested functions. Managed to get it working like that but it looks horrible, so scrapped that and figured there must be a better way of doing this but I seem to be stuck...
static int[] AssignPoints (int[] numbers) {
int[] points = new int[numbers.Length];
for (int i = 0; i < numbers.Length; i++) {
points[i]++; //allocating initial point
???
}
return points;
}
static int[] AssignPoints (int[] numbers) {
int[] points = new int[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
int prevIndex = (i-1 < 0 ? numbers.Length -1 : i-1);
int nextIndex = (i+1 >= numbers.Length ? 0 : i + 1);
if (numbers[i] > numbers[prevIndex])
points[i]++;
if (numbers[i] > numbers[nextIndex])
points[i]++;
}
return points;
}
A very explicit example:
static int[] AssignPoints (int[] numbers) {
int[] points = new int[numbers.Length];
for (int i = 0; i < numbers.Length; i++) {
var leftIndex = i == 0 ? numbers.Length - 1 : i - 1;
var rightIndex = i == numbers.Length - 1 ? 0 : i + 1;
points[i] = 1
+ (numbers[i] > numbers[leftIndex] ? 1 : 0)
+ (numbers[i] > numbers[rightIndex] ? 1 : 0);
}
return points;
}
static List<int> AssignPoints(List<int> numbers)
{
List<int> points =new List<int>(numbers.Capacity);
int i = 0, point;
foreach (int item in numbers)
{
point = 1;
if(i != 0)
if (numbers[i - 1] < numbers[i]) point++;
if(i != numbers.Capacity -1)
if (numbers[i + 1] < numbers[i]) point++;
i++;
points.Add(point);
}
return points;
}
I want to output the number of slices required to slice an unsorted array of n distinct integers into one or more slices and sort them so that when the sorted slices are joined back (in the same order), it gives the original array in the sorted order.
For example,
Given array = [2,1,6,4,3,7]
If you slice the given array like this : [2,1] [6,4,3] [7] Then sort these individually like this: [1,2] [3,4,6] [7] And finally, join them back like this : [1,2,3,4,6,7] You get the original array in sorted order. So, the number of slices is 3
I tried to search it in Stack Overflow/Google and found the following solution but it doesn't seem to work for the above input (returns 2 instead of 3).
public int solution(int[] A)
{
if (A.Length < 3) return A.Length;
int count = 0;
for (int i = 1; i < A.Length; i++)
{
if (A[i] > A[i - 1]) count += 1;
}
return count;
}
Can anyone suggest how can we approach this problem and appropriately solve this in C#
public int solution(int[] A) {
int l = A.length;
if (l < 3) return l;
int count = 0;
for (int i = 1; i < l; i++) {
if (A[i] > A[i - 1]) count += 1;
}
if (A[l - 1] > A[l - 2]) {
count += 1;
}
return count;
}
I'm trying to solve the below problem in C# which I was unable to answer within the time limit during a technical interview.
The provided code contains a bug and it can only be fixed by amending 2 lines of code at most.
The function takes 2 integer arrays as parameters.
All integers within both parameters will always be positive integers.
There may be multiple occurrences of the same integer in each array parameter.
The function should return the lowest positive integer that exists in both arrays.
The function should return -1 if no such integer exists
public int test(int[] A, int[] B)
{
int m = A.Length;
int n = B.Length;
Array.Sort(A);
Array.Sort(B);
int i = 0;
for (int k = 0; k < m; k++)
{
if (i < n - 1 && B[i] < A[k])
i += 1;
if (A[k] == B[i])
return A[k];
}
return -1;
}
I'm struggling to come up with a solution that only amends 1-2 lines of code. I thought I could replace i += 1; with i += 1; k = 0; but this is obviously adding a new line.
The original code will work for some inputs but not something like the below example because we don't want to increase k when B[i] < A[k]:
int[] A = { 3, 4, 5, 6 };
int[] B = { 2, 2, 2, 3 ,5 };
Considering you can only amend the code and not add new lines to it, I believe the following should be working:
public int test(int[] A, int[] B)
{
int m = A.Length;
int n = B.Length;
Array.Sort(A);
Array.Sort(B);
int i = 0;
for (int k = 0; k < m; k++)
{
while (i < n - 1 && B[i] < A[k])
{
i += 1;
}
if (A[k] == B[i])
return A[k];
}
return -1;
}
What changed is that the if that was checking for i is now a while
It's not exactly the prettiest code, but since those are the requirements...
If A, B, and C are all classes in memory and the array is elements 0-2:
[0] = A
[1] = B
[2] = C
I want to shift the array so that it turns into this:
[0] = C
[1] = A
[2] = B
I would want to be able to go either direction, but I'd assume if someone could point me towards how to do it in one direction I can figure out the other.
Thought I should mention, I need this without iteration if at all possible.
This is for a 3D game of pseudo-infinite terrain. Each object in the arrays are chunks of terrain data. I want to shift them as they contain extremely large jagged arrays with a significant amount of data each. As the player moves, I have terrain sliding (in to/out of) memory. I never considered the performance hit of doing only an array.copy to shift arrays followed by completely rebuilding the next series of chunks.
So to eliminate this relatively minor performance issue, I wanted to shift the arrays with wrapping as described and instead of rebuilding the whole next series of chunks by re-allocating memory, I'm going to re-use the huge jagged arrays mentioned by copying default values into them rather than completely reinitializing them.
For kicks so you can see what I was doing before:
public void ShiftChunks(strVector2 ChunkOffset) {
while (ChunkOffset.X < 0) {
Array.Copy(Chunks, 0, Chunks, 1, Chunks.Length - 1);
for (int X = 1; X < maxChunkArraySize; X++)
for (int Z = 0; Z < maxChunkArraySize; Z++)
Chunks[X][Z].SetArrayPosition(X, Z);
Chunks[0] = new clsChunk[maxChunkArraySize];
for (int Z = 0; Z < maxChunkArraySize; Z++)
Chunks[0][Z] = new clsChunk(0, Z);
ChunkOffset.X++;
}
while (ChunkOffset.X > 0) {
Array.Copy(Chunks, 1, Chunks, 0, Chunks.Length - 1);
for (int X = 0; X < maxChunkArraySize - 1; X++)
for (int Z = 0; Z < maxChunkArraySize; Z++)
Chunks[X][Z].SetArrayPosition(X, Z);
Chunks[maxChunkArraySize - 1] = new clsChunk[maxChunkArraySize];
for (int Z = 0; Z < maxChunkArraySize; Z++)
Chunks[maxChunkArraySize - 1][Z] = new clsChunk(maxChunkArraySize - 1, Z);
ChunkOffset.X--;
}
while (ChunkOffset.Z < 0) {
for (int X = 0; X < maxChunkArraySize; X++) {
Array.Copy(Chunks[X], 0, Chunks[X], 1, Chunks[X].Length - 1);
for (int Z = 1; Z < maxChunkArraySize; Z++)
Chunks[X][Z].SetArrayPosition(X, Z);
Chunks[X][0] = new clsChunk(X, 0);
}
ChunkOffset.Z++;
}
while (ChunkOffset.Z > 0) {
for (int X = 0; X < maxChunkArraySize; X++) {
Array.Copy(Chunks[X], 1, Chunks[X], 0, Chunks[X].Length - 1);
for (int k = 0; k < maxChunkArraySize - 1; k++)
Chunks[X][k].SetArrayPosition(X, k);
Chunks[X][maxChunkArraySize - 1] = new clsChunk(X, maxChunkArraySize - 1);
}
ChunkOffset.Z--;
}
}
If anyone would like to give opinions on how I might do this even better or how to optimize the code further, feel free to let me know.
static void Rotate<T>(T[] source)
{
var temp = source[source.Length - 1];
Array.Copy(source, 0, source, 1, source.Length - 1);
source[0] = temp;
}
I happen to have created the exact thing for this just a few days ago:
private static T[] WrapAround<T>(T[] arr, int amount) {
var newArr = new T[arr.Length];
while (amount > 1) {
for (var i = 0; i < arr.Length; i++) {
if (i != 0) {
newArr[i] = arr[i - 1];
}
if (i == 0) {
newArr[i] = arr[arr.Length - 1];
}
}
arr = (T[]) newArr.Clone();
amount--;
}
return newArr;
}
Edit: Actually, #Matthias' solution is a lot easier.. You might want to use that instead.
Here's a function that will rotate an array by any offset in either direction (up to +/- length of the array) using just Array.Copy().
This is an extension of Matthias's answer above. It allocates a temporary array with the size of the offset to deal with wrapping.
void Rotate<T>(T[] array, int offset) {
if (offset==0) return;
if (offset>0) {
var temp = new T[offset];
System.Array.Copy(array, array.Length-offset, temp, 0, offset);
System.Array.Copy(array, 0, array, offset, array.Length-offset);
System.Array.Copy(temp, 0, array, 0, offset);
}else{
var temp = new T[-offset];
System.Array.Copy(array, 0, temp, 0, -offset);
System.Array.Copy(array, -offset, array, 0, array.Length+offset);
System.Array.Copy(temp, 0, array, array.Length+offset, -offset);
}
}
However, for the use case you described, it might be faster to not shift the array at all, but rather use a cyclical index when retrieving your data.