I'm looking for an algorithm that given a list like:
[1, 1, 2, 1, 1, 5, 1, 1, 1, 1, 2, 1]
can find and return all subsequences of a given value. For example, if given the value 1, the function would return [[1, 1], [1, 1], [1, 1, 1, 1], [1]].
I believe this is similar to problems such as summing up all subsequences of an array or finding all the subsequences of a given string but algorithms was never my strong suit. The answer can be psuedo-code or language agnostic. And if you wouldn't mind, could you explain the complexity of the solution?
I can explain what I need this for if that helps. Comment if you want that.
We can do this in O(n) time complexity by scanning the array twice. Pseudocode:
//use an array list so we can access element at an index in O(1) time
outputArrays = new ArrayList<int[]> //list of arrays
//loop to declare arrays of outputs - this scans each element once
int currLen = 0;
for (item in inputArray) {
if (item = itemToLookFor) {
currLen++;
}else if (currLen > 0) {
currLen = 0;
outputArrays.add(new int[currLen]);
}
}
//loop to actually populate the output - this scans each element once
currLen = 0;
currIndex = 0;
for (item in inputArray) {
if (item = itemToLookFor) {
outputArrays.getElement(currIndex)[currLen] = item;
currLen++;
}else if (currLen > 0) {
currLen = 0;
currIndex++;
}
}
Let me know if there is anything i can clarify.
Let a be initial array, res - resulting array of sequences, curSeq - a current sequence, given_value - a given value.
res = []
curSeq = []
for i = 1..length(a)
if a[i] != given_value
if curSeq has at least one item
append curSeq to res
end if
curSeq = []
else
append given_value to curSeq
end if
end for
if curSeq has at least one item
append curSeq to res
end if
As you can see the time complexity is O(n) where n is the length of initial array.
Here is the O(n) solution.
Here arr is input array of sequence and sequence is array for sub-sequence. You can save sequence another array for your answer.
arr = [1, 1, 2, 1, 1, 5, 1, 1, 1, 1, 2, 1]; // here is your
selectNumber = 1 //take input for selected input
sequence = [];
for (i: 0 to arr.length) {
if (arr[i] == selectNumber) {
sequence.push(selectNumber);
} else {
if(sequence.length > 0) {
print sequence;
sequence = [] // empty sequence array as it is already printed or saved
}
}
}
if (sequence > 0) {
print sequence; // last sequence if exist
}
Related
I'm stuck in solving an interview question. The goal is to find a specific element from an array with unknown length (cannot use .length) and return the number of steps, but for an array with a length of n, the elements are guaranteed to be from 0 to n-1, no duplicates. For example, if the array's length is 5, the elements are {0, 1, 2, 3, 4} but the order may be different. Additional requirements are no loops, no static/global variables, and no helper functions, and the only parameters passing in are the array int[] arr and the target value int x, no extra parameters allowed, the array remains the same after all the operations have done.
//So you can only write in the body of the following method, no outside variables nor methods could be used.
private int findElement (int[] arr, int x) {
}
What I have gotten so far is, since the elements are guaranteed to be 0 to n-1, I can use the target number as an index and go back to the array to see if the number arr[x] equals the number x I want. If not, I take that number arr[x] and make it my new index, repeating until I find the target value.
int[] arr = {4, 1, 0, 2, 3}
int target = 3;
arr[3] = 2; //take target as the initial index
arr[2] = 0;
arr[0] = 4;
arr[4] = 3; //we got the number we want
//steps total is 3 since the question says the first time doesn't count.
Question: I tried to solve this by recursion, but since I am always comparing the following values with the initial parameter value, in the above case I always wanted to find 3. So how to store that information without static variables or extra parameters is my bigges problem. Is there any other way I can store the initial parameter value and pass it through the whole process?
private int findElement(int [] arr, int x) {
int actualN = arr[x];
if (actualN == **???**) { //can't be x cuz x is changing but I always want 3
return 0;
} else {
return findElement(arr, arr[x]) + 1;
}
}
Preferably using Java
Any hints or help would be greatly appreciated.
Probably this should work:
private int findElement(int [] arr, int x) {
int currValue = arr[x], returnValue;
if(arr[x]>0)
arr[x] = 0;//setting the actual element of the array to 0
else
arr[x]--;// decrementing the search index so it goes from 0-> -1 -> -2 -> -3...
if(Math.abs(arr[-arr[x]]) == x)//We check if the number is at our search index...
returnValue = 0;
else
returnValue = findElement(arr, x)+1;
arr[x] = currValue;//We take the value of the index from when the function was called and then reassign it to the same index after our work with it is done.
return returnValue;
}
Since the array only has to be the same after execution and it doesn't matter it's state during execution, this may work.
Note: I haven't done elaborate test on this so please do test the code sometimes before submitting
You were almost there
// t is the target number, o is teh array offset
static int find(int [] arr, int t, int o) {
if (arr[o] == t)
return o;
return find(arr, t, o + 1);
}
and
static void Main(string[] args) {
int[] arr = { 4, 1, 0, 2, 3 };
int target = 3;
int x = find(arr, 3, 0);
}
if only 2 args allowed - I missed that
in c
static int* find(int* arr, int t) {
if (*arr == t)
return arr;
return find(arr + 1, t);
}
int main() {
int arr[] = {4, 1, 0, 2, 3};
int target = 2;
int x = find(arr, target) - arr;
}
in c#
static unsafe int* find(int * arr, int t) {
if (*arr == t)
return arr;
return find(arr + 1,t);
}
static void Main(string[] args) {
int[] arr = { 4, 1, 0, 2, 3 };
int target = 3;
unsafe {
fixed (int * p = &arr[0]) {
int x = (int)(find(p, target) - p);
}
}
}
I have assumed arr can be modified, provide it is unchanged after the answer has been obtained.
Since it is only "preferable" that the answer be in Java (and I don't know Java), I'll offer a solution in Ruby. With its pseudo-code appearance and added comments readers unfamiliar with Ruby should be able to follow the calculations.
Specifically, I append an element to the given array which equals the index of the current element of the array to be examined (initially zero). If that element equals the target value we return up the recursion chain, initially returning zero, then adding one at each subsequent point of the chain. Before returning the desired count in doit, the last element of the array is removed to restore the array to its initial value.
If the value of the array indexed by the last element of the array (the current index) does not equal the target value the last element of the array is incremented by one and the method is called recursively.
def doit(arr,target)
arr << 0 # append the index 0 to arr
n = recurse(arr, target)
arr.pop # remove the last element of arr
n
end
def recurse(arr, target)
return 0 if arr[arr[-1]] == target
arr[-1] += 1 # increment last value of arr by 1
1 + recurse(arr, target)
end
arr = [4, 1, 0, 2, 3]
doit(arr, 4) #=> 0
doit(arr, 1) #=> 1
doit(arr, 0) #=> 2
doit(arr, 2) #=> 3
doit(arr, 3) #=> 4
I have to find (or atleast count) all pairs of (not necessarily adjacent) unsorted elements in a partially sorted array.
If we assume the sorting to be ascending, the array [1 4 3 2 5] has the following unsorted pairs: (4, 3), (3, 2) and (4, 2).
I'm thinking of an algorithm that works along the lines of insertion sort, as insertion sort tends to compare every new element with all elements which are misplaced with respect to the new element.
Edit: While posting the question, I didn't realise that finding the pairs would have a higher time complexity than counting them. Is there a better possible algorithm that just counts how many such pairs exist?
It depends a little bit on what you mean exactly by "partially sorted" - One could argue that every array is partially sorted to some degree.
Since this algorithm has worst-case complexity O(n^2) anyway (consider the input sorted in descending order), you might as well go down the straight-forward route:
ret = []
for i in range(len(array)):
for j in range(i, len(array)):
if array[i] > array[j]:
ret.append((array[i], array[j]))
return ret
This works very well for random arrays.
However, I suppose what you have in mind is more something that there are larger stretches inside the array where the numbers are sorted but that that's not the case for the array as a whole.
In that case, you can save a bit of time over the naive approach above by first identifying those stretches - this can be done in a linear pass. Once you have them, you only have to compare these stretches with each other, and you can use binary search for that (since the stretches are in sort order).
Here's a Python implementation of what I have in mind:
# find all sorted stretches
stretches = []
begin = 0
for i in range(1, len(array)):
if array[i-1] > array[i]:
stretches.append(array[begin:i])
begin = i
if i+1 > begin:
stretches.append(array[begin:])
# compare stretches
ret = []
for i in range(len(stretches)):
stretchi = stretches[i]
stretchi_rev = None
for j in range(i+1, len(stretches)):
stretchj = stretches[j]
if stretchi[-1] > stretchj[0]:
if stretchi_rev is None:
stretchi_rev = list(reversed(stretchi))
hi = len(stretchj)
for x in stretchi_rev:
i = bisect.bisect_left(stretchj, x, 0, hi)
if i == 0:
break
else:
for y in stretchj[:i]:
ret.append((x, y))
hi = i
return ret
For random arrays, this will be slower than the first approach. But if the array is big, and the amount of partially sorted portions is high enough, this algorithm will at some point starting to beat the brute-force search.
As suggested by #SomeDude in the comments, if you just need to count pairs there's an O(nlogn) solution based on building a binary search tree. There are some subtleties involved - we need to keep track of the number of duplicates (ic) at each node, and for performance reasons we also keep track of the number of right children (rc).
The basic scheme for inserting a value v intro the tree rooted at node n is:
def insert(n, v)
if v < n.data
count = 1 + n.ic + n.rc
if n.left is null
n.left = node(v)
return count
return count + insert(n.left, v)
else if v > n.data
if n.right is null
n.right = node(v)
n.rc = 1
return 0
n.rc += 1
return insert(n.right, v)
else // v == n.data
n.ic += 1
return n.rc
And here's some functioning Java code (Ideone):
static int pairsCount(Integer[] arr) {
int count = 0;
Node root = new Node(arr[0]);
for(int i=1; i<arr.length; i++)
count += insert(root, arr[i]);
return count;
}
static int insert(Node n, int v) {
if(v < n.value) {
int count = 1 + n.rc + n.ic;
if(n.left == null) {
n.left = new Node(v);
return count;
}
return count + insert(n.left, v);
}
else if(v > n.value) {
if(n.right == null) {
n.right = new Node(v);
n.rc = 1;
return 0;
}
n.rc += 1;
return insert(n.right, v);
}
else {
n.ic += 1;
return n.rc;
}
}
static class Node {
int value;
Node left, right;
int rc; // right children count
int ic; // duplicate count
Node(int value) {
this.value = value;
}
}
Test:
Integer[] arr = {1, 4, 3, 2, 5};
System.out.println(pairsCount(arr));
Output:
3
I made this function which should remove all adjacent values it finds from a vector.
fn remove_adjacent<T: std::cmp::PartialEq>(values: &mut Vec<T>, item: T) {
let mut offset = 0;
while let Some(idx) = values.iter().skip(offset).position(|n| *n == item) {
let length = values
.iter()
.skip(idx)
.position(|v| *v != item)
.unwrap_or(values.len() - idx);
if length > 1 {
values.drain(idx + 1..length + idx);
}
offset = idx + 1;
}
}
It works fine for vectors like
vec![2, 1, 3, 3, 3, 3, 3];
But not for vectors whose target element to be removed repeats after a non-target value, like
vec![2, 1, 3, 3, 3, 3, 3, 7, 3, 3, 3];
It should also remove the threes 3 values after 7, but instead it get stuck in an infinite loop. I'm not able find the error on my own, if anyone has tips on how to fix this I'll really appreciate it.
Example on Rust Playground
Everything in your code works correctly except getting the idx.
You can print out the idx and see what is wrong with it. Printing offset helps too.
fn remove_adjacent<T: std::cmp::PartialEq>(values: &mut Vec<T>, item: T) {
let mut offset = 0;
while let Some(idx) = values.iter().skip(offset).position(|n| *n == item) {
dbg!(idx, offset); // prints out nicely
let length = values
.iter()
.skip(idx)
.position(|v| *v != item)
.unwrap_or(values.len() - idx);
if length > 1 {
values.drain(idx + 1..length + idx);
}
offset = idx + 1;
}
}
You will notice that the idx is not always what you want.
This is happening becuase .position( counts not in values but in the iterator you get after .skip(offset).
I hope looking at the printed values and my clue guides you to fix the error on your own. Good luck! 😃
Let say I have an array of Int, I want to find a pair of number in this array that the sum of this pair is equal to an number, like so:
func findPair(list: [Int], _ sum: Int) -> (Int, Int)? {
for i in 0..<list.count - 1{
for j in (i+1)..<list.count {
let sumOfPair = list[i] + list[j]
if sumOfPair == sum {
return (list[i], list[j])
}
}
}
return nil
}
The first parameter is an array of Int, the second parameter is an number that we need to compare some pairs in that array.
For example:
findPair([1,2,3,4,5], 7) // will return (2, 5), because 2 + 5 = 7
But the complexity of this algorithm is O(n^2).
Is there any way faster?
Try the following approach:
sort(arr,arr+n);//Sort the array
low=0;
high=n-1; // The final index number (pointing to the greatest number)
while(low<=high)
{
if(arr[low]+arr[high]==num)
{ print(low,high);
break;
}
else if(arr[low]+arr[high]<num)
low++;
else if(arr[low]+arr[high]>num)
high--;
}
Basically, you are following the greedy Approach over here... Hope it works.. :)
Try with this:
func findPair(list: [Int], _ sum: Int) -> (Int, Int)? {
//save list of value of sum - item.
var hash = Set<Int>()
var dictCount = [Int: Int]()
for item in list {
//keep track of count of each element to avoid problem: [2, 3, 5], 10 -> result = (5,5)
if (!dictCount.keys.contains(item)) {
dictCount[item] = 1
} else {
dictCount[item] = dictCount[item]! + 1
}
//if my hash does not contain the (sum - item) value -> insert to hash.
if !hash.contains(sum-item) {
hash.insert(sum-item)
}
//check if current item is the same as another hash value or not, if yes, return the tuple.
if hash.contains(item) &&
(dictCount[item] > 1 || sum != item*2) // check if we have 5+5 = 10 or not.
{
return (item, sum-item)
}
}
return nil
}
There surely is much faster O(n log(n)) to solve this problem. Below is the pseudo algorithm for that :-
1) Sort the given array.
2) Take two pointers. One pointing to the beginning and other pointing to the end.
3) Check if sum of two values pointed by two pointer is equal to given number.
4) If yes then return.
5) If greater than increment first pointer and go to step 3.
6) Else decrement second pointer and go to step 3.*
I had previously posted a question, Given an array, find out the next smaller element for each element
now, i was trying to know , if there is any way to find out "given an array, for each element, find out the total number of elements lesser than it, which appear to the right of it"
for example, the array [4 2 1 5 3] should yield [3 1 0 1 0]??
[EDIT]
I have worked out a solution, please have a look at it, and let me know if there is any mistake.
1 Make a balanced BST inserting elements traversing the array from right to left
2 The BST is made in such a way that each element holds the size of the tree rooted at that element
3 Now while you search for the right position to insert any element, take account of the total size of the subtree rooted at left sibling + 1(for parent) if you move right
Now since, the count is being calculated at the time of insertion of an element, and that we are moving from right to left, we get the exact count of elements lesser than the given element appearing after it.
It can be solved in O(n log n).
If in a BST you store the number of elements of the subtree rooted at that node when you search the node (reaching that from the root) you can count number of elements larger/smaller than that in the path:
int count_larger(node *T, int key, int current_larger){
if (*T == nil)
return -1;
if (T->key == key)
return current_larger + (T->right_child->size);
if (T->key > key)
return count_larger(T->left_child, key, current_larger + (T->right_child->size) + 1);
return count_larger(T->right_child, key, current_larger)
}
** for example if this is our tree and we're searching for key 3, count_larger will be called for:
-> (node 2, 3, 0)
--> (node 4, 3, 0)
---> (node 3, 3, 2)
and the final answer would be 2 as expected.
Suppose the Array is 6,-1,5,10,12,4,1,3,7,50
Steps
1.We start building a BST from right end of the array.Since we are concerned with all the elements to right for any element.
2.Suppose we have formed the partial solution tree upto the 10.
3.Now when inserting 5 we do a tree traversal and insert to the right of 4.
Notice that each time we traverse to the right of any node we increment by 1 and add the no. of elements in left subtree of that node.
eg:
for 50 it is 0
for 7 it is 0
for 12 it is 1 right traversel + leftsubtree size of 7 = 1+3 =4
for 10 same as above.
for 4 it is 1+1 =2
While building bst we can easily maintain the left subtree size for each node by simply maintaining a variable corresponding to it and incrementing it by 1 each time a node traverses to the left by it.
Hence the Solution Average case O(nlogn).
We can use other optimizations such as predetermining whether array is sorted in decreasing order
find groups of element in decreasing order treat them as single.
I think is it possible to do it in O(nlog(n))with a modified version of quicksort. Basically each time you add an element to less, you check if this element rank in the original array was superior to the rank of the current pivot. It may look like
oldrank -> original positions
count -> what you want
function quicksort('array')
if length('array') ≤ 1
return 'array' // an array of zero or one elements is already sorted
select and remove a pivot value 'pivot' from 'array'
create empty lists 'less' and 'greater'
for each 'x' in 'array'
if 'x' ≤ 'pivot'
append 'x' to 'less'
if oldrank(x) > = oldrank(pivot) increment count(pivot)
else
append 'x' to 'greater'
if oldrank(x) < oldrank(pivot) increment count(x) //This was missing
return concatenate(quicksort('less'), 'pivot', quicksort('greater')) // two recursive calls
EDIT:
Actually it can be done using any comparison based sorting algorithm . Every time you compare two elements such that the relative ordering between the two will change, you increment the counter of the bigger element.
Original pseudo-code in wikipedia.
You can also use binary Index tree
int tree[1000005];
void update(int idx,int val)
{
while(idx<=1000000)
{
tree[idx]+=val;
idx+=(idx & -idx);
}
}
int sum(int idx)
{
int sm=0;
while(idx>0)
{
sm+=tree[idx];
idx-=(idx & -idx);
}
return sm;
}
int main()
{
int a[]={4,2,1,5,3};
int s=0,sz=6;
int b[10];
b[sz-1]=0;
for(int i=sz-2;i>=0;i--)
{
if(a[i]!=0)
{
update(a[i],1);
b[i]=sum(a[i]-1)+s;
}
else s++;
}
for(int i=0;i<sz-1;i++)
{
cout<<b[i]<<" ";
}
return 0;
}
//some array called newarray
for(int x=0; x <=array.length;x++)
{
for(int y=x;y<array.length;y++)
{
if(array[y] < array[x])
{
newarray[x] = newarray[x]+1;
}
}
}
something like this,where array is your input array and newarray your output array
make sure to initialize everything correctly(0 for the newarrays values)
Another approach without using the tree.
Construct another sorted array . For example for input array {12, 1, 2, 3, 0, 11, 4} it will be {0, 1, 2, 3, 4, 11, 12}
Now compare position of each element from input array with sorted array.For example 12 in first array is at 0 index while sorted array it’s as 6
Once comparison is done, remove element from both array
Other than using BST, we can also solve this problem optimally by doing some modification in merge sort algorithm (in O(n*logn) time).
If you observe this problem more carefully, you can say that in the problem we need to count the number of inversions required for each element to make the array sorted in ascending order, right?
So this problem can be solved using Divide and Conquer paradigm. Here you need to maintain an auxiliary array for storing the count of inversions required (i.e. elements smaller than it on the right side of it).
Below is a python program:
def mergeList(arr, pos, res, start, mid, end):
temp = [0]*len(arr)
for i in range(start, end+1):
temp[i] = pos[i]
cur = start
leftcur = start
rightcur = mid + 1
while leftcur <= mid and rightcur <= end:
if arr[temp[leftcur]] <= arr[temp[rightcur]]:
pos[cur] = temp[leftcur]
res[pos[cur]] += rightcur - mid - 1
leftcur += 1
cur += 1
else:
pos[cur] = temp[rightcur]
cur += 1
rightcur += 1
while leftcur <= mid:
pos[cur] = temp[leftcur]
res[pos[cur]] += end - mid
cur += 1
leftcur += 1
while rightcur <= end:
pos[cur] = temp[rightcur]
cur += 1
rightcur += 1
def mergeSort(arr, pos, res, start, end):
if start < end:
mid = (start + end)/2
mergeSort(arr, pos, res, start, mid)
mergeSort(arr, pos, res, mid+1, end)
mergeList(arr, pos, res, start, mid, end)
def printResult(arr, res):
print
for i in range(0, len(arr)):
print arr[i], '->', res[i]
if __name__ == '__main__':
inp = input('enter elements separated by ,\n')
inp = list(inp)
res = [0]*len(inp)
pos = [ind for ind, v in enumerate(inp)]
mergeSort(inp, pos, res, 0, len(inp)-1)
printResult(inp, res)
Time : O(n*logn)
Space: O(n)
You can also use an array instead of a binary search tree.
def count_next_smaller_elements(xs):
# prepare list "ys" containing item's numeric order
ys = sorted((x,i) for i,x in enumerate(xs))
zs = [0] * len(ys)
for i in range(1, len(ys)):
zs[ys[i][1]] = zs[ys[i-1][1]]
if ys[i][0] != ys[i-1][0]: zs[ys[i][1]] += 1
# use list "ts" as binary search tree, every element keeps count of
# number of children with value less than the current element's value
ts = [0] * (zs[ys[-1][1]]+1)
us = [0] * len(xs)
for i in range(len(xs)-1,-1,-1):
x = zs[i]+1
while True:
us[i] += ts[x-1]
x -= (x & (-x))
if x <= 0: break
x = zs[i]+1
while True:
x += (x & (-x))
if x > len(ts): break
ts[x-1] += 1
return us
print count_next_smaller_elements([40, 20, 10, 50, 20, 40, 30])
# outputs: [4, 1, 0, 2, 0, 1, 0]
Instead of BST, you can use stl map.
Start inserting from right.
After inserting an element, find its iterator:
auto i = m.find(element);
Then subtract it from m.end(). That gives you the number of elements in map which are greater than current element.
map<int, bool> m;
for (int i = array.size() - 1; i >= 0; --i) {
m[array[i]] = true;
auto iter = m.find(array[i])
greaterThan[i] = m.end() - iter;
}
Hope it helped.
Modified Merge sort: (Already tested code)
Takes O(nlogn) time.
public class MergeSort {
static HashMap<Integer, Integer> valueToLowerCount = new HashMap<Integer, Integer>();
public static void main(String[] args) {
int [] arr = new int[] {50, 33, 37, 26, 58, 36, 59};
int [] lowerValuesOnRight = new int[] {4, 1, 2, 0, 1, 0, 0};
HashMap<Integer, Integer> expectedLowerCounts = new HashMap<Integer, Integer>();
idx = 0;
for (int x: arr) {
expectedLowerCounts.put(x, lowerValuesOnRight[idx++]);
}
for (int x : arr) valueToLowerCount.put(x, 0);
mergeSort(arr, 0, arr.length-1);
//Testing
Assert.assertEquals("Count lower values on right side", expectedLowerCounts, valueToLowerCount);
}
public static void mergeSort(int []arr, int l, int r) {
if (r <= l) return;
int mid = (l+r)/2;
mergeSort(arr, l, mid);
mergeSort(arr, mid+1, r);
mergeDecreasingOrder(arr, l, mid, r);
}
public static void mergeDecreasingOrder(int []arr, int l, int lr, int r) {
int []leftArr = Arrays.copyOfRange(arr, l, lr+1);
int []rightArr = Arrays.copyOfRange(arr, lr+1, r+1);
int indexArr = l;
int i = 0, j = 0;
while (i < leftArr.length && j < rightArr.length) {
if (leftArr[i] > rightArr[j]) {
valueToLowerCount.put(leftArr[i], valueToLowerCount.get(leftArr[i]) + rightArr.length - j);
arr[indexArr++] = leftArr[i++];
}else {
arr[indexArr++] = rightArr[j++];
}
}
while (i < leftArr.length) {
arr[indexArr++] = leftArr[i++];
}
while (j < rightArr.length) {
arr[indexArr++] = rightArr[j++];
}
}
}
To find the total number of values on right-side which are greater than an array element, simply change single line of code:
if (leftArr[i] > rightArr[j])
to
if (leftArr[i] < rightArr[j])