题目:二维数组中,每行从左到右递增,每列从上到下递增,设计一个算法,找其中的一个数
分析:
二维数组这里把它看作一个矩形结构,如图所示:
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
在做这道题的时候我最先考虑的是每次比较对角线上的元素可能可以取得较好的效果,
以查找9为例,
从1(0,0)开始,1<10,可以得出结论,10在1的右侧或下侧;
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
然后看4(1,1),4<9,
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
然后看10(2,2),10>9,这个时候可以确定在10的右上方,或者左下方,
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
然后可以考虑使用递归黄色的两个方框,设an>x时是(x,y),an-k>x时是(x0,y0),那么此次递归的起始点因该是:右上(x,y0),左下(x0,y)。
左下的方框,4(2,0),4<9;再看8(3,1),8<10,可以确定不在左下方框;
右上的方框,8(0,2),8<9;再看12(1,3),12>9,再次递归,(1,2)或(0,3)都可以找到。
看似可以解决问题,但是,这个时候的矩形必须是正方形才行。。。。。。
如上图所示,就没办法了(当然,可以通过宽高的关系,计算出选择纵向移动多少次,横向移动 多少次,可以正好走个对角,但是,太麻烦了。。。。),所以,这么想是不对滴。。。。。。
然后我们考虑可以通过比较一次后可以去掉一行或者一列,那这个方法也可以算不错的了。
以查找10为例,
1.如果从左上角开始找,1<10,发现除了一个个往后比没有什么更好的办法了 ;
2.如果从右上角(0,3)开始找,9<10,由于每行从左到右递增,所以可以把第一行(0)排除掉了;
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
然后看第二行最后一个数(1,3),12>10,由于每列从上到下递增,所以可以把最后一列(3)排除;
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
然后看(1,2),9<10,排除行1;
1 | 2 | 8 | 9 |
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
然后看(2,2),10==10,找到目标,返回行列号。
3.除了从右上角开始分析有较好的效果外,可以发现从左下角也可以以经过一次比较排除一行或者是一列;从右下角分析则同1一样,效率不高。
代码:
package study; /** * 二维数组中,每行从左到右递增,每列从上到下递增, * 设计一个算法找其中的一个数 * @author cnx * @CreateDate ; 2014年9月28日 上午10:14:21 */ public class FindInMatrix { public static void main(String[] args) { FindInMatrix f = new FindInMatrix(); int a[] = f.find(f.a1, 12); if(a!=null) System.out.println("a1 find 12. row= "+a[0]+"; col="+a[1]); a = f.find(f.a2, 18); System.out.println("a2 find 18. row= "+a[0]+"; col="+a[1]); a = f.find(f.a2, 2); System.out.println("a2 find 2. row= "+a[0]+"; col="+a[1]); a = f.find(f.a2, 7); System.out.println("a2 find 7. row= "+a[0]+"; col="+a[1]); } public int a1 [][] = null; public int a2 [][] = {{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}}; //查找18,2,7 public int[] find(int a[][], int des){ //存行列数 int result[] = {-1,-1}; if(a != null && a.length>0 && a[0].length>0){ int row = 0; int col = a[0].length-1; while (row<a.length && col>=0) { // System.out.println(a.length + " ," +a[0].length); if (a[row][col] == des) { result[0] = row; result[1] = col; break; } if (a[row][col] > des) { col--; } else { row++; } } } else result = null; return result; } }