《程序员面试金典》(第六版)习题:仅为记录一下以加强印象,不为商业用途,如有侵权请联系删除。以下源码和解释参考了书中源码以及解释。
基础算法利用到了排序矩阵的特殊性质,如果待查找元素小于一列开头的元素则待查找元素肯定不会位于该列右边的列以及该列本身。如果待查找元素小于一行末尾的元素则待查找元素肯定不会位于该行上边的行以及该行本身。基础算法从矩阵第0行最后一个元素开始搜索,不断向左下角行进来找到待查找元素。
//基础算法
bool findElement(vector<vector<int>> matrix,int elem)
{
int row = 0;
int col = matrix[0].size() - 1;
while (row< matrix.size()&&col>=0)
{
if (matrix[row][col]==elem)
{
return true;
}
else if (matrix[row][col] > elem)
{
col--;
}
else
{
row++;
}
}
return false;
}
改进算法充分利用到了排序矩阵的特殊性质,算法首先沿着对角线利用二分查找算法寻找需要查找的元素,如果找到需要查找的元素就直接返回,否则找到对角线上第一个比需要查找的元素大的元素,然后以此元素为基点将原矩阵划分为两块面积更小的矩阵并递归在这两块矩阵上查找。
//改进算法
int min(int a,int b)
{
if (a > b)
return b;
else
return a;
}
class Coordinate
{
public:
int row;
int column;
bool isFinded;
Coordinate(int r, int c)
{
row = r;
column = c;
isFinded = false;
}
bool inbounds(vector<vector<int>> matrix)
{
return ((row >= 0) && (column >= 0) && (row < matrix.size()) && (column < matrix[0].size()));
}
bool isBefore(Coordinate p)
{
return row <= p.row && column <= p.column;
}
void moveDownRight()
{
row++;
column++;
}
void setToAverage(Coordinate min, Coordinate max)
{
row = (min.row + max.row) / 2;
column = (min.column + max.column) / 2;
}
};
Coordinate findElement(vector<vector<int>> matrix, Coordinate origin, Coordinate dest, int x);
Coordinate findElement(vector<vector<int>> matrix, int x)
{
Coordinate origin(0, 0);
Coordinate dest(matrix.size() - 1, matrix[0].size() - 1);
return findElement(matrix, origin, dest, x);
}
Coordinate partitionAndSearch(vector<vector<int>> matrix, Coordinate origin, Coordinate dest, Coordinate pivot, int x)
{
Coordinate lowerLeftOrigin(pivot.row, origin.column);
Coordinate lowerLeftDest(dest.row, pivot.column - 1);
Coordinate upperRightOrigin(origin.row, pivot.column);
Coordinate upperRightDest(pivot.row - 1, dest.column);
Coordinate lowerLeft = findElement(matrix, lowerLeftOrigin, lowerLeftDest, x);
if (!lowerLeft.isFinded)
{
return findElement(matrix, upperRightOrigin, upperRightDest, x);
}
return lowerLeft;
}
Coordinate findElement(vector<vector<int>> matrix, Coordinate origin, Coordinate dest, int x)
{
if (!origin.inbounds(matrix) || !dest.inbounds(matrix))
{
origin.isFinded = false;
return origin;
}
if (matrix[origin.row][origin.column] == x)
{
cout << "elements find!!!!!!!!!" << endl;
cout << "row=" << origin.row << " column=" << origin.column << endl;
origin.isFinded = true;
return origin;
}
else if (!origin.isBefore(dest))
{
origin.isFinded = false;
return origin;
}
/* Set start to start of diagonal and end to the end of the diagonal. Since
* the grid may not be square, the end of the diagonal may not equal dest.
*/
Coordinate start = origin;
int diagDist = min(dest.row - origin.row, dest.column - origin.column);
Coordinate end(start.row + diagDist, start.column + diagDist);
Coordinate p(0, 0);
/* Do binary search on the diagonal, looking for the first element greater than x */
while (start.isBefore(end))
{
p.setToAverage(start, end);
if (x > matrix[p.row][p.column])
{
start.row = p.row + 1;
start.column = p.column + 1;
}
else if(x < matrix[p.row][p.column])
{
end.row = p.row - 1;
end.column = p.column - 1;
}
//对于部分对角线上的元素可以快速找到
else if (x == matrix[p.row][p.column])
{
cout << "elements fast find!!!!!!" << endl;
cout << "row=" << p.row << " column=" << p.column << endl;
p.isFinded = true;
return p;
}
}
/* Split the grid into quadrants. Search the bottom left and the top right. */
return partitionAndSearch(matrix, origin, dest, start, x);
}
//测试程序
int main()
{
vector<vector<int>> matrix = { {15, 30, 50, 70, 73},
{35, 40, 100, 102, 120},
{36, 42, 105, 110, 125},
{46, 51, 106, 111, 130},
{48, 55, 109, 140, 150} };
int m = matrix.size();
int n = matrix[0].size();
int count = 0;
int littleOverTheMax = matrix[m - 1][n - 1] + 10;
for (int i = 0; i < littleOverTheMax; i++)
{
Coordinate c = findElement(matrix, i);
if (c.isFinded)
{
cout<<i<<": ("<<c.row<<", "<<c.column<<")"<<endl;
count++;
}
}
cout << "Found " << count << " unique elements." << endl;
}