本系列博客習(xí)題來自《算法(第四版)》,算是本人的讀書筆記肆饶,如果有人在讀這本書的以舒,歡迎大家多多交流脂倦。為了方便討論,本人新建了一個(gè)微信群(算法交流),想要加入的,請(qǐng)?zhí)砑游业奈⑿盘?hào):zhujinhui207407 謝謝。另外,本人的個(gè)人博客 http://www.kyson.cn 也在不停的更新中,歡迎一起討論
知識(shí)點(diǎn)
- 矩陣的概念
- 線性代數(shù)概念
- 凱利介紹
題目
1.4.19 矩陣的局部最小元素笼蛛。給定一個(gè)含有 N^2 個(gè)不同整數(shù)的 N×N 數(shù)組 a[]。設(shè)計(jì)一個(gè)運(yùn)算時(shí)間和 N 成正比的算法來找出一個(gè)局部最小元素:滿足 a[i][j] < a[i+1][j]蛉鹿、a[i][j] < a[i][j+1]滨砍、a[i][j] < a[i-1][j] 以及 a[i][j] < a[i][j-1] 的索引 i 和 j。程序運(yùn)行時(shí)間在最壞情況下應(yīng)該和 N 成正比妖异。
1.4.19 Local minimum of a matrix. Given an N-by-N array a[] of N 2 distinct integers, design an algorithm that runs in time proportional to N to find a local minimum: a pair of indices i and j such that a[i][j] < a[i+1][j], a[i][j] < a[i][j+1], a[i][j] < a[i-1][j], and a[i][j] < a[i][j-1]. The running time of your program should be proportional to N in the worst case.
分析
我們首先要注意的是惋戏,這是一個(gè)正方形的矩陣。關(guān)于矩陣的定義這里不多說了他膳,這是個(gè)很宏大的主題响逢,這里就貼點(diǎn)概念性的東西吧。
在數(shù)學(xué)中棕孙,矩陣(Matrix)是一個(gè)按照長(zhǎng)方陣列排列的復(fù)數(shù)或?qū)崝?shù)集合舔亭,最早來自于方程組的系數(shù)及常數(shù)所構(gòu)成的方陣。這一概念由19世紀(jì)英國(guó)數(shù)學(xué)家凱利(又譯做“凱萊”)首先提出蟀俊。
所以钦铺,矩陣的發(fā)明者是凱利,那下面講一下關(guān)于凱利這個(gè)人肢预。
凱利是英國(guó)數(shù)學(xué)家矛洞。生于里士滿 (Richmond),卒于劍橋烫映。17歲時(shí)考入劍橋大學(xué)的三一學(xué)院 沼本,畢業(yè)后留校講授數(shù)學(xué),幾年內(nèi)發(fā)表論文數(shù)十篇锭沟。1846年轉(zhuǎn)攻法律學(xué)抽兆,三年后成為律師,工作卓有成效族淮。任職期間郊丛,他仍業(yè)馀研究數(shù)學(xué),并結(jié)識(shí)數(shù)學(xué)家西爾維斯特(Sylvester)瞧筛。1863年應(yīng)邀返回劍橋大學(xué)任數(shù)學(xué)教授。他得到牛津大學(xué)导盅、都柏林大學(xué)和萊頓大學(xué)的名譽(yù)學(xué)位较幌。1859年當(dāng)選為倫敦皇家學(xué)會(huì)會(huì)員。
凱利一生僅出版一本專著白翻,便是1876年的《橢圓函數(shù)初論》乍炉,但發(fā)表了近1000篇論文绢片,其中一些影響極為深遠(yuǎn)。凱利在勸說劍橋大學(xué)接受女學(xué)生中起了很大作用岛琼。他在生前得到了他所處時(shí)代一位科學(xué)家可能得到的幾乎所有重要榮譽(yù)底循。Arthur Cayley
這道題有一定難度,在Stack Overflow上也有一些回答槐瑞,但給出代碼的寥寥無幾熙涤,我們先列幾個(gè)Stack Overflow上的提問以及回答吧:
Find local minimum in n x n matrix in O(n) time
上面給的答案就是一種“滾下山”(roll downhill)的方式,首先找到中間行困檩,并在中間行中找到該行的最小值祠挫,然后判斷它在該列中是不是局部最小值,如果是的話悼沿,那就返回這個(gè)值等舔,否則向該列的小一側(cè)方向移動(dòng),如此循環(huán)往復(fù)糟趾。
Peak Finding
麻省理工學(xué)院的算法入門課也有這道題的詳細(xì)的介紹題目的介紹:假設(shè)你掉入了一個(gè)群山連綿的地方慌植,很口渴,需要找個(gè)水池义郑,那方法是怎么樣的蝶柿。(看來算法真的還是有用處的,可以自救)
提出問題:找出局部最大值或者最小值
建模:把這個(gè)問題歸結(jié)為二維數(shù)組(或矩陣)的找局部最大值問題
看這個(gè)數(shù)組的中間元素不能拆分這個(gè)問題
找出這個(gè)矩陣每列的最大值魔慷,列出來
如果中間列的最大值不是局部最大值只锭,那么找到它的更大值的鄰居。以此類推院尔。這也正是前面我們提到的滾下山”(roll downhill)的方式蜻展。
算出時(shí)間復(fù)雜度是nlgn,能否更快邀摆?
方法:將矩陣分為四個(gè)象限纵顾,得到四個(gè)小矩陣
分析:隨便找個(gè)小矩陣中取得局部最大值,那在整個(gè)大矩陣中也是局部最大值栋盹,這樣就相當(dāng)于只需要解決大問題中的一個(gè)小問題施逾。
算出復(fù)雜度是n,完美解決例获!
如上面的圖可知汉额,他們解決的是局部最大值的問題,但其實(shí)我們的局部最小值也是一樣的解決方案榨汤。
我們的先把滾下山的解法寫出來蠕搜,因?yàn)檫@種比較好理解
public class MatrixLocalMinimum {
private static class IndexPath {
int row;
int column;
}
private IndexPath miniMumIndexPathOfItem(int[][] matrix,IndexPath indexPath){
IndexPath resultItem = new IndexPath();
resultItem.column = indexPath.column;
resultItem.row = indexPath.row;
int currentItem = matrix[indexPath.row][indexPath.column];
int left = matrix[indexPath.row][(indexPath.column - 1) >= 0 ? (indexPath.column - 1) : indexPath.column ];
int right = matrix[indexPath.row][(indexPath.column + 1) <= matrix.length ? (indexPath.column + 1) : indexPath.column ];
int top = matrix[(indexPath.row - 1 ) >= 0 ? (indexPath.row - 1 ) : indexPath.row][indexPath.column];
int bottom = matrix[(indexPath.row + 1 ) <= matrix.length ? (indexPath.row + 1 ) : indexPath.row][indexPath.column];
int[] rounder = {left,right,top,bottom,currentItem};
Arrays.sort(rounder);
if (rounder[0] == currentItem){
System.out.print("row:"+resultItem.row + "column:" + resultItem.column);
return resultItem;
}else if (rounder[0] == left){
resultItem.column = (indexPath.column - 1);
miniMumIndexPathOfItem(matrix,resultItem);
}else if (rounder[0] == right){
resultItem.column = (indexPath.column + 1);
miniMumIndexPathOfItem(matrix,resultItem);
}else if (rounder[0] == top) {
resultItem.row = (indexPath.row - 1);
miniMumIndexPathOfItem(matrix,resultItem);
}else if (rounder[0] == bottom) {
resultItem.row = (indexPath.row + 1);
miniMumIndexPathOfItem(matrix,resultItem);
}else{
}
return resultItem;
}
/**
* 找出數(shù)組中的最小值的index
*/
private static int miniumOfArray(int[] x) {
int indexOfMinium = 0;
int itemOfMinium = Integer.MAX_VALUE;
for (int i = 0; i < x.length; i++) {
if (x[i] < itemOfMinium) {
itemOfMinium = x[i];
indexOfMinium = i;
}
}
return indexOfMinium;
}
public static void main(String[] args) {
int[][] matrix = {
{ 11, 2, 3, 4, 102 },
{ 53, 6, 7, 18, 101 },
{ 12, 11, 10, 89, 100 },
{ 14, 1, 8, 5, 0 },
{ 114,51, 58, 55, 99 }
};
int middleRow = matrix.length / 2;
int[] row = matrix[middleRow];
int index = miniumOfArray(row);
MatrixLocalMinimum localMinimum = new MatrixLocalMinimum();
IndexPath indexPath = new IndexPath();
indexPath.row = middleRow;
indexPath.column = index;
IndexPath resultIndexPath = localMinimum.miniMumIndexPathOfItem(matrix,indexPath);
}
}
但答案要求的是復(fù)雜度為n的解法,我們通過獲取submatrix的解法實(shí)現(xiàn):
答案
代碼索引
廣告
我的首款個(gè)人開發(fā)的APP壁紙寶貝上線了收壕,歡迎大家下載妓灌。