So I was doing a question on LeetCode...
Question:
Write an efficient algorithm that searches for a target value in an m x n integer matrix. The matrix has the following properties:
Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.
Example 1:
Input: matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
Output: true
Example 2:
Input: matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
Output: false
So first I attempted this question by regular brute force method:
Answer-1:
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int t) {
int i=0,j,I=matrix.size(),J,mj;
for(;i<I;i++)
{
j=0;J=matrix[i].size()-1;
mj=(j+J)/2;
while(j<=J)
{
if(matrix[i][mj]==t)
return true;
else if(matrix[i][mj]<t)
j=mj+1;
else
J=mj-1;
mj=(j+J)/2;
}
}
return false;
}
};
Then I decided to do it by idk Divide and Conquer ig...
Answer-2:
class Solution {
public:
bool VFinder(vector<vector<int>>& matrix, int hstart, int hend, int vstart, int vend, int ele)
{
if(vstart > vend || hstart > hend)
return false;
int mid = vstart;
int start = vstart;
int end = vend;
while(start<=end)
{
mid = (int)((start + end) / 2);
if (start == end)
{
if (matrix[mid][hstart] == ele)
{
return true;
}
else
{
return HFinder(matrix, hstart + 1, hend, vstart, mid, ele);
}
}
else
{if(matrix[mid][hstart] <ele && matrix[mid+1][hstart] > ele)
return HFinder(matrix, hstart+1, hend, vstart, mid,ele);
else if(matrix[mid][hstart] <ele)
start = mid+1;
else if(matrix[mid][hstart] >ele)
end = mid-1;
else if(matrix[mid][hstart] == ele)
return true;}
}
return false;
}
bool HFinder(vector<vector<int>>& matrix, int hstart, int hend, int vstart, int vend, int ele)
{
if(hstart > hend || vstart > vend)
return false;
int mid = hstart;
int start = hstart;
int end = hend;
while(start<=end)
{
mid = (int)((start + end) / 2);
if (start == end)
{
if (matrix[vstart][mid] == ele)
{
return true;
}
else
{
return VFinder(matrix, hstart, mid, vstart + 1, vend, ele);
}
}
else
{if(matrix[vstart][mid] <ele && matrix[vstart][mid+1] > ele)
return VFinder(matrix, hstart, mid, vstart+1, vend, ele);
else if(matrix[vstart][mid] <ele)
start = mid+1;
else if(matrix[vstart][mid] >ele)
end = mid-1;
else if(matrix[vstart][mid] == ele)
return true;}
}
return false;
}
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int horizontal = matrix[0].size();
int vertical = matrix.size();
return HFinder(matrix, 0, horizontal-1, 0, vertical-1, target);
}
};
So the first code after submission took about : 328 ms
And the second one took about : 488 ms
But in second one, I am after each step reducing the search space, so it should have taken less time as compared to the first code, but it is not happening so.
Can someone please tell me why is it so?
And also what is the time complexity of the second code?
Related
I'm trying to write a recursive binary search function using below approach. I'm basically using divide and conquer strategy and everything looks good to me in code, but unable to figure out where my code and approach goes wrong.
#include<iostream>
using namespace std;
bool b_search(int *arr, int n, int start, int end){
if(start==end){
if(arr[start]==n){
return true;
}
else{
return false;
}
}
else{
int mid=start+(end-start)/2;
if(arr[mid]==n){
return true;
}
else if(arr[mid]>n){
return b_search(arr,n,mid+1,end);
}
else{
return b_search(arr,n,start,mid-1);
}
}
}
int main(){
int arr[8]={3,5,8,11,13,15,16,25};
cout<<b_search(arr,16,0,7);
}
I'm getting output as zero but it should be 1.
When arr[mid]>n you then search for the number in the part with higher number which is guaranteed to miss. You need to search in the part with lower numbers.
Example:
bool b_search(int *arr, int n, int start, int end) {
if (start == end) return arr[start] == n;
int mid = start + (end - start) / 2;
if (arr[mid] < n) { // arr[mid] is lower than n, search in the high part
return b_search(arr, n, mid + 1, end);
} else if (arr[mid] > n) { // arr[mid] is greater than n, search lower part
return b_search(arr, n, start, mid - 1);
}
return true;
}
Your next interval is wrong.
else if(arr[mid]>n){
return b_search(arr,n,mid+1,end);
When the middle element is too large then you continue with the larger portion of the array. You should continue with the smaller portion of the array instead:
else if(arr[mid]<n){
return b_search(arr,n,mid+1,end);
}
else{
return b_search(arr,n,start,mid-1);
}
You are searching in the wrong direction. If arr[mid] > n then you should be searching from start to mid -1 and the other way around. The reason is that your searched value n is then in the other half of your searched array
#include<iostream>
using namespace std;
bool b_search(int *arr, int n, int start, int end)
{
if(start==end)
{
if(arr[start]==n)
{
return true;
}
else
{
return false;
}
}
else
{
int mid=start+(end-start)/2;
if(arr[mid]==n)
{
return true;
}
else if(arr[mid]<n) // turn around the comparison
{
return b_search(arr,n,mid+1,end);
}
else
{
return b_search(arr,n,start,mid-1);
}
}
}
int main()
{
int arr[8]={3,5,8,11,13,15,16,25};
cout<<b_search(arr,16,0,7);
}
Here is a simple code of Binary Search in C++:
int binarySearch(vector<int> &vec, int start, int end, int element) {
int middle = 0;
if (start <= end) {
middle = start + (end - start) / 2;
if (vec[middle] == element) {
return middle;
}
else if (vec[middle] < element) {
binarySearch(vec, middle + 1, end, element);
}
else {
binarySearch(vec, start, middle - 1, element);
}
}
return -1;
}
It always produces the result -1. Now, I know that in a function's stack unwinding phase, the last return -1 gets called.
However, the following code works just fine:
int binarySearch(vector<int> &vec, int start, int end, int element) {
int middle = 0;
if (start <= end) {
middle = start + (end - start) / 2;
if (vec[middle] == element) {
return middle;
}
else if (vec[middle] < element) {
return binarySearch(vec, middle + 1, end, element);
}
else {
return binarySearch(vec, start, middle - 1, element);
}
}
return -1;
}
I want to know what exactly is the difference between returning a function and calling a function?
Given a list of n non repeating integer numbers L:=(x1,...,xn) develop an algorithm that decides if there are xi1, xi2, xi3 in L such that i1 is lower than i2, i2 is lower than i_3, xi1 is lower than xi3 and xi3 is lower than xi2. Only a yes-no answer is required.
The statement also suggest to use the "divide & conquer" strategy.
My try was the following:
I read the vector left to right
If the list changes from increasing to decreasing, then it is clear that the last read number is lower than the maximum of the currently read list. So if it is greater than the minimum of the current list we can stop.
If the list changes from decreasing to increasing, then I look for the first number m in the list which is a local minimum and it is lower than the last read number c. And then I look for a local maximum appearing after m which is greater than c.
If the list keeps increasing we do the same as in the previous step.
If the list keeps decreasing do nothing.
So the complexity is nlogn. I think the strategy is good, but an online judge rejected it. I don't know if it is due to a silly bug or because the strategy is indeed wrong.
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
bool solveCase();
bool increasingCase(map<int, int> & mins, map<int, int> & maxs,
pair<map<int, int>::iterator, bool> & lastMaxInserted,
const int & current);
void ignoreStuff();
int main() {
while (solveCase())
;
return 0;
}
bool solveCase() {
/*---Reading the number of children---*/
int N;
if (scanf("%d", &N) == EOF) {
return false;
}
/*---Used variables---*/
int globalMax;
int globalMin;
map<int, int> maxs;
map<int, int> mins;
int localMin;
int localMinPos;
bool increasing;
pair<map<int, int>::iterator, bool> lastMaxInserted;
int old;
int current;
/*-----Reading the first two children-----*/
/*--Reading the first children--*/
scanf("%d", &old);
globalMax = old;
globalMin = old;
/*--Reading the second children--*/
scanf("%d", ¤t);
if (current > old) { /*The sequence starts increasing*/
increasing = true;
globalMax = current;
localMin = old;
localMinPos = 0;
} else { /*The sequence starts decreasing*/
increasing = false;
globalMin = current;
lastMaxInserted = maxs.insert(pair<int, int>(old, 0));
}
old = current;
/*-----Reading the rest-----*/
for (int i = 2; i < N; i++) {
scanf("%d", ¤t); /*Reading a child*/
if (!increasing) { /*--The sequence was decreasing--*/
if (current < old) { /*The sequence keeps decreasing*/
globalMin = min(current, globalMin);
} else { /*The monotony changes*/
localMin = old;
localMinPos = i - 1;
if (increasingCase(mins, maxs, lastMaxInserted, current)) {
printf("ELEGIR OTRA\n");
ignoreStuff(); /*Ignoring the rest*/
return true;
}
increasing = true;
}
} else { /*--The sequence was increasing--*/
if (current > old) { /*The sequence keeps increasing*/
globalMax = max(current, globalMax);
if (increasingCase(mins, maxs, lastMaxInserted, current)) {
printf("ELEGIR OTRA\n");
ignoreStuff(); /*Ignoring the rest*/
return true;
}
} else { /*The monotony changes*/
if (current > globalMin) { /*Check if we can end*/
printf("ELEGIR OTRA\n");
ignoreStuff(); /*Ignoring the rest*/
return true;
} else {
globalMin = current;
/*Inserting the local minimum (saved somewhere)*/
map<int, int>::iterator minIter;
minIter = mins.lower_bound(localMin);
if (!mins.empty() && minIter != mins.begin()) {
/*The value is the minimum position of the local
* minimums lower than the current local minimum*/
minIter--;
mins.insert(pair<int, int>(localMin, minIter->second));
} else {
mins.insert(pair<int, int>(localMin, localMinPos));
}
/*Inserting the local maximum (old)*/
/*The value is the maximum position of the local
* maximums greater or equal than than the current
* local maximum (i.e. the position of the local
* maximum). The local maximums lower than the
* current maximum have incoherent values, but it
* doesn't matter...*/
lastMaxInserted = maxs.insert(pair<int, int>(old, i - 1));
increasing = false;
}
}
}
old = current;
}
printf("SIEMPRE PREMIO\n");
return true;
}
bool increasingCase(map<int, int> & mins, map<int, int> & maxs,
pair<map<int, int>::iterator, bool> & lastMaxInserted,
const int & current) {
if (!mins.empty()) {
/*--Getting the position of the first local minimum lower than current--*/
map<int, int>::iterator minIter;
minIter = mins.lower_bound(current);
if (minIter != mins.begin()) {
minIter--;
} else {
return false;
}
int minPos = minIter->second;
/*--Trying to get a good local maximum coming after the minimum--*/
if (!maxs.empty()) {
map<int, int>::iterator maxIter;
maxIter = maxs.upper_bound(current);
if (maxIter != maxs.end()) {
if (maxIter->first < lastMaxInserted.first->first) {
if (minPos > lastMaxInserted.first->second) {
return false;
}
} else {
if (minPos > maxIter->second) {
return false;
}
}
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
return true;
}
void ignoreStuff() {
char trash = getchar();
while (trash != '\n') {
trash = getchar();
}
}
Any idea?
I am trying to count the number of comparisons done by heap sorting algorithm.
my code is based on priority queue and I want to know where I should put the counter. here is what I have but when I try to print the counter it shows zero counts, what am I doing wrong? Thank you.
here is the heapbuild function:
#include<iostream>
vector<int> pq_keys;
void buildHeap()
{
int size = pq_keys.size();
int midIdx = (size -2)/2;
while (midIdx >= 0)
{
shiftRight(midIdx, size-1);
--midIdx;
}
and this is the function that does the comparison:
int shiftRight(int low, int high)
{
int root = low;
int counter=0;
while ((root*2)+1 <= high)
{
int leftChild = (root * 2) + 1;
int rightChild = leftChild + 1;
int swapIdx = root;
if (pq_keys[swapIdx] < pq_keys[leftChild])
{
counter++;
cout<<counter;
swapIdx = leftChild;
}
/*If right child exists check if it is less than current root*/
if ((rightChild <= high) && (pq_keys[swapIdx] < pq_keys[rightChild]))
{
counter++;
swapIdx = rightChild;
}
/*Make the biggest element of root, left and right child the root*/
if (swapIdx != root)
{
counter++;
int tmp = pq_keys[root];
pq_keys[root] = pq_keys[swapIdx];
pq_keys[swapIdx] = tmp;
root = swapIdx;
}
else
{
break;
}
}
return counter;
}
You want to increment the counter before you do the comparison. Consider this code, from your shiftRight method:
if (pq_keys[swapIdx] < pq_keys[leftChild])
{
counter++;
cout<<counter;
swapIdx = leftChild;
}
That only increments the counter if the conditional is true. If pq_keys[swpIdx] >= pq_keys[leftChild], then you made the comparison without counting it. You need to change your code to be:
counter++;
if (pq_keys[swapIdx] < pq_keys[leftChild])
{
cout<<counter;
swapIdx = leftChild;
}
You need to do the same thing in the other two places where you count comparisons: increment the counter, then do the comparison.
class LessPredicate
{
size_t callCount_ = 0;
temlate<class T>
bool compare(const T& l, conct T& r)
{
return l < r; // or other logic
}
public:
size_t CallTimes() const { return callCount_; }
temlate<class T>
bool operator() (const T& l, conct T& r)
{
++callCount_;
return compare(l, r);
}
};
int main()
{
LessPredicate less;
...// use it like less(a, b) instead a < b;
auto compareCount = less.CallTimes();
}
I have sevral questions about maze - solver algorithms:C
What is the time complexity of recursive (backtracking) maze-solver?(As an amount of paths in the matrix? - I can`t figure this number..)
What is the time complexity of BFS based maze-solver?(O(n^2)?) n is a dimension of the squared maze matrix?
What is the best algoritm to count the number of all possible paths from the source to the destination in the maze?
Can you propose the idea if and how an it be implemented using parallel computing (opecl/cuda)
Here is the class for my maze solver ,which has brute (recursive) and bfs based version.I implemented it and the questions are based on this maze-solver implementation
//MazeSolver.h
//#define N 5
typedef enum {BLACK,WHITE,GRAY,VISITED} color;
class MazeSolver
{
public:
MazeSolver(){}
struct Cell
{
unsigned int _x;
unsigned int _y;
Cell* _p;
Cell(unsigned int x = 0,unsigned int y = 0, Cell* p = NULL) : _x(x),_y(y),_p(p) {}
bool operator == (const Cell& c)
{
return _x == c._x && _y == c._y;
}
};
bool solveMazeBrute(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<Cell>& path);
bool solveMazeBFS(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<Cell>& path);
private:
std::queue<Cell* > _bfs;
std::vector<Cell* > _cells;
Cell* addCellBFS(color maze[][N],unsigned int n,int x,int y,Cell* p = NULL);
};
//MazeSolver.cpp
MazeSolver::Cell* MazeSolver::addCellBFS(color maze[][N],unsigned int n,int x,int y,Cell* p)
{
if (x >= 0 && x < n && y >= 0 && y < n && maze[x][y] == WHITE)
{
Cell* c = new Cell(x,y,p);
maze [x][y] = VISITED;
_bfs.push(c);
_cells.push_back(c);
return c;
}
return NULL;
}
bool MazeSolver::solveMazeBrute(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<MazeSolver::Cell>& path)
{
bool solved = false;
if (xS < 0 || xS >= n || yS < 0 || yS >= n || maze[xS][yS] == VISITED || maze[xS][yS] == BLACK)
{
return false;
}
Cell s(xS,yS);
Cell d(xD,yD);
if (s == d)
{
path.push_front(s);
return true;
}
maze[xS][yS] = VISITED;
if (solveMazeBrute(maze,n,xS + 1,yS,xD,yD,path) ||
solveMazeBrute(maze,n,xS - 1,yS,xD,yD,path) ||
solveMazeBrute(maze,n,xS,yS + 1,xD,yD,path) ||
solveMazeBrute(maze,n,xS,yS - 1,xD,yD,path))
{
path.push_front(s);
solved = true;
}
maze[xS][yS] = WHITE;
return solved;
}
bool MazeSolver::solveMazeBFS(color maze[][N],unsigned int n,int xS,int yS,int xD,int yD,std::list<Cell>& path)
{
Cell d(xD,yD);
addCellBFS(maze,n,xS,yS);
while(!_bfs.empty())
{
Cell* cur = _bfs.front();
if (*cur == d)
{
while (cur != NULL)
{
path.push_front(*cur);
cur = cur->_p;
}
return true;
}
_bfs.pop();
addCellBFS(maze,n,cur->_x - 1,cur->_y,cur);
addCellBFS(maze,n,cur->_x + 1,cur->_y,cur);
addCellBFS(maze,n,cur->_x,cur->_y - 1,cur);
addCellBFS(maze,n,cur->_x,cur->_y + 1,cur);
}
for(std::vector<Cell*>::iterator itC= _cells.begin();itC != _cells.end();++itC)
{
maze[(*itC)->_x][(*itC)->_y] = WHITE;
delete *itC;
}
return false;
}
Maybe we can find the target in O(n).
Let's imagine 5X5 matrix.
In each iteration we'll step single step ahead, we'll check the cell is valid and is not the end of maze, and mark it as "visited".
So, we'll start at the first cell (0,0). in next iteration we'll check the next layer, mean (0,1),(1,0), in next iteration we'll continue check the next layer (0,2),(1,1),(2,0). and so on.
So, we'll check each cell once only! and we'll find the end (the target) in n complexity.
Am i wrong?