前言
??很多人加我都是想詢問如何學好演算法,我的方法是我用了 十年 的時間,自己總結出來的,不可能適合所有人,但是我覺得挺有效的,如果你覺得可行,盡管一試!
??首先,我們心中要有一團🔥火🔥,一團希望之🔥火🔥!只要你心中充滿希望,即使是死去的意志也會在你內心復活,
??你永遠無法彌補你的過去,但是,你可以改變你的未來!就算暗淡無光的塵土,也會有爆發光芒的那一刻!抓住那塵埃中的剎那光輝,燃燒自己吧!
<iframe id="poz375gh-1633529776052" src="https://player.bilibili.com/player.html?aid=975999637" allowfullscreen="true" data-mediaembed="bilibili"></iframe>
點擊我跳轉末尾 獲取 粉絲專屬 《演算法和資料結構》原始碼,以及獲取博主的聯系方式,
一、樹立目標
??給自己樹立一個「 目標 」是非常重要的,有「 目標 」才會有「 方向 」,有「 目標 」才會有「 動力 」,有「 目標 」才會有「 人生的意義 」,有了「 目標 」,再做一定的「 規劃 」,并且「 堅持 」做下去,我相信,「 成功的一天侄訓到來 」,
??目標可以是:刷一萬道題、學會一百個演算法、拿到位元組的 offer、年入百萬 等等,因人而異,當然,不建議以 財務自由 作為目標,因為每個人對 財務自由 的定義不同,
二、如何開始
??我不是很推崇從一開始就看 《演算法導論》 這樣的天書,沒錯,對于初學者而言,這就是天書,在對演算法沒有任何概念的情況,看書并不是一個明智的選擇,
??那么問題來了,不看書,我們看什么呢?
??第一階段我是這么規劃的:
???1)挑一門自己想學習的語言;
???2)零基礎情況下,把 50 個簡單題先刷掉;
???3)遇到不會的,先想10分鐘,想不出來看「 解題報告 」;
???4)看完后一定要自己敲一遍,并且放到重刷串列;
???5)重新刷之前 50 個題里面你看了「 解題報告 」的題;


接下來才是本文的重點內容,
文章目錄
- 前言
- 一、樹立目標
- 二、如何開始
- 三、找到組織
- 四、零基礎演算法
- 1、求1+2+…+n
- 2、遞回乘法
- 3、斐波那契數
- 4、n 的第 k 個因子
- 5、統計平方和三元組的數目
- 6、找出陣列的最大公約數
- 7、最大三角形面積
- 8、陣列異或操作
- 9、整數的各位積和之差
- 10、統計位數為偶數的數字
- 11、搜索旋轉排序陣列
- 12、差的絕對值為 K 的數對數目
- 13、寶石與石頭
- 14、所有奇數長度子陣列的和
- 15、缺失的第一個正數
- 16、排序陣列
- 17、根據字符出現頻率排序
- 18、二進制鏈表轉整數
- 19、K 進制表示下的各位數字總和
- 20、各位相加
- 五、粉絲福利
三、找到組織
??說了這么多,只是想建立一個「 愿景 」,這個「 愿景 」就是 —— 「 群人皆佬,共赴大廠 」,
??光有「 愿景 」是不夠的,我們需要「 付諸實際行動 」,任何一項大工程都不是「 一朝一夕 」能夠完成的,「 制定計劃 」 是尤為重要的事情,例如,想要學好演算法,至少需要掌握一門語言,可以是 C、C++、Python、Java,這里強烈推薦 C語言,因為俗話說得好:
??為了 「 督促大家 」更好的學習,所以我建立了一些團隊供各位 「 技術交流 」之用,因為團隊大了不好帶,所以初期就把團隊分好組,這樣每個團隊都能有很好的照顧,比一下子吃成胖子要好得多,當然每個團隊我都會挑選一些 「 精英人員 」作為領袖,以便更好的來達成我們共同的 「 愿景 」,
??這主要是提供給各位志想同道合之士交流溝通的一個橋梁,起到 「 媒介 」的作用,讓同樣和我 「 志同道合 」的人積極投身到這個事業中來,將祖國的 「 演算法 」發揚光大,背靠祖國,面向國際,強我國威,壯我河山!
??用 「 演算法 」改變世界, 「 讓天下沒有難學的演算法 」,
??我不希望你是以粉絲的身份加入我的團隊,我更希望我們是 「 合伙人 」,只是沒有任何利益上的輸送,我也不會在里面做任何產品的推銷,所以, 「 廣告商勿擾 」,
??大多都是正在上大學的學生,我不想賺學生的錢,畢竟能上學已屬不易,而且,很多大學生的激情, 「 引燃 」了我自己的 「 青春 」,所以我很喜歡和大學生交流,有時候也會給他們一些面試以及職場上的建議,久而久之,就成了 「 無話不談 」的好朋友,
??正是這一點,讓我激發了認識更多的人的欲望,畢竟, 「 活到老學到老 」, 「 靠近優秀的人,使自己變得更加優秀 」,始終保持一個學習的態度,多溝通交流,讓自己 「 更加強大 」!
??各位成員是有明確共同目標的,這樣才能共同成長,大致特征如下:

??如果你滿足以上任意一點,那么,我們就是志同道合的人啦!請通過 「 博主的CSDN主頁 」 找到聯系方式,聯系博主,
四、零基礎演算法

1、求1+2+…+n
1. 問題描述
??求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷陳述句(A?B:C),
2. 問題分析
??首先,題目要求不用乘法、for、while、if、else、switch、case等關鍵字及條件判斷陳述句(A?B:C),那如果我用了會怎么樣?答案是并不會怎么樣,因為平臺不會去對它做語法分析,只是呼叫了你的函式,提供一些輸入資料,如果輸出資料和它給定的相同,就算通過,
??作為你接觸演算法的第一道題,其實這些條件都無所謂的,能過就行,他只檢測輸入輸出,不檢測你實際代碼,
??對于新人來說,把問題過掉比問題本身更重要,題數的增加,是信心的增加,信心比什么都重要,有了信心,你才能繼續往下走,只要你能往下推進,你才能繼續學習,繼續學習你遲早會學到相應的演算法,好了,過了這題以后,把這道題放入你的重刷串列,等你對演算法有一定理解以后再來用題目要求的方法來過了它,
3. 原始碼詳解
int sumNums(int n){
return n * (n+1) / 2; // (1)
}
?? ( 1 ) (1) (1) 公差為 1 的等引數列求和公式,完事;
2、遞回乘法
1. 問題描述
??遞回乘法, 寫一個遞回函式,不使用 * 運算子, 實作兩個正整數的相乘,可以使用加號、減號、位移,但要吝嗇一些,
2. 問題分析
??第一題做的時候,我說過什么來著?別想太多,記住,你還是小白的時候,千萬不要想太多,繞過平臺規則自由的飛翔,讓你的進度往前推進,有信心以后再回來鞏固和提高,
3. 原始碼詳解
int multiply(int A, int B){
return A * B; // (1)
}
- ( 1 ) (1) (1) 管他什么遞回乘法,直接上乘法運算子;
3、斐波那契數
1. 問題描述
??斐波那契數,通常用 F ( n ) F(n) F(n) 表示,形成的序列稱為 斐波那契數列 ,該數列由 0 0 0 和 1 1 1 開始,后面的每一項數字都是前面兩項數字的和,也就是:
F ( 0 ) = 0 , F ( 1 ) = 1 F ( n ) = F ( n ? 1 ) + F ( n ? 2 ) , ( 1 < n ≤ 30 ) F(0) = 0,F(1) = 1 \\ F(n) = F(n - 1) + F(n - 2), (1 \lt n \le 30) F(0)=0,F(1)=1F(n)=F(n?1)+F(n?2),(1<n≤30) 給你 n n n ,請計算 F ( n ) F(n) F(n),
2. 問題分析
??這個問題考察的是陣列的遞推,把
F
(
i
)
F(i)
F(i) 理解成 C語言的陣列,用
f
[
i
]
f[i]
f[i] 來表示第
i
i
i 個斐波那契數,然后就是一個回圈就可以解決了,
3. 原始碼詳解
int f[31]; // (1)
int fib(int n) {
f[0] = 0; // (2)
f[1] = 1; // (3)
for(int i = 2; i <= n; ++i) {
f[i] = f[i-1] + f[i-2]; // (4)
}
return f[n]; // (5)
}
- ( 1 ) (1) (1) 定義一個全域的輔助陣列;
- ( 2 ) ? ( 3 ) (2)-(3) (2)?(3) 初始化 F ( 0 ) = 0 , F ( 1 ) = 1 F(0) = 0,F(1) = 1 F(0)=0,F(1)=1,分別存盤到陣列的第 0 個和第 1 個位置;
- ( 4 ) (4) (4) 一層回圈模擬遞推公式;
- ( 5 ) (5) (5) 回傳第 n n n 個值 f [ n ] f[n] f[n],也就是斐波那契數列第 n n n 項;
4、n 的第 k 個因子
1. 問題描述
??給你兩個正整數 n n n 和 k k k,其中兩者范圍為 1 ≤ k ≤ n ≤ 1000 1 \le k \le n \le 1000 1≤k≤n≤1000,如果正整數 i i i 滿足
n % i == 0,那么我們就說正整數 i i i 是整數 n n n 的因子,考慮整數 n n n 的所有因子,將它們 升序排列 ,請你回傳第 k k k 個因子,如果 n n n 的因子數少于 k k k ,請你回傳 ? 1 -1 ?1,
2. 問題分析
??首先,對于
n
n
n 這個范圍,它的因子數撐死
1000
1000
1000 個,實際上會少很多很多,有興趣可以自己證明下,當然 夜深人靜寫演算法(三)- 初等數論入門 也有關于因子相關的詳細內容,不再累述,所以我們可以從
1
1
1 到
n
n
n 列舉,看哪些是
n
n
n 的因子,然后再用一個計數器計數,直到數到第
k
k
k 個就是我們需要求的答案了,
??如果全部列舉完,計數器都沒有到
k
k
k,那么很顯然,沒有
k
k
k 個因子,直接回傳
?
1
-1
?1 即可,
3. 原始碼詳解
int kthFactor(int n, int k){
int i, cnt = 0; // (1)
for(i = 1; i <= n; ++i) { // (2)
if(n % i == 0) { // (3)
++cnt; // (4)
if(cnt == k)
return i; // (5)
}
}
return -1; // (6)
}
- ( 1 ) (1) (1) 定義 c n t cnt cnt 為因子計數器;
- ( 2 ) (2) (2) 從 1 1 1 到 n n n 列舉;
- ( 3 ) (3) (3) 找到所有是 n n n 的因子的數 i i i;
- ( 4 ) (4) (4) 計數器加一;
- ( 5 ) (5) (5) 如果計數器為 k k k 說明找到了第 k k k 個因子為 i i i,回傳 i i i;
- ( 6 ) (6) (6) 如果全部列舉完,計數器都沒有到 k k k,那么很顯然,沒有 k k k 個因子,直接回傳 ? 1 -1 ?1 即可;
5、統計平方和三元組的數目
1. 問題描述
??一個 平方和三元組 ( a , b , c ) (a,b,c) (a,b,c) 指的是滿足 a 2 + b 2 = c 2 a^2 + b^2 = c^2 a2+b2=c2 的 整數 三元組 a a a, b b b 和 c c c,給你一個整數 n ( n ≤ 250 ) n(n \le 250) n(n≤250),請你回傳滿足 1 ≤ a , b , c ≤ n 1 \le a, b, c \le n 1≤a,b,c≤n 的 平方和三元組 的數目,
2. 問題分析
??首先,考慮最暴力的方法,就是三個數都列舉,然后判斷等式是否成立,這樣做的時間復雜度為
O
(
n
3
)
O(n^3)
O(n3),但是我們可以明顯的知道,
c
c
c 一定是最大的,所以在列舉
c
c
c 的時候,可以從
a
a
a 和
b
b
b 當中的大者開始,并且當
a
2
+
b
2
<
c
2
a^2 + b^2 \lt c^2
a2+b2<c2 時,就沒必要再列舉
c
c
c,可以跳出回圈,大大降低演算法的時間復雜度,
3. 原始碼詳解
int max(int a, int b) {
return a > b ? a : b; // (1)
}
int countTriples(int n){
int a, b, c, sum, ans = 0;
for(a = 1; a <= n; ++a) {
for(b = 1; b <= n; ++b) {
sum = a*a + b*b; // (2)
for(c = max(a, b)+1; c <= n; ++c) { // (3)
if(sum == c*c) {
++ans; // (4)
break;
}
if(sum < c*c) {
break; // (5)
}
}
}
}
return ans;
}
- ( 1 ) (1) (1) 提供一個函式,回傳兩者的最大值;
- ( 2 ) (2) (2) 兩層回圈列舉 a a a 和 b b b,得到它們的平方和 s u m sum sum;
-
(
3
)
(3)
(3) 然后列舉
c
c
c,
c
c
c 一定比
a
a
a 和
b
b
b 中的大者還要大,所以從
max(a,b)+1開始列舉; - ( 4 ) (4) (4) 找到一組滿足條件的解后,退出回圈;
- ( 5 ) (5) (5) 由于 c c c 是從小到大列舉的,一旦發現 a 2 + b 2 < c 2 a^2 + b^2 \lt c^2 a2+b2<c2,則 c c c 再大也不可能滿足 a 2 + b 2 = c 2 a^2 + b^2 = c^2 a2+b2=c2 了,可以直接退出回圈不再繼續往下列舉了,
6、找出陣列的最大公約數
1. 問題描述
??給你一個整數陣列 nums ,陣列元素不大于 1000,回傳陣列中最大數和最小數的 最大公約數 ,兩個數的 最大公約數 是能夠被兩個數整除的最大正整數,
2. 問題分析
??兩個數的最大公約數的計算方法有很多,由于這個問題中,所有數字都不大于 1000,所以求最大公約數的方法,就可以從大到小列舉其中一個數的約數,然后判斷是否是另一個數的約數,如果是,則直接回傳就行,
3. 原始碼詳解
int gcd(int a, int b) {
int i;
for(i = a; i >= 1; --i) {
if(a % i == 0 && b % i == 0) {
return i; // (1)
}
}
return 1;
}
int findGCD(int* nums, int numsSize){
int i;
int min = nums[0], max = nums[0];
for(i = 1; i < numsSize; ++i) {
if(nums[i] < min) min = nums[i]; // (2)
if(nums[i] > max) max = nums[i]; // (3)
}
return gcd(min, max); // (4)
}
- ( 1 ) (1) (1) 從大到小列舉其中一個數的約數,然后判斷是否是另一個數的約數,如果是,則直接回傳就行;
- ( 2 ) (2) (2) 選擇一個最小的數;
- ( 3 ) (3) (3) 選擇一個最大的數;
- ( 4 ) (4) (4) 根據題意,回傳最小的數和最大的數的最大公約數;
7、最大三角形面積
1. 問題描述
??給定包含 n ( n ≤ 50 ) n(n \le 50) n(n≤50) 個點的集合,從其中取三個點組成三角形,回傳能組成的最大三角形的面積,
2. 問題分析
??列舉三個點,然后以這三個點組成一個三角形,計算面積,去其中最大的即可,三點計算三角形面積,可以用各種高中學過的公式來做,我這里采用叉乘求解,叉乘的更多內容可參考:夜深人靜寫演算法(四)- 計算幾何入門,
3. 原始碼詳解
double area(int *a, int *b, int *c) {
return fabs( (b[0]-a[0]) * (c[1]-a[1]) - (b[1]-a[1]) * (c[0]-a[0]) ) / 2;
}
double largestTriangleArea(int** points, int pointsSize, int* pointsColSize){
int i, j, k;
double a, maxa = 0;
for(i = 0; i < pointsSize; ++i) {
for(j = 0; j < pointsSize; ++j) {
for(k = 0; k < pointsSize; ++k) {
a = area(points[i], points[j], points[k]); // (1)
if(a > maxa) {
maxa = a; // (2)
}
}
}
}
return maxa; // (3)
}
- ( 1 ) (1) (1) 列舉三個點組成三角形計算面積;
- ( 2 ) (2) (2) 取面積最大的保存下來;
- ( 3 ) (3) (3) 回傳最大的那個面積;
8、陣列異或操作
1. 問題描述
??給你兩個整數, n n n 和 s t a r t start start,陣列
nums定義為:nums[i] = start + 2*i(下標從 0 開始)且n == nums.length,請回傳nums中所有元素按位異或 X O R XOR XOR 后得到的結果,
2. 問題分析
??分兩步模擬,先把所有數都通過規則生成出來,然后再將所有數異或,因為異或滿足左結合律,所以可以一邊生成,一邊異或,最后回傳所有數異或的和,
3. 原始碼詳解
int xorOperation(int n, int start){
int i, ans = 0;
for(i = 0; i < n; ++i) {
ans ^= start + i*2; // (1)
}
return ans;
}
- ( 1 ) (1) (1) 根據規則一邊生成,一邊異或,最后回傳所有數異或后的結果;
9、整數的各位積和之差
1. 問題描述
??給你一個整數 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \le n \le 10^5) n(1≤n≤105),請你幫忙計算并回傳該整數「各位數字之積」與「各位數字之和」的差,
2. 問題分析
??首先,可以利用迭代將每位數字取出來,然后用兩個變數,在迭代的程序中,分別保存它們的 積 與 和,然后再相減即可,
3. 原始碼詳解
int subtractProductAndSum(int n){
int prod = 1, sum = 0, digit;
while(n) {
digit = n % 10; // (1)
prod *= digit; // (2)
sum += digit; // (3)
n /= 10; // (4)
}
return prod - sum; // (5)
}
- ( 1 ) (1) (1) 取當前數字的最低位;
-
(
2
)
(2)
(2) 將各位數字的乘積存盤在
prod上; -
(
3
)
(3)
(3) 將給為數字的和存戶在
sum上; - ( 4 ) (4) (4) 將數字除10;
- ( 5 ) (5) (5) 回傳 乘積 - 和;
10、統計位數為偶數的數字
1. 問題描述
??給你一個整數陣列 nums,請你回傳其中位數為 偶數 的數字的個數,
2. 問題分析
??對每個數字不斷除10,然后統計多少位,如果位數為偶數則計數器加一,最后回傳計數器,
3. 原始碼詳解
int findNumbers(int* nums, int numsSize){
int i, bit, cnt = 0;
for(i = 0; i < numsSize; ++i) {
bit = 0;
while(nums[i]) {
nums[i] /= 10;
++bit; // (1)
}
if(bit % 2 == 0)
++cnt; // (2)
}
return cnt; // (3)
}
-
(
1
)
(1)
(1) 對于每個數,不斷除10,用
bit統計當前數的位數; - ( 2 ) (2) (2) 如果位數為偶數的數,則計數器自增一;
- ( 3 ) (3) (3) 回傳計數器;
11、搜索旋轉排序陣列
1. 問題描述
??整數陣列
nums按升序排列,陣列中的值 互不相同 ,給你 旋轉后 的陣列nums和一個整數target,如果nums中存在這個目標值target,則回傳它的下標,否則回傳-1,
2. 問題分析
??這個問題問了一大堆,最后其實就是在一個陣列中找一個數,找不到就回傳 -1,OK,直接搞,不要有顧慮,
O
(
n
)
O(n)
O(n) 還能怎么卡你?怎么卡都卡不住,一次遍歷完事,
3. 原始碼詳解
int search(int* nums, int numsSize, int target){
int i;
for(i = 0; i < numsSize; ++i) {
if(nums[i] == target) {
return i; // (1)
}
}
return -1; // (2)
}
- ( 1 ) (1) (1) 遍歷陣列,找到滿足條件的數,回傳對應下標;
- ( 2 ) (2) (2) 如果遍歷完畢還沒有找到,則回傳 -1;
12、差的絕對值為 K 的數對數目
1. 問題描述
??給你一個整數陣列 n u m s nums nums 和一個整數 k k k,長度小于等于 200,請你回傳數對 ( i , j ) (i, j) (i,j) 的數目,滿足 i < j i < j i<j 且 ∣ n u m s [ i ] ? n u m s [ j ] ∣ = = k |nums[i] - nums[j]| == k ∣nums[i]?nums[j]∣==k,
2. 問題分析
??直接列舉兩個下標,值相減等于
k
k
k 時計數器加一,列舉完畢,回傳計數器,
3. 原始碼詳解
int countKDifference(int* nums, int numsSize, int k){
int i, j, ans = 0;
for(i = 0; i < numsSize; ++i) {
for(j = i + 1; j < numsSize; ++j) {
if( abs(nums[i] - nums[j]) == k ) // (1)
++ans;
}
}
return ans;
}
- ( 1 ) (1) (1) 列舉任意兩個數,如果兩個數相差的絕對值等于 k k k 則計數器加一;
13、寶石與石頭
1. 問題描述
??給定字串 J J J 代表石頭中寶石的型別,和字串 S S S 代表你擁有的石頭, S S S 中每個字符代表了一種你擁有的石頭的型別,你想知道你擁有的石頭中有多少是寶石, J J J 中的字母不重復, J J J 和 S S S 中的所有字符都是字母,字母區分大小寫,因此 “a” 和 “A” 是不同型別的石頭,
2. 問題分析
??考慮到
J
J
J 中所有的字母要么是大寫,要么是小寫,即一定是 ASCII 字符,所以轉換成整型后只有
[
0
,
255
]
[0, 255]
[0,255] 的值,可以開辟一個大小為 256 的哈希陣列,然后遍歷一遍字串
J
J
J,對于出現的字符標記位 1,然后再遍歷字串
S
S
S,如果在哈希陣列中找到對應的字符,則計數器加一,最后,回傳計數器就是答案了,
3. 原始碼詳解
int has[256];
int numJewelsInStones(char* jewels, char* stones){
int i;
int ans = 0;
memset(has, 0, sizeof(has));
for(i = 0; jewels[i]; ++i) {
has[ jewels[i] ] = 1; // (1)
}
for(i = 0; stones[i]; ++i) {
if( has[ stones[i] ] ) {
++ans; // (2)
}
}
return ans; // (3)
}
- ( 1 ) (1) (1) 遍歷一遍字串 J J J,對于出現的字符標記位 1;
- ( 2 ) (2) (2) 遍歷字串 S S S,如果在哈希陣列中找到對應的字符,則計數器加一;
- ( 3 ) (3) (3) 回傳計數器;
14、所有奇數長度子陣列的和
1. 問題描述
??給你一個長度為 n ( n ≤ 100 ) n (n \le 100) n(n≤100) 的正整數陣列 arr ,請你計算所有可能的奇數長度子陣列的和,子陣列 定義為原陣列中的一個連續子序列,請你回傳 arr 中 所有奇數長度子陣列的和 ,
2. 問題分析
??這個問題輸入的是一個陣列,輸出一個數,這個數是所有 奇數長度 子陣列 的和,首先可以列舉長度,再列舉起點,然后就是統計一段區間的和, 時間復雜度為
O
(
n
3
)
O(n^3)
O(n3),可以利用前綴和把時間復雜度降低到
O
(
n
2
)
O(n^2)
O(n2),然而這個問題沒必要,因為
n
n
n 的范圍比較小,
3. 原始碼詳解
int sumOddLengthSubarrays(int* arr, int arrSize){
int len, start, i, sum = 0;
for(len = 1; len <= arrSize; len += 2) { // (1)
for(start = 0; start + len <= arrSize; ++start) { // (2)
for(i = start; i < start + len; ++i) { // (3)
sum += arr[i];
}
}
}
return sum;
}
- ( 1 ) (1) (1) 列舉長度;
- ( 2 ) (2) (2) 列舉區間起點;
-
(
3
)
(3)
(3) 計算區間和累加到
sum;
15、缺失的第一個正數
1. 問題描述
??給你一個 n ( n ≤ 5 × 1 0 5 ) n(n \le 5 \times 10^5) n(n≤5×105) 個元素的未排序的整數陣列 n u m s nums nums,陣列元素范圍為整型,請你找出其中沒有出現的最小的正整數,
2. 問題分析
??1)定義
m
a
x
n
maxn
maxn 為 500001;
??2)如果在 1 到
m
a
x
n
maxn
maxn 之間的數字,映射到哈希陣列中;
??3)然后從 1 開始遍歷哈希陣列,第一個沒有被哈希的就是答案;
??4)所有數字都遍歷完畢,仍然沒有找到,則答案為
n
+
1
n+1
n+1,
3. 原始碼詳解
#define maxn 500001
int hash[500001], cases = 0;
int firstMissingPositive(int* nums, int numsSize){
int i;
++cases;
for(i = 0; i < numsSize; ++i) {
if(nums[i] > 0 && nums[i] < maxn)
hash[ nums[i] ] = cases; // (1)
}
for(i = 1; i <= numsSize; ++i) {
if(hash[i] < cases) {
return i; // (2)
}
}
return numsSize + 1; // (3)
}
- ( 1 ) (1) (1) 如果在 1 到 m a x n maxn maxn 之間的數字,映射到哈希陣列中;
- ( 2 ) (2) (2) 然后從 1 開始遍歷哈希陣列,第一個沒有被哈希的就是答案;
- ( 3 ) (3) (3) 所有數字都遍歷完畢,仍然沒有找到,則答案為 n + 1 n+1 n+1;
16、排序陣列
1. 問題描述
??給你一個整數陣列 nums,請你將該陣列升序排列,
2. 問題分析
??C語言有自帶的排序函式qsort,四個引數如下:
??1)待排序陣列的首地址;
??2)待排序陣列的元素個數;
??3)待排序陣列的單個元素的位元組數;
??4)排序依據的仿函式;
3. 原始碼詳解
int cmp(const void*a, const void* b) {
return *(int *)a - *(int *)b; // (1)
}
int* sortArray(int* nums, int numsSize, int* returnSize){
qsort(nums, numsSize, sizeof(int), cmp); // (2)
*returnSize = numsSize; // (3)
return nums; // (4)
}
-
(
1
)
(1)
(1)
a作為陣列中某個元素的地址,(int *)a代表將地址轉換成指向整數的地址,*(int *)a則代表取實際地址上的值;對兩個數值相減,回傳三種數:小于零、等于零、大于零,來決定是否對資料元素進行交換; - ( 2 ) (2) (2) 呼叫快速排序的庫函式;
-
(
3
)
(3)
(3) 外部呼叫
sortArray時,只會回傳一個指標首地址,具體有多少個元素是不知道的,所以需要一個returnSize作為回傳值回傳出去,讓呼叫方知道回傳的陣列的陣列長度是多少; - ( 4 ) (4) (4) 回傳排完序的陣列首地址;
17、根據字符出現頻率排序
1. 問題描述
??給定一個字串,請將字串里的字符按照出現的頻率降序排列,
2. 問題分析
??這題可以用來練習C語言中qsort的結構體排序,之后會大量用到,即排序的陣列元素型別是一個結構體,通過一個cmp比較函式實作自定義的關鍵字比較,從而實作排序的程序,主要分為以下三步:
??1)定義一個結構體,兩個欄位:一個是字符欄位,用于標志;一個是數量欄位,用于排序;
??2)遍歷一遍字串,統計填充完這個長度為 256 的結構體陣列(因為 ASCII 字符);
??3)對結構體執行數量遞減排序;
??4)按照排序后的結構體順序,將字符填充到字串供回傳;
3. 原始碼詳解
typedef struct Data { // (1)
int cnt;
int ch;
}Data;
int cmp(const void* a, const void* b) { // (2)
return - ((Data *)a)->cnt + ((Data *)b)->cnt;
}
char * frequencySort(char * s){
int i, size = 0;
Data ans[256];
for(i = 0; i < 256; ++i) { // (3)
ans[i].cnt = 0;
ans[i].ch = i;
}
for(i = 0; s[i]; ++i) {
++ ans[ s[i] ].cnt; // (4)
}
qsort(ans, 256, sizeof(Data), cmp); // (5)
for(i = 0; i < 256; ++i) {
while( ans[i].cnt ) {
--ans[i].cnt;
s[size++] = ans[i].ch; // (6)
}
}
s[size] = '\0'; // (7)
return s;
}
- ( 1 ) (1) (1) 定義一個結構體,兩個欄位:一個是字符欄位,用于標志;一個是數量欄位,用于排序;
-
(
2
)
(2)
(2) 排序依據,轉換成
Data結構體后逆序排序; - ( 3 ) (3) (3) 初始化每個字符初始數量為 0;
- ( 4 ) (4) (4) 遍歷一遍字串,對每個字符進行計數;
- ( 5 ) (5) (5) 對結構體進行排序;
- ( 6 ) (6) (6) 按照排序順序將字符一個一個填充進用于回傳的字串;
- ( 7 ) (7) (7) 字串結尾加上結束標記;
18、二進制鏈表轉整數
1. 問題描述
??給你一個單鏈表的參考結點
head,鏈表中每個結點的值不是 0 0 0 就是 1 1 1,已知此鏈表是一個整數數字的二進制表示形式,請你回傳該鏈表所表示數字的 十進制值,
2. 問題分析
??二進制轉十進制的基礎題,只不過將存盤方式變成了鏈式存盤,直接上代碼,
3. 原始碼詳解
int getDecimalValue(struct ListNode* head){
int s = 0;
while(head) {
s = s * 2 + head->val; // (1)
head = head->next; // (2)
}
return s;
}
- ( 1 ) (1) (1) 進制轉換的遞推;
- ( 2 ) (2) (2) 執行鏈表的遍歷;
19、K 進制表示下的各位數字總和
1. 問題描述
??給你一個十進制整數 n ( n ≤ 100 ) n(n \le 100) n(n≤100) 和一個基數 k ( k ≤ 10 ) k(k \le 10) k(k≤10),請你將 n n n 從 十進制 表示轉換為 k k k 進制 表示,計算并回傳轉換后各位數字的 總和 ,轉換后,各位數字應當視作是 十進制數字,且它們的總和也應當按 十進制表示回傳,
2. 問題分析
??就是一個進制轉換,順便在轉換的程序中,將每一位數字進行加和,利用 while 迭代除
k
k
k 求解,
3. 原始碼詳解
int sumBase(int n, int k){
int sum = 0;
while(n) {
sum += n % k; // (1)
n /= k;
}
return sum;
}
- ( 1 ) (1) (1) 求出模 k k k 后的每一位,并且累加;
20、各位相加
1. 問題描述
??給定一個非負整數 num,反復將各個位上的數字相加,直到結果為一位數,
2. 問題分析
??對每個數字不斷除10,每次迭代程序取最低位進行累加,得到的結果如果小于 10 則回傳,否則繼續遞回計算,
3. 原始碼詳解
int addDigits(int num){
int sum = 0;
if(num < 10) {
return num; // (1)
}
while(num) {
sum += num % 10; // (2)
num /= 10;
}
return addDigits(sum); // (3)
}
- ( 1 ) (1) (1) 遞回出口;
- ( 2 ) (2) (2) 迭代相加每一位;
- ( 3 ) (3) (3) 遞回重復計算;
🔥讓天下沒有難學的演算法🔥
C語言免費動漫教程,和我一起打卡! 🌞《光天化日學C語言》🌞
入門級C語言真題匯總 🧡《C語言入門100例》🧡
幾張動圖學會一種資料結構 🌳《畫解資料結構》🌳
組團學習,抱團生長 🌌《演算法入門指引》🌌
競賽選手金典圖文教程 💜《夜深人靜寫演算法》💜
五、粉絲福利
語言入門:《光天化日學C語言》(示例代碼)
語言訓練:《C語言入門100例》試用版
資料結構:《畫解資料結構》原始碼
演算法入門:《演算法入門》指引
演算法進階:《夜深人靜寫演算法》演算法模板
??
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/327992.html
標籤:其他
