注:如果代码出现了段错误问题,可能是没有考虑到空数组(至少包括
[]、[[]]两种空的二维数组),健壮性也是算法的一部分
一、暴力法
1.分析:遍历数组,如果找到就返回 true
2.代码
// Solution 1: 运行时间:15ms 占用内存:1764k
bool Find(int target, vector > array) {
// for循环代码可以处理空数组,不需单独处理
int rows = array.size();
int columns = array[0].size();
for (int i = 0; i < rows; ++i)
for (int j = 0; j < columns; ++j)
{
if (array[i][j] == target)
return true;
else
continue;
}
return false;
}3.复杂度
时间复杂度:O(n2)
空间复杂度:O(1)
二、N行折半查找法
1.分析:依次对每一行(列)都执行折半查找
2.代码
// Solution 2: 运行时间:15ms 占用内存:1764k
bool Find(int target, vector<vector<int> > array) {
if (array.empty()) return false;
if (array[0].empty()) return false; //处理空数组
int length = array.size();
for (int i = 0; i < length; ++i)
// 对每一列二分查找
for (int begin=0, end=length-1, j=length/2; begin<=end;)
{
if (array[i][j] == target)
return true;
else if (array[i][j] > target)
end = j-1;
else
begin =j+1;
j = begin + (end-begin)/2;
}
return false;
}
3.复杂度
时间复杂度:O(n*lgn)
空间复杂度:O(1)
4.拓展:双折半查找
二维数组分为上下左右四个边界top,bottom,left,right:
对上边界top进行折半查找,假设终止点为E,则可以将二维数组位于终止点E右边的矩形Rr排除,因为终止点E小于其右边相邻的元素E+1,而E+1是右边矩形Rr的最小元素(左上元素)
同理,对下边界bottom折半,可以排除二维数组位于终止点E左边的矩形Rl排除,
对左边界left折半,可以排除二维数组位于终止点E下边的矩形Rb排除,
对右边界right折半,可以排除二维数组位于终止点E上边的矩形Rt排除,
一轮过去,边界范围缩小,对由新边界组成的矩形重复以上操作,直到范围缩小为只有一个元素。
三、十字分割法
我首先想到的是这种方法,不过要注意这种方法无论是从思维还是实现过程都比较麻烦,实战慎用。
1.分析:在主对角线方向上进行查找操作,直到一个元素大于目标,该终止点的左上区域与右下区域都可以排除,再递归剩下的左下、右上两个区域。
2.代码
// Solution 2: 运行时间:12ms 占用内存:1624k
bool Find_2(int target, vector<vector<int> > array) {
if (array.empty())return false;
if (array[0].empty())return false; //处理空数组
//初始化栈
typedef struct {
int xmin=0,ymin=0,xmax,ymax;
} stack_elem;
stack_elem temp, newTemp;
stack<stack_elem> s;
temp.xmax = temp.ymax = array.size()-1;
s.push(temp);
while (!s.empty()){
newTemp = temp = s.top();
s.pop();
int x=temp.xmin, y=temp.ymin;
while (true){
// 首先确定区域是否可能包含目标值
if (array[temp.xmin][temp.ymin]>target || array[temp.xmax][temp.ymax]<target) break;
if (temp.xmin>temp.xmax || temp.ymin>temp.ymax) break;
// 遍历过程节点分为几类
if (array[x][y] == target) return true; // 情况1: 找到目标值
if (array[x][y] > target){ //情况2:找到大于目标值的节点,缩小大区域为两个小区域
newTemp.xmax = x-1;
newTemp.ymin = y;
if (newTemp.xmin<=newTemp.xmax && newTemp.ymin<=newTemp.ymax)
s.push(newTemp);
temp.ymax = y-1;
temp.xmin = x;
y = temp.ymin;
}
else if (x == temp.xmax){ //情况3:处理非正方形区域某一边界先溢出的情况
temp.ymin = y+1;
x = temp.xmin;
++y;
}
else if (y == temp.ymax){
temp.xmin = x+1;
y = temp.ymin;
++x;
}
else {++x,++y;} // 情况4:继续查找
}
}
return 0;
} 3.复杂度
时间复杂度:采用二分查找时为O(lgn)、采用顺序查找时为O(nlgn)
空间复杂度:O(1)
四、左下/右上元素移动法
1.分析:依次对每一行(列)都执行折半查找
2.代码
// Solution 4: 运行时间:10ms 占用内存:1504k
bool Find_3(int target, vector<vector<int> > array) {
if (array.empty())return false;
if (array[0].empty())return false;
int length = array.size();
int row=0, col=length-1;
while (row<length && col>-1){
if (array[row][col]==target) return true;
if (array[row][col]>target) --col;
else ++row;
}
return false;
} 3.复杂度
时间复杂度:O(n)
空间复杂度:O(1)

京公网安备 11010502036488号