算法知識梳理(4) 數組第一部分

1、概要

本文介紹了有關數組的算法第一部分的Java代碼實現,全部代碼都可經過 在線編譯器 直接運行,算法目錄:java

  • 二維數組的整數查找
  • 旋轉數組中的最小數字(旋轉數組中的最大數字)
  • 調整數組使奇數位於偶數以前
  • 找出數組中出現次數超過一半的數字

2、代碼實現

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},最小值爲1spa

解決思路

加入通過旋轉後的數組不等於它自己,那麼這個旋轉後的數組有一個特色:它以最小值做爲分界點被分爲兩個部分,不包含最小值的前半部分是有序的,包含最小值的後半部分也是有序的,所以咱們能夠藉助 二分查找 的思想。code

首先得到當前數組的中點位置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 調整數組使奇數位於偶數以前

問題描述

輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得全部奇數位於數組的前半部分,全部偶數位於數組的後半部分。get

解答思路

經過兩個變量pStartpEnd分別記錄從首節點和末節點開始掃描的下標,pStart從首節點向末節點開始掃描,若是找到一個偶數,那麼中止掃描,讓pEnd從末節點向首節點開始掃描,直到找到一個奇數,而後和pStart所指向的偶數交換,這樣就能保證[0, pStart]之間的都是奇數,而[pEnd, len-1]之間的都是偶數。編譯器

完成交換後,再開始移動pStart尋找下一個偶數,重複上面的操做,直到pStartpEnd相遇,就能夠知足問題的要求了。string

實現代碼

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 找出數組中出現次數超過一半的數字

問題描述

找出數組中出現次數超過一半的數字

解決思路

將整個數組中的元素當作兩類:出現次數超過一半的數字其他數字。利用一個輔助的變量timed,初始時候將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 知識梳理系列:

相關文章
相關標籤/搜索