1. 程式人生 > 其它 >極客時間李煜東演算法訓練營2021版二期

極客時間李煜東演算法訓練營2021版二期

愛學習愛分享 威❤ itspcool

為什麼要學習資料結構和演算法

學習演算法最重要的是什麼?

在學習演算法的過程中,一能解決問題,二對自己有用,是最大的推動力。 而那些抽象的,與程式設計師日常工作關係不大的競賽題,很難提起大多數人的學習興趣。 最好能通過工作中應用的一些案例來切入,利用碎片化時間入門演算法,提升技術競爭力。

順序查詢

順序表查詢。複雜度O(n)

二分查詢

有序表中查詢我們可以使用二分查詢。

/*
eg: [1,3,5,6,7,9] k=6
@return 返回元素的索引下表,找不到就返回-1
*/
int binary_search(int *a,int length,int k){
	int low = 0;
	int high = length-1;
	int mid;

	while(low<high){//bug
		mid = (low+high)/2;
		if (a[mid] < k) low = mid+1; //不+1的話, 會有個bug: 可能 死迴圈
		if (a[mid == k]) return mid;
		if (a[mid] > k) high = mid-1; 
	}

	return -1;
}
注意細節
mid+1/mid-1 , 否則的話,有可能死迴圈

while(low <= high) 而不是  while(low<high)

mid = (low+high)/2;  跟  mid = left + (right - left) / 2; 有什麼區別?

如果搜尋有序數列是[1,2,2,2,2,3]這種,想得到 target 的左側邊界,即索引 1,或者我想得到 target 的右側邊界,即索引 4 ; 這時候怎麼處理呢?

你也許會說,找到一個 target,然後向左或向右線性搜尋不行嗎?可以,但是不好,因為這樣難以保證二分查詢對數級的複雜度了。

尋找左側邊界的二分搜尋

int left_binary_search(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0;
    int right = nums.length; // 注意

    while (left < right) { // 注意
        int mid = left + (right - left) / 2;

        if (nums[mid] == target) { //找到 target 時不要立即返回,而是縮小「搜尋區間」的上界 right
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid; // 注意 , 這裡沒有 -1
        }
    }
    return left;
}

分塊查詢

塊內無序,塊之間有序;可以先二分查詢定位到塊,然後再到塊中順序查詢。

動態查詢

這裡之所以叫 動態查詢表,是因為表結構是查詢的過程中動態生成的。查詢結構通常是二叉排序樹,AVL樹,B- ,B+等。這部分的內容可以去看『二叉樹』章節

雜湊表

雜湊表以複雜度O(1)的成績位列所有查詢演算法之首,大量查詢的資料結構中都可以看到雜湊表的應用。