一、概要
本文介紹了有關陣列的演算法第一部分的Java
程式碼實現,所有程式碼均可通過 線上編譯器 直接執行,演算法目錄:
- 二維陣列的整數查詢
- 旋轉陣列中的最小數字(旋轉陣列中的最大數字)
- 調整陣列使奇數位於偶數之前
- 找出陣列中出現次數超過一半的數字
二、程式碼實現
2.1 二維陣列的整數查詢
問題描述
在一個二維陣列中,每一行都按照 從左到右遞增的順序,每一列都按照 從上到下遞增的順序 排序,編寫一個函式,輸入這樣的一個二維陣列和一個整數,判斷該整數是否在二位陣列中。
解決思路
首先要確定整數存在於陣列的一個 前提條件:如果最小的元素(左上角)大於d
,或者最大的元素(右下角)小於d
,那麼可以確定矩陣中不存在d
。
這裡需要關注一個特殊的點,二維陣列右上角的元素d
,如果以d
所在的列將陣列分為左右兩個部分,那麼 右邊部分的所有元素都是大於d
的;而如果以d
所在的行將陣列分為上下兩個部分,那麼 上半部分的所有元素都是小於d
的。利用這一特性,我們 從陣列的右上角 開始搜尋:
- 判斷陣列右上角元素是否就是查詢的值
- 如果不是,先按
x
軸的反方向遍歷,從 右至左找到第一個不大於d
的元素。 - 之後再按
y
軸的正方向遍歷,從 上至下找到第一個不小於d
的元素 - 經過以上兩步,會得到一個縮小後的矩陣,檢查前提條件是否仍然滿足,如果不滿足,那麼就說明
p
不存在於陣列中,反之則從第一步開始重複。
實現程式碼
class Untitled {
static Boolean searchMisInt(int p[][], int d, int maxx, int maxy){
int minx = 0; int miny = 0;
while(minx <= maxx && miny <= maxy){
//如果最小的元素(左上角)大於d,或者最大的元素(右下角)小於d,那麼可以確定矩陣中不存在p。
if (p[minx][miny] > d|| p[maxx][maxy] < d)
return false;
//如果右上角的元素和p直接相等,那麼直接返回。
if (d == p[minx][maxy]) {
return true;
}
//不斷縮小矩形的範圍。
while (p[minx][maxy] > d) //從右上角的第一個元素,從右往左,找到第一個不大於d的元素。
maxy -= 1;
while (p[minx][maxy] < d) //從右上角的第一個元素,從上到下,找到第一個不小於d的元素。
minx += 1;
}
return false;
}
public static void main(String[] args) {
int p[][] = { {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
System.out.println("result=" + searchMisInt(p, 10, 3, 3));
}
}
複製程式碼
執行結果:
>> result=true
複製程式碼
2.2 獲得旋轉陣列中的最小數字
問題描述
把一個陣列最開始的若干個元素搬到陣列的末尾,稱為陣列的旋轉。現在輸入一個遞增序列的旋轉陣列,輸出旋轉陣列的最小值,例如{1, 2, 3, 4, 5}
的一個旋轉陣列為{3, 4, 5, 1, 2}
,最小值為1
。
解決思路
加入經過旋轉後的陣列不等於它本身,那麼這個旋轉後的陣列有一個特點:它以最小值作為分界點被分為兩個部分,不包含最小值的前半部分是有序的,包含最小值的後半部分也是有序的,因此我們可以藉助 二分查詢 的思想。
首先獲得當前陣列的中點位置pMid
:
- 如果
pMid
的數值 大於等於 首節點pStart
的數值,那麼說明 pMid 位於前半部分陣列中,因此可以確定最小值在[pMid, pEnd]
之間 - 如果
pMid
的數值 小於等於 末節點pEnd
的數值,那麼說明 pMid 位於後半陣列當中,而pMid
是[pMid,pEnd]
之間最小的元素,因此可以確定最小值在[pStart, pMid]
之間。 - 通過以上兩步驟,不斷縮小陣列的範圍,直到縮小後的陣列只有兩個元素為止,第二個元素的值就是我們要找的最小值。
實現程式碼
class Untitled {
static int rotateMinIndex(int p[], int length){
if (length == 1) {
return 0;
}
int pStart = 0;
int pMid = 0;
int pEnd = length-1;
if (p[pStart] < p[pEnd]) {
return pStart;
}
while (pStart < pEnd - 1) {
pMid = (pStart + pEnd) >> 1;
if (p[pStart] == p[pMid] && p[pMid] == p[pEnd])
return rotateMinIndexOrder(p, pStart, pEnd);
if (p[pMid] >= p[pStart]) //左邊陣列是有序的,最小點在右邊
pStart = pMid;
else if(p[pMid] <= p[pEnd]) //右邊陣列是有序的,最小點在左邊
pEnd = pMid;
}
if (p[pStart] > p[pEnd])
return p[pEnd];
return -1;
}
static int rotateMinIndexOrder(int p[], int pStart, int pEnd){
for(int i = pStart; i < pEnd; i++){
if (p[i+1] < p[i])
return i+1;
}
return pEnd;
}
public static void main(String[] args) {
int p[] = {3, 4, 5, 1, 2};
System.out.println("result=" + rotateMinIndex(p, 5));
}
}
複製程式碼
執行結果
>> result=1
複製程式碼
2.3 調整陣列使奇數位於偶數之前
問題描述
輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,使得所有奇數位於陣列的前半部分,所有偶數位於陣列的後半部分。
解答思路
通過兩個變數pStart
、pEnd
分別記錄從首節點和末節點開始掃描的下標,pStart
從首節點向末節點開始掃描,如果找到一個偶數,那麼停止掃描,讓pEnd
從末節點向首節點開始掃描,直到找到一個奇數,然後和pStart
所指向的偶數交換,這樣就能保證[0, pStart]
之間的都是奇數,而[pEnd, len-1]
之間的都是偶數。
完成交換後,再開始移動pStart
尋找下一個偶數,重複上面的操作,直到pStart
和pEnd
相遇,就可以滿足問題的要求了。
實現程式碼
class Untitled {
static void printArray(int p[]) {
for (int i = 0; i < p.length; i++) {
System.out.print(p[i] + ",");
}
}
static void reverseOddEven(int p[], int length){
int i = 0;
int j = length-1;
int t;
while (true) {
/*i指向陣列length,或指向一個偶數*/
while (i < length && p[i] % 2 != 0)
i++;
/*j指向-1,j指向一個奇數,j的值小於i*/
while (j >= 0 && (p[j] % 2 == 0) && j >= i)
j--;
if (i > j)
break;
t = p[i]; p[i] = p[j]; p[j] = t;
}
}
public static void main(String[] args) {
int p[] = {3, 4, 5, 1, 2};
reverseOddEven(p, p.length);
printArray(p);
}
}
複製程式碼
執行結果:
>> 3,1,5,4,2,
複製程式碼
2.4 找出陣列中出現次數超過一半的數字
問題描述
找出陣列中出現次數超過一半的數字
解決思路
將整個陣列中的元素看成兩類:出現次數超過一半的數字 和 其餘數字。利用一個輔助的變數time
和d
,初始時候將d
設為p[0]
,time
設為1
,開始從頭開始遍歷陣列。
實現程式碼
class Untitled {
static Boolean verifyMoreThanHalf(int p[], int data, int length){
int time = 0;
for (int i = 0; i < length; i++) {
if(p[i] == data)
time++;
}
if ((time << 1) >= length)
return true;
return false;
}
static void moreThanHalf(int p[], int length) {
//初始化
int d = p[0];
int time = 1;
//從第二個元素開始遍歷。
for (int i = 1; i < length; i++) {
if(time == 0){
d = p[i];
time = 1;
}else if(d == p[i])
time += 1;
else
time -= 1;
}
if (verifyMoreThanHalf(p, d, length)) {
System.out.println("出現次數超過一半的元素=" + d);
} else {
System.out.println("沒有次數超過一半的元素");
}
}
public static void main(String[] args) {
int p[] = {1, 2, 3, 2, 2, -1, 2, 2, 8, 2, 2};
moreThanHalf(p, p.length);
}
}
複製程式碼
執行結果
>> 出現次數超過一半的元素=2
複製程式碼
更多文章,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:www.jianshu.com/p/fd82d1899…
- 個人主頁:lizejun.cn
- 個人知識總結目錄:lizejun.cn/categories/