Meeting Conflict algorithms - algorithm

I had a interview today and was asked to check whether two meeting conflicts with each other or not. Each meeting has start time and end time.
I tried to answer the question but not that specific..can somebody throw some idea?
bool IsConflict(Datetime s1, Datetime e1, Datetime s2, Datetime e2)
should return true if Conflict is there and false if no conflict.
E.g
True if:
(s1, e1)= 8,10
(s2, e2) = 9, 11
(s1, e1)= 7,10
(s2, e2) = 8, 9
(s1, e1)= 8,11
(s2, e2) = 9, 11
and so on

This is basic interval algebra, see my answer here for more details, but the code would look like this:
bool IsConflict(Datetime s1, Datetime e1, Datetime s2, Datetime e2)
{
return (s1 < e2) && (e1 > s2);
}
I am assuming that two meetings where one start where the other ends are not in conflict.

In the simple case of two intervals I think this will work (untested pseudocode ahead):
bool IsConflict(Datatime s1, Datatime e1, Datatime s2, Datatime e2) {
if( s1 < s2 ) {
// meeting 1 starts first
if( e1 > s2 ) return true; // overlap
}
else {
// meeting 2 starts first
if( e2 > s1 ) return true; // overlap
}
return false;
}

The meetings overlap if and only if max(s1, s2) < min(e1, e2). This intersection based approach assumes that intervals (s, e) are open, and implies (rightly or wrongly) that an empty meeting s = e cannot have an overlap with another meeting.

Complexity of following algorithm is O (nlogn)
public boolean isConflicts(float startTime[], float endTime[])
{
TreeMap<Float, Integer> map = new TreeMap<Float, Integer>();
for (int i = 0; i < startTime.length; i++)
{
map.put(startTime[i], -1);
map.put(endTime[i], 1);
}
Iterator<Integer>iter = map.values().iterator();
while (iter.hasNext())
{
if ((iter.next() + iter.next()) != 0)
{
System.out.println ("Conflicts...");
return true;
}
}
return false;
}

The plan
There are three cases to check for with this problem.
Case 1: Does s1 lie within the interval [s2,e2]
(s1 >= s2) && (s1 <= e2)
Case 2: Does e1 lie within the interval [s2, e2]
(e1 >= s2) && (e2 <= e2))
Case 3: Does the point (s2, e2) lie within [s1, e1]
(s1 <= s2) && (e1 >= e2)
So here is the answer. I apologize; It's not the most readable lines of code.
The code (pseudo):
bool isConflict(Datetime s1, Datetime e1, Datetime s2, Datetime e2){
return ((s1 >= s2) && (s1 <= e2)) || ((e1 >= s2) && (e2 <= e2)) || (s1 <= s2) && (e1 >= e2));
}

Related

Does recursion in code still make my code linear to string length

Let's say I have two string s and t and I want to know if I can get from s to t via deleting, inserting or replacing a character in s. I have the following algorithm:
class Solution {
public boolean isOneEditDistance(String s, String t) {
return onedistance(s, t, 0, 0, 0);
}
private boolean onedistance(String s, String t, int si, int ti, int count) {
if(count > 1) return false;
while(si < s.length() || ti < t.length()) {
if(si == s.length()) return onedistance(s, t, si, ti + 1, count + 1);
if(ti == t.length()) return onedistance(s, t, si + 1, ti, count + 1);
if(s.charAt(si) == t.charAt(ti)) {
ti++;
si++;
} else {
return onedistance(s, t, si + 1, ti, count + 1) ||
onedistance(s, t, si, ti + 1, count + 1) ||
onedistance(s, t, si + 1, ti + 1, count + 1);
}
}
return count == 1;
}
}
Basically, the idea is to keep track of current pointer si and ti for character we are comparing now for s and t, if they are the same move both pointer forward, else move either si or ti or both to represent adding, deleting or replacing a char in s, we can only do it once, so if count > 1 we return false, at the end we check if count is equal to one to know if edit distance between s and t is 1.
I am wondering now if my code is O(m + n) where m and n is length of s and t, because even we have the recursive part, we only do it once and return immediately if count > 1;

Find a number in a sequence using divide and conquer

I have a sequence A = [x1, x2,...,xn] in which x1 = 0 and xk > xk-1 for each k=2,3,...n.
For example we can have [0, 2, 3, 5, 7]. In such sequence it turns out that:
If xc < c then xi < i for each 1 <= i <= c and,
If xc > c then xi > i for each c <= i <= n
I want to find a number m which belongs to sequence such that xm = m.
Is it possible to implement such an algorithm using divide and conquer technique?
This is the thing what Binary Search does. But just in divide and conquer technique.
Here are C++ code looks like -
int findNumber(int st, int ed, int tar, const vector<int> x) {
if (st == ed) {
if (x[st] == tar) return st;
else {
return -1;
}
}
int mid = (st + ed) / 2;
if (x[mid] < mid) {
return findNumber(mid+1, ed, tar, x);
} else {
return findNumber(st, mid-1, star, x);
}
}
Call this method as findNumber(0, x.size() - 1, tar, x)

Unclear understanding on Lowest Common Ancestor(LCA) Algorithm

I was trying to learn LCA algorithm O(nlog n) preprocessing and O(log n) query.I am reading it from a russian site with help of google translate.But it is not translating good and I am having some tough time understanding it.Can anybody help me with this ?
This is pseudo code I have taken from that website
int n, l;
vector <vector <int>> g;
vector <int> tin, tout;
int timer;
vector <vector <int>> up;
void dfs (int v, int p = 0)
{
tin [v] = ++ timer;
up [v] [0] = p;
for (int i = 1; i <= l; i ++) /** 3)What is this going
up [v] [i] = up [up [v] [i-1]] [i-1];
for (i = 0 size_t; i <g [v] .size (); i ++)
{
to g = int [v] [i];
if (to! = p)
dfs (to, v);
}
tout [v] = ++ timer;
}
bool upper (int a, int b)
{
return tin [a] <= tin [b] && tout [a]> = tout [b];
}
int lca (int a, int b)
{
if (upper (a, b)) return a;
if (upper (b, a)) return b;
for (int i = l; i> = 0; --i) /** 2)What is this going
if (! upper (up [a] [i], b))
a = up [a] [i];
return up [a] [0];
}
int main () {
... Read n and g ...
tin.resize (n), tout.resize (n), up.resize (n);
l = 1;
/** 0)What is 'l' used for ?
while ((1 << l) <= n) ++ l; /** 1)What is this going
for (int i = 0; i <n; i ++)
up [i] .resize (l + 1);
dfs (0);
for (;;) //->query loop
{
int a, b; // The current query
int res = lca (a, b); // Response to a request
}
}
What I have understood
I know we are traversing the graph and storing the in-time and out-time of every vertex.
I understand what up[i][j] is It is the 2^j ancestor of i vertex.
I understand why up[v][0]=p (because 2^0i.e first ancestor of vertex v is its father only)
I understand what upper function do.It decides which vertex occured before A or B.
I understand upper(a,b) comes out to be true than lca is A and similarly second step.
What I don't understand is mentioned by me in the pseudo code.Please help me and please confirm if I have understood everything correct or not.
P.S-> Sorry for my english.Not much comfortable with this.

Intersection of two triangles in the plane

The intersection of two triangles is either empty or an n-gon (for n up to 6).
In theory, it is easy to come up with an algorithm to compute the intersection area. One can compute the possible intersections of all line segments and combine them with the points of the corner points of the triangles.
In practise, there are some numerical issues. If line segments are (nearly) parallel, they may or may not have an intersection point and its calculation can be imprecise (one usually divides by the determinant of the matrix, which is then approximately zero).
Any suggestions to avoid these numerical instabilities?
I don't know how to find the intersection area, but if what you want is just to know if they intersect, the algorithm in the article "Faster Triangle-Triangle Intersection Tests" by Olivier Devillers and Philippe Guigue is supposed to be very stable according to some polynomial order theory I don't quite understood nor looked up in the reference.
Follows my own JavaScript implementation of it. I can't guarantee it is correct because it hasn't seen enough real world action.
function det3(a, b, c)
{
var a11 = a[0] - c[0]; var a12 = a[1] - c[1];
var a21 = b[0] - c[0]; var a22 = b[1] - c[1];
return a11 * a22 - a21 * a12;
}
function planar_intersect(vs, t1, t2)
{
var p1, q1, r1;
var p2, q2, r2;
// I am doing this weird unpacking of the vertices because
// originally they were on R³, and I had a code here to project
// them to some orthogonal plane on R².
p1 = t1.a; q1 = t1.b; r1 = t1.c;
p2 = t2.a; q2 = t2.b; r2 = t2.c;
// Ensure both triangles are counterclockwise
var tmp;
if(det3(p1, q1, r1) < 0) {
tmp = q1;
q1 = r1;
r1 = tmp;
}
if(det3(p2, q2, r2) < 0) {
tmp = q2;
q2 = r2;
r2 = tmp;
}
// Calculate signed areas of triangles
var s1 = Array(3);
// If 0, the vertex is on the edge of the other triangle
s1[0] = det3(p1, p2, q2);
if(s1[0] == 0)
return true;
s1[1] = det3(p1, q2, r2);
if(s1[1] == 0)
return true;
s1[2] = det3(p1, r2, p2);
if(s1[2] == 0)
return true;
// If all positive, the vertex is internal to the other triangle
if(s1[0] > 0 && s1[1] > 0 && s1[2] > 0) {
return true;
}
// Reorder t2 in order for a1 to be in the right area
for(var i = 0; i < 2; ++i) {
if(s1[0] > 0 && s1[2] <= 0) {
break;
}
tmp = s1[0];
s1[0] = s1[1];
s1[1] = s1[2];
s1[2] = tmp;
tmp = p2;
p2 = q2;
q2 = r2;
r2 = tmp;
}
if(s1[1] > 0) {
// Follow Figure 9 tree.
if(det3(r2, p2, q1) >= 0) {
// II.a
if(det3(r2, p1, q1) >= 0) {
// III.a
if(det3(p1, p2, q1) >= 0) {
return true;
} else {
// IV.a
if(det3(p1, p2, r1) >= 0) {
// V
return det3(q1, r1, p2) >= 0;
} else {
return false;
}
}
} else {
return false;
}
} else {
// II.b
if(det3(r2, p2, r1) >= 0) {
// III.b
if(det3(q1, r1, r2) >= 0) {
// IV.b
return det3(p1, p2, r1) <= 0;
} else {
return false;
}
} else {
return false;
}
}
} else {
// Follow Figure 10 tree.
if(det3(r2, p2, q1) >= 0) {
// II.a
if(det3(q2, r2, q1) >= 0) {
// III.a
if(det3(p1, p2, q1) >= 0) {
// IV.a
return det3(p1, q2, q1) <= 0;
} else {
// IV.b
if(det3(p1, p2, r1) >= 0) {
// V.a
return det3(r2, p2, r1) >= 0;
} else {
return false;
}
}
} else {
// III.b
if(det3(p1, q2, q1) <= 0) {
// IV.c
if(det3(q2, r2, r1) >= 0) {
// V.b
return det3(q1, r1, q2) >= 0;
} else {
return false;
}
} else {
return false;
}
}
} else {
// II.b
if(det3(r2, p2, r1) >= 0) {
// III.c
if(det3(q1, r1, r2) >= 0) {
// IV.d
return det3(r1, p1, p2) >= 0;
} else {
// IV.c
if(det3(q1, r1, q2) >= 0) {
// V.c
return det3(q2, r2, r1) >= 0;
} else {
return false;
}
}
} else {
return false;
}
}
}
}

Mauritus national flag problem

I've made a solution for the Dutch national flag problem already.
But this time, I want to try something more difficult: the Mauritus national flag problem - 4 colours, instead of 3. Any suggestions for an effective algorithm?
Basically, The Mauritius National Flag Problem focuses on how you would be able to sort the given list of pairs based on the order of colors in the Mauritius National Flag (Red, Blue, Yellow, Green). And the numbers must be sorted in ascending order too.
Scheme Programming Sample Input:
( (R . 3) (G . 6) (Y . 1) (B . 2) (Y . 7) (G . 3) (R . 1) (B . 8) )
Output:
( (R . 1) (R . 3) (B . 2) (B . 8) (Y . 1) (Y . 7) (G . 3) (G . 6) )
Here is what I came up with. Instead of colors, I am using numbers.
// l - index at which 0 should be inserted.
// m1 - index at which 1 should be inserted.
// m2 - index at which 2 should be inserted.
// h - index at which 3 should be inserted.
l=m1=m2=0;
h=arr.length-1
while(m2 <= h) {
if (arr[m2] == 0) {
swap(arr, m2, l);
l++;
// m1 should be incremented if it is less than l as 1 can come after all
// 0's
//only.
if (m1 < l) {
m1++;
}
// Now why not always incrementing m2 as we used to do in 3 flag partition
// while comparing with 0? Let's take an example here. Suppose arr[l]=1
// and arr[m2]=0. So we swap arr[l] with arr[m2] with and increment l.
// Now arr[m2] is equal to 1. But if arr[m1] is equal to 2 then we should
// swap arr[m1] with arr[m2]. That's why arr[m2] needs to be processed
// again for the sake of arr[m1]. In any case, it should not be less than
// l, so incrmenting.
if(m2<l) {
m2++;
}
}
// From here it is exactly same as 3 flag.
else if(arr[m2]==1) {
swap(arr, m1, m2)
m1++;
m2++;
}
else if(arr[m2] ==2){
m2++;
}
else {
swap(arr, m2, h);
h--;
}
}
}
Similarly we can write for five flags.
l=m1=m2=m3=0;
h= arr.length-1;
while(m3 <= h) {
if (arr[m3] == 0) {
swap(arr, m3, l);
l++;
if (m1 < l) {
m1++;
}
if(m2<l) {
m2++;
}
if(m3<l) {
m3++;
}
}
else if(arr[m3]==1) {
swap(arr, m1, m3);
m1++;
if(m2<m1) {
m2++;
}
if(m3<m1) {
m3++;
}
}
else if(arr[m3] ==2){
swap(arr,m2,m3);
m2++;
m3++;
}
else if(arr[m3]==3) {
m3++;
}
else {
swap(arr, m3, h);
h--;
}
}
This is just like the Dutch national flag problem, but we have four colors. Essentially the same strategy applies. Assume we have (where ^ represents the point being scanned).
RRRRBBB???????????YYYYGGGG
^
and we scan a
red, then we swap the first blue with the current node
BLUE we do nothing
yellow we swap with the last ?
Green we swap the last yellow with the last ? Then the current node with the swapped ?
So we need to keep track or one more pointer than usual.
We need to keep track of the first blue, the first ?, the last ?, the last Y
In general, the same strategy works for any number of colors, but an increasing numbers of swaps are needed.
Basically, maintain the following :
a[0-p] => '0'
a[p-q] => '1'
a[q-r] => '2'
a[r-s] => traversing!
a[s-length] => '3'
Code:
int p=-1,q=-1,r=0,s=a.length-1;
while(r<=s){
if(a[r]==0){
exchange(a,p+1,r);
p++;r++;
if(q!=-1)
q++;
} else if (a[r]==1){
if(q==-1)
q=p;
exchange(a,q+1,r);
q++;r++;
} else if(a[r]==2) {
r++;
} else {
exchange(a,r,s);
s--;
}
}
I do have a similar kind of code but insted of
function sort(a:string[]){
let low = 0;
let mid1 = 0;
let mid2 = a.length-1;
let high = a.length-1;
while(mid1 <= mid2){
switch(a[mid1]){
case '0':
[a[mid1],a[low]] = [a[low],a[mid1]];
mid1++;
low++;
break;
case '1':mid1++;break;
case '2':
case '3':[a[mid1],a[mid2]] = [a[mid2],a[mid1]];
mid2--;
break;
}
}
//sort 2 and 3
while(mid1 <= high){
switch(a[mid1]){
case '2': mid1++; break;
case '3': [a[mid1],a[high]] = [a[high],a[mid1]]
high--;
break;
}
}
}
function sort3(a:string[]):void{
let low = 0;
let mid1 = 0;
let mid2 = 0;
let high = a.length - 1;
while(mid2<=high){
switch(a[mid2]){
case '0': [a[mid2],a[low]] = [a[low],a[mid2]];
low++;
if(mid1<low)
mid1++;
if(mid2<mid1)
mid2++;
break;
case '1': [a[mid2],a[mid1]] = [a[mid1],a[mid2]];
mid1++;
mid2++;
break;
case '2':mid2++
break;
case '3':[a[mid2],a[high]] = [a[high],a[mid2]];
high--;
}
}
}
let a:string[] = ['1','2','1','0','2','4','3','0','1','3'];
function sort3(a:string[]):void{
let low = 0;
let mid1 = 0;
let mid2 = 0;
let mid3 = 0;
let high = a.length - 1;
while(mid3<=high){
switch(a[mid3]){
case '0': [a[mid3],a[low]] = [a[low],a[mid3]];
low++;
if(mid1 < low)
mid1++;
if(mid2 < mid1)
mid2++;
if(mid3 < mid2)
mid3++;
break;
case '1': [a[mid3],a[mid1]] = [a[mid1],a[mid3]];
mid1++;
if(mid2 < mid1)
mid2++;
if(mid3 < mid2)
mid3++
break;
case '2': [a[mid2],a[mid3]] = [a[mid3],a[mid2]];
mid2++;
mid3++;
break;
case '3':
mid3++;break;
case '4': [a[mid3],a[high]] = [a[high],a[mid3]];
high--;
}
}
}

Resources