從乙個題目引入:
給定乙個序列和正整數m = 8, 求序列中的兩個數 a + b = m
本題最直接的解法就是列舉:
for(int i = 0; i < n; i++)}}
顯然,這個解法的時間複雜度為o(n)
,當n為\(10^5\)的規模是不可承受的
利用序列的遞增特性,我們可以利用以下解法:
反覆執行直到i>=j
成立
while(i < j)else if(a[i] + a[j] < m)else
}
這便是two pointers
思想,充分利用了序列遞增的性質,使複雜度降低到o(n)
假設有兩個遞增序列a和b,要求將他們合併為遞增序列c
解法:
直到i
、j
中的乙個到達序列末端
為止,然後將另乙個序列的所有元素依次加入c中
int mergeabtoc(int a, int b, int c, int n, int m)else
}while(i < n) c[index++] = a[i++];
while(j < m) c[index++] = b[j++];
return index;
}
主要學習二路歸併排序
,其原理為:將序列歸併為\([n/2]\)個組,組內單獨排序;然後將這些組再兩兩歸併排序,生成\([n/4]\)個組,組內再單獨排序;以此類推,直到剩下乙個組為止。歸併排序的時間複雜度為o(nlogn)
利用歸併排序實現
用乙個**來理解:只需要反覆將當前區間[left, right]
分為兩半,對兩個子區間[left, mid]
和[mid+1, right]
分別遞迴進行歸併排序,然後將兩個已經有序的子區間合併為有序序列即可。
/*先實現將兩個陣列合併*/
int maxn = 100;
void merge(int a, int l1, int r1, int l2, int r2)else
}while(i <= r1) temp[index++] = a[i++];
while(j <= r2) temp[index++] = a[j++];
for(int i = 0; i < index; i++)
}
/*將array陣列當前區間[left, right]進行歸併排序*/
void mergesort(int a, int left, int right)
}
void mergesort(int a)}}
}
如果題目中只要求給出歸併排序每一趟結束的序列,那麼可以使用sort函式代替merge
void mergesort(int a)}}
快速排序的平均時間複雜度為o(logn)
,其要解決是:
對於序列a為,調整序列中元素的位置,使得a的左側所有元素不超過a, 右側所有元素都大於a, 如下圖:
解決該題最快的做法就是two pointers思想:
⭕舉例:
進行一次左右劃分:
// 對區間[left, right]進行劃分
int partition(int a, int left, int right)
a[left] = temp;
return left;
}
正式實現快速排序演算法
void quicksort(int a, int left, int right)
}
當序列中元素接近有序時,會達到最壞時間複雜度\(o(n^2)\),產生原因在於主元沒有把當前區間劃分為兩個長度接近的子區間。為了解決這一問題,我們要在序列中隨機選擇乙個主元,雖然最壞的情況下時間複雜度仍可能\(o(n^2)\),但是對於任意輸入資料的期望時間複雜度都能到達\(o(nlogn)\)
#include#include// 引數隨機數需要這兩個標頭檔案
#includeint main()
return 0;
}
rand()
函式只能產生[0, rand_max]
範圍內的整數(rand_max
是stdlib.h
中的乙個常數,不同系統中不同,如可能為:32767),所以想要產生[a,b]
內的隨機數,應該使用rand() % (b - a + 1) + a
。
rand % (b - a + 1) + 0; // 產生範圍[0, b - a]
rand % (b - a + 1) + a; // 產生範圍[a, b]
#include#include#includeint main()
for(int i = 0; i < 10; i++)
}
如果要產生大於rand_max
的隨機數時,可以如下: 演算法思維 two pointers
easy 級例題 給定乙個遞增的具有n個元素的正整數序列arr和乙個正整數s,求序列中兩個不同位置的數a和b,使他們的和恰好等於s,輸出所有滿足條件的結果i和j。如序列arr 和正整數s 9,就有 4 5 和 3 6 本例最簡單的方法就是利用二重迴圈列舉所有的可能性,得出結果。但是這樣做的時間複雜度...
Two pointers技巧的應用
查詢陣列中兩個位置不同的數字之和為sum的個數。先來看看暴力法,粗略估計,時間複雜度為0 n 2 void violence int a,int totalnumber,int sum int count 0 計算不匹配的結果次數 不匹配次數是41次,嗯,看起來結果還不錯的樣子。來看看two poi...
關於Two pointers的個人理解
剛剛在刷題的時候接觸到了一道題,題的大意是給出乙個遞增的數字序列,並給出乙個m,要求找到a,b兩個數字,且和為m,並且atwo pointers思想是對有序陣列的優化遍歷 如果根據題目中的思想,進行兩層列舉,則不可避免地會使時間複雜度到達o n 2 級別。但是可以針對序列遞增這一條進行優化 對這個有...