面試問演算法
❶ 面試經典數據結構和演算法匯總
如果說數據結構是骨架,那麼演算法就是靈魂。沒了骨架,靈魂沒有實體寄託;沒了靈魂,骨架也是個空殼。兩者相輔相成,缺一不可,在開發中起到了砥柱中流的作用。
現在我對各種數據結構和演算法做一總結,對比一下它們的效率
1.數據結構篇
1. 如果讓你手寫個棧和隊列,你還會寫嗎?
2. 開發了那麼多項目,你能自己手寫個健壯的鏈表出來嗎?
3. 下次面試若再被問到二叉樹,希望你能對答如流!
4. 面試還在被紅-黑樹虐?看完這篇輕松搞定面試官 !
2.排序演算法篇
1. 幾個經典的基礎排序演算法,你還記得嗎?
2. 手把手教你學會希爾排序,很簡單!
3. 快速排序演算法到底有多快?
4. 五分鍾教你學會歸並排序
5. 簡單說下二叉樹排序
6. 學會堆排序只需要幾分鍾
7. 圖,這個玩意兒竟然還可以用來排序!
掌握了這些經典的數據結構和演算法,面試啥的基本上沒什麼問題了,特別是對於那些應屆生來說。接下來再總結一下不同數據結構和演算法的效率問題,做一下對比,這也是面試官經常問的問題。
數據結構常用操作效率對比:
常用排序演算法效率的對比:
關於經典的數據結構和演算法,就總結到這,本文建議收藏,利用等公交、各種排隊之時提升自己。這世上天才很少,懶蛋卻很多,你若對得起時間,時間便對得起你。
❷ 面試會出哪些經典演算法題
1、排序演算法∶快速排序、歸並排序、計數排序
2、搜索演算法∶回溯、遞歸、剪枝技巧
3、圖論∶最短路、最小生成樹、網路流建模
4、動態規劃:背包問題、最長子序列、計數問題
5、基礎技巧:分治、倍增、二分、貪心
6、數組與鏈表:單/雙向鏈表、跳舞鏈
7、棧與隊列
8、樹與圖:最近公共祖先、並查集
9、哈希表
10、堆:大/小根堆、可並堆
11、字元串∶字典樹、後綴樹
(2)面試問演算法擴展閱讀:
演算法的重要性:
1、演算法能力能夠准確辨別一個程序員的技術功底是否扎實;
2、演算法能力是發掘程序員的學習能力與成長潛力的關鍵手段;
3、演算法能力能夠協助判斷程序員在面對新問題時,分析並解決問題的能力;
4、演算法能力是設計一個高性能系統、性能優化的必備基礎。
❸ 面試官常問十大經典演算法排序(用python實現)
演算法是一種與語言無關的東西,更確切地說就算解決問題的思路,就是一個通用的思想的問題。代碼本身不重要,演算法思想才是重中之重
我們在面試的時候總會被問到一下演算法,雖然演算法是一些基礎知識,但是難起來也會讓人非常頭疼。
排序演算法應該算是一些簡單且基礎的演算法,但是我們可以從簡單的演算法排序鍛煉我們的演算法思維。這里我就介紹經典十大演算法用python是怎麼實現的。
十大經典演算法可以分為兩大類:
比較排序: 通過對數組中的元素進行比較來實現排序。
非比較排序: 不通過比較來決定元素間的相對次序。
演算法復雜度
冒泡排序比較簡單,幾乎所有語言演算法都會涉及的冒泡演算法。
基本原理是兩兩比較待排序數據的大小 ,當兩個數據的次序不滿足順序條件時即進行交換,反之,則保持不變。
每次選擇一個最小(大)的,直到所有元素都被輸出。
將第一個元素逐個插入到前面的有序數中,直到插完所有元素為止。
從大范圍到小范圍進行比較-交換,是插入排序的一種,它是針對直接插入排序演算法的改進。先對數據進行預處理,使其基本有序,然後再用直接插入的排序演算法排序。
該演算法是採用 分治法 對集合進行排序。
把長度為n的輸入序列分成兩個長度為n/2的子序列,對這兩個子序列分別採用歸並排序,最終合並成序列。
選取一個基準值,小數在左大數在在右。
利用堆這種數據結構所設計的一種排序演算法。
堆是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。利用最大堆和最小堆的特性。
採用字典計數-還原的方法,找出待排序的數組中最大和最小的元素,統計數組中每個值為i的元素出現的次數,對所有的計數累加,將每個元素放在新數組依次排序。
設置一個定量的數組當作空桶;遍歷輸入數據,並且把數據一個一個放到對應的桶里去;對每個不是空的桶進行排序;從不是空的桶里把排好序的數據拼接起來。
元素分布在桶中:
然後,元素在每個桶中排序:
取得數組中的最大數,並取得位數;從最低位開始取每個位組成新的數組;然後進行計數排序。
上面就是我整理的十大排序演算法,希望能幫助大家在演算法方面知識的提升。看懂之後可以去試著自己到電腦上運行一遍。最後說一下每個排序是沒有調用數據的,大家記得實操的時候要調用。
參考地址:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html
❹ 面試演算法題
定義一個函數實現數據類型的轉換
第一個元素是數據標識,第二個元素的數值必須大於等於50才返回,不夠50往後累加,加到最後如果不夠50也直接返回,因為沒有可加的數據了
例子1:
a = [[1,3],[2,51],[3,49],[4,42],[5,42]] #入參
a1 = [[2,54],[4,91],[5,42]] #返回
例子2:
b = [[1,50],[2,5],[3,10],[4,42],[5,42],[6,10]] #入參
b1 = [[1,50],[4,57],[6,52]] #返回
a = [[1, 3], [2, 51], [3, 49], [4, 42], [5, 42]]
li = []
n =0
for i, kin a:
n += k
if n >=50:
li.append([i, n])
n =0
elif len(a) == i:
li.append([i, k])
print(li)
一個球從100米高度自由落下,每次落地後反跳回原高度的一半;再落下,求它在第10次落地時,共經過多少米?第10次反彈多高?
def fun(n):
if n ==1:
return 100 /2
else:
res = fun(n -1) /2
return res
print(fun(10))
def func(n):
if n ==1:
return 100
else:
return (fun(n -1) *2) + func(n -1)
print(func(10))
# for 循環實現
def height_100():
# 定義S用來計算總距離
s =0
h =100
for iin range(10):
# 加上本次落地的距離
s += h
h = h /2
# 加上反彈的距離
s += h
print(f'第10次落地的總距離為:{s-h}')
print(f'第10次反彈的高度:{h}')
height_100()
斐波拉契數列
[1,1,2,3,5,8,13,21,34,55]
分析:
月份 數量
1 2隻
2 2隻
3 4隻
4 6隻
5 10隻
6 16隻
def tu_func(n):
if n ==1 or n ==2:
return 2
else:
return tu_func(n -1) + tu_func(n -2)
print(tu_func(10))
# for 循環實現
def tu_func1(n):
s = []
for iin range(1, n +1):
if i ==1 or i ==2:
s.append(2)
else:
s.append(s[i -2] + s[i -3])
return s
print(tu_func1(10))
小明有100元錢 打算買100本書,A類書籍5元一本,B類書籍3元一本,C類書籍1元兩本,
請用程序算出小明一共有多少種買法?
def func3():
count =0
for ain range(21):
for bin range(34):
c =100 - a - b
if a *5 + b *3 + c *0.5 ==100:
count +=1
print(a, b, c)
print(F'一共有{count}種買法')
func3()
❺ 面試會出哪些經典演算法題
如下:
1、排序演算法∶快速排序、歸並排序、計數排序
2、搜索演算法∶回溯、遞歸、剪枝技巧
3、圖論∶最短路、最小生成樹、網路流建模
4、動態規劃:背包問題、最長子序列、計數問題
5、基礎技巧:分治、倍增、二分、貪心
6、數組與鏈表:單/雙向鏈表、跳舞鏈
7、棧與隊列
8、樹與圖:最近公共祖先、並查集
9、哈希表
10、堆:大/小根堆、可並堆
11、字元串∶字典樹、後綴樹
演算法簡介:
演算法(Algorithm)是指解題方案的准確而完整的描述,是一系列解決問題的清晰指令,演算法代表著用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規范的輸入,在有限時間內獲得所要求的輸出。
如果一個演算法有缺陷,或不適合於某個問題,執行這個演算法將不會解決這個問題。不同的演算法可能用不同的時間、空間或效率來完成同樣的任務。一個演算法的優劣可以用空間復雜度與時間復雜度來衡量。
演算法中的指令描述的是一個計算,當其運行時能從一個初始狀態和(可能為空的)初始輸入開始,經過一系列有限而清晰定義的狀態,最終產生輸出並停止於一個終態。一個狀態到另一個狀態的轉移不一定是確定的。隨機化演算法在內的一些演算法,包含了一些隨機輸入。
形式化演算法的概念部分源自嘗試解決希爾伯特提出的判定問題,並在其後嘗試定義有效計算性或者有效方法中成形。
這些嘗試包括庫爾特·哥德爾、Jacques Herbrand和斯蒂芬·科爾·克萊尼分別於1930年、1934年和1935年提出的遞歸函數,阿隆佐·邱奇於1936年提出的λ演算,1936年Emil Leon Post的Formulation 1和艾倫·圖靈1937年提出的圖靈機。即使在當前,依然常有直覺想法難以定義為形式化演算法的情況。
❻ 大公司筆試面試有哪些經典演算法題目
1、二維數組中的查找
具體例題:如果一個數字序列逆置之後跟原序列是一樣的就稱這樣的數字序列為迴文序列。例如:{1, 2, 1}, {15, 78, 78, 15} , {112} 是迴文序列, {1, 2, 2}, {15, 78, 87, 51} ,{112, 2, 11} 不是迴文序列。現在給出一個數字序列,允許使用一種轉換操作:選擇任意兩個相鄰的數,然後從序列移除這兩個數,並用這兩個數字的和插入到這兩個數之前的位置(只插入一個和)。現在對於所給序列要求出最少需要多少次操作可以將其變成迴文序列?
❼ 面試最常考的 100 道演算法題分類整理
大家好,我是 「負雪明燭」 ,一位用 7 年寫了 1000 篇 LeetCode 演算法題題解的程序員。歡迎關注。
粉絲常說: LeetCode 演算法題太多了,准備面試該刷哪些題目 ?
我之前根據 LeetCode 上面的點贊量分享過: LeetCode 上最經典的 100 道演算法題 。
這 100 道題目都屬於經典題目了,面試也常考,不過我還是不放心呢,畢竟 經典題 ≠ 面試題 呀!
但如果想知道面試常考的 100 道演算法題的話,需要至少整理 1000 篇面經吧?這個工作量可不小啊!
還好,網上有個開源項目,幫我們做了這件事情,這個項目就是 CodeTop !
這是網站的界面(地址: https://codetop.cc/home ),展示的就是每個面試題目出現的頻度情況,甚至區分了公司和崗位:
這是開源項目的 GitHub 主頁,已經 11.5k star ⭐️ 了:
這個項目中的題目來源是牛客網的面經、網友投票等,而且持續更新中,所以還是比較可靠的。
我對這個項目做了整理,分類整理出來面試常考的 100 道演算法題。
在整理之後,我對結果還是有點 驚訝 的!因為一些常見的數據結構與演算法,竟然沒有在常考面試中出現過!
比如前綴和、前綴樹、並查集、圖,這些都沒有出現……
最常考面試題還是很基本的鏈表、二叉樹、動態規劃等等,是不是符合你的認知呢?
強烈建議大家在面試前把這 100 道題目搞懂!
作為寵粉達人,我提供了 3 種方式查看這 100 道題目:
沒有任何套路,直接分享給大家!
在線查看地址: https://www.mubucm.com/doc/7jiBYKCKqet
在線查看地址: https://leetcode-cn.com/problem-list/q3iOID0B/
所有題目的地址如下:
前序遍歷
中序遍歷
層序遍歷
視圖
如果你覺得對你有幫助的話,求贊、求分享、求收藏。你的每一點鼓勵都是對我的最大幫助!
❽ 大公司筆試面試有哪些經典演算法題目
1、二維數組中的查找
具體例題:如果一個數字序列逆置之後跟原序列是一樣的就稱這樣的數字序列為迴文序列。例如:{1, 2, 1}, {15, 78, 78, 15} , {112} 是迴文序列, {1, 2, 2}, {15, 78, 87, 51} ,{112, 2, 11} 不是迴文序列。現在給出一個數字序列,允許使用一種轉換操作:選擇任意兩個相鄰的數,然後從序列移除這兩個數,並用這兩個數字的和插入到這兩個數之前的位置(只插入一個和)。現在對於所給序列要求出最少需要多少次操作可以將其變成迴文序列?
❾ 如何回答面試演算法問題
給定一個有序數組xxx 中,"有序"是否可以利用?
a: 用幾個簡單的測試用例,檢驗一下
b:暴力解法 通常都是思考的起點.
a: 遍歷常見的演算法思路
b: 遍歷常見的數據結構
c: 空間和時間的交換?
d: 預處理數據 => 排序
e: 在瓶頸處找到答案
a: 極端條件判斷
數組為空? 字元串==null? 數字==0? 指針->null?
b: 變數名等 符合規范
c: 注重模塊化,復用性
演算法在1s之內 可解決的問題:
O(n^2) 的演算法可處理大約10^4級別的數據
O(n) 的演算法可處理大約10^8級別的數據
O(nlogn)的演算法可處理大約10^7級別的數據
❿ java演算法面試題:排序都有哪幾種方法
一、冒泡排序
[java] view plain
package sort.bubble;
import java.util.Random;
/**
* 依次比較相鄰的兩個數,將小數放在前面,大數放在後面
* 冒泡排序,具有穩定性
* 時間復雜度為O(n^2)
* 不及堆排序,快速排序O(nlogn,底數為2)
* @author liangge
*
*/
public class Main {
public static void main(String[] args) {
Random ran = new Random();
int[] sort = new int[10];
for(int i = 0 ; i < 10 ; i++){
sort[i] = ran.nextInt(50);
}
System.out.print("排序前的數組為");
for(int i : sort){
System.out.print(i+" ");
}
buddleSort(sort);
System.out.println();
System.out.print("排序後的數組為");
for(int i : sort){
System.out.print(i+" ");
}
}
/**
* 冒泡排序
* @param sort
*/
private static void buddleSort(int[] sort){
for(int i=1;i<sort.length;i++){
for(int j=0;j<sort.length-i;j++){
if(sort[j]>sort[j+1]){
int temp = sort[j+1];
sort[j+1] = sort[j];
sort[j] = temp;
}
}
}
}
}
二、選擇排序
[java] view plain
package sort.select;
import java.util.Random;
/**
* 選擇排序
* 每一趟從待排序的數據元素中選出最小(或最大)的一個元素,
* 順序放在已排好序的數列的最後,直到全部待排序的數據元素排完。
* 選擇排序是不穩定的排序方法。
* @author liangge
*
*/
public class Main {
public static void main(String[] args) {
Random ran = new Random();
int[] sort = new int[10];
for (int i = 0; i < 10; i++) {
sort[i] = ran.nextInt(50);
}
System.out.print("排序前的數組為");
for (int i : sort) {
System.out.print(i + " ");
}
selectSort(sort);
System.out.println();
System.out.print("排序後的數組為");
for (int i : sort) {
System.out.print(i + " ");
}
}
/**
* 選擇排序
* @param sort
*/
private static void selectSort(int[] sort){
for(int i =0;i<sort.length-1;i++){
for(int j = i+1;j<sort.length;j++){
if(sort[j]<sort[i]){
int temp = sort[j];
sort[j] = sort[i];
sort[i] = temp;
}
}
}
}
}
三、快速排序
[java] view plain
package sort.quick;
/**
* 快速排序 通過一趟排序將要排序的數據分割成獨立的兩部分, 其中一部分的所有數據都比另外一部分的所有數據都要小,
* 然後再按此方法對這兩部分數據分別進行快速排序, 整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
* @author liangge
*
*/
public class Main {
public static void main(String[] args) {
int[] sort = { 54, 31, 89, 33, 66, 12, 68, 20 };
System.out.print("排序前的數組為:");
for (int data : sort) {
System.out.print(data + " ");
}
System.out.println();
quickSort(sort, 0, sort.length - 1);
System.out.print("排序後的數組為:");
for (int data : sort) {
System.out.print(data + " ");
}
}
/**
* 快速排序
* @param sort 要排序的數組
* @param start 排序的開始座標
* @param end 排序的結束座標
*/
public static void quickSort(int[] sort, int start, int end) {
// 設置關鍵數據key為要排序數組的第一個元素,
// 即第一趟排序後,key右邊的數全部比key大,key左邊的數全部比key小
int key = sort[start];
// 設置數組左邊的索引,往右移動判斷比key大的數
int i = start;
// 設置數組右邊的索引,往左移動判斷比key小的數
int j = end;
// 如果左邊索引比右邊索引小,則還有數據沒有排序
while (i < j) {
while (sort[j] > key && j > start) {
j--;
}
while (sort[i] < key && i < end) {
i++;
}
if (i < j) {
int temp = sort[i];
sort[i] = sort[j];
sort[j] = temp;
}
}
// 如果左邊索引比右邊索引要大,說明第一次排序完成,將sort[j]與key對換,
// 即保持了key左邊的數比key小,key右邊的數比key大
if (i > j) {
int temp = sort[j];
sort[j] = sort[start];
sort[start] = temp;
}
//遞歸調用
if (j > start && j < end) {
quickSort(sort, start, j - 1);
quickSort(sort, j + 1, end);
}
}
}
[java] view plain
/**
* 快速排序
*
* @param a
* @param low
* @param high
* voidTest
*/
public static void kuaisuSort(int[] a, int low, int high)
{
if (low >= high)
{
return;
}
if ((high - low) == 1)
{
if (a[low] > a[high])
{
swap(a, low, high);
return;
}
}
int key = a[low];
int left = low + 1;
int right = high;
while (left < right)
{
while (left < right && left <= high)// 左邊向右
{
if (a[left] >= key)
{
break;
}
left++;
}
while (right >= left && right > low)
{
if (a[right] <= key)
{
break;
}
right--;
}
if (left < right)
{
swap(a, left, right);
}
}
swap(a, low, right);
kuaisuSort(a, low, right);
kuaisuSort(a, right + 1, high);
}
四、插入排序
[java] view plain
package sort.insert;
/**
* 直接插入排序
* 將一個數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據
* 演算法適用於少量數據的排序,時間復雜度為O(n^2)。是穩定的排序方法。
*/
import java.util.Random;
public class DirectMain {
public static void main(String[] args) {
Random ran = new Random();
int[] sort = new int[10];
for (int i = 0; i < 10; i++) {
sort[i] = ran.nextInt(50);
}
System.out.print("排序前的數組為");
for (int i : sort) {
System.out.print(i + " ");
}
directInsertSort(sort);
System.out.println();
System.out.print("排序後的數組為");
for (int i : sort) {
System.out.print(i + " ");
}
}
/**
* 直接插入排序
*
* @param sort
*/
private static void directInsertSort(int[] sort) {
for (int i = 1; i < sort.length; i++) {
int index = i - 1;
int temp = sort[i];
while (index >= 0 && sort[index] > temp) {
sort[index + 1] = sort[index];
index--;
}
sort[index + 1] = temp;
}
}
}
順便添加一份,差不多的
[java] view plain
public static void charuSort(int[] a)
{
int len = a.length;
for (int i = 1; i < len; i++)
{
int j;
int temp = a[i];
for (j = i; j > 0; j--)//遍歷i之前的數字
{
//如果之前的數字大於後面的數字,則把大的值賦到後面
if (a[j - 1] > temp)
{
a[j] = a[j - 1];
} else
{
break;
}
}
a[j] = temp;
}
}
把上面整合起來的一份寫法:
[java] view plain
/**
* 插入排序:
*
*/
public class InsertSort {
public void sort(int[] data) {
for (int i = 1; i < data.length; i++) {
for (int j = i; (j > 0) && (data[j] < data[j - 1]); j--) {
swap(data, j, j - 1);
}
}
}
private void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
五、順便貼個二分搜索法
[java] view plain
package search.binary;
public class Main {
public static void main(String[] args) {
int[] sort = {1,2,3,4,5,6,7,8,9,10};
int mask = binarySearch(sort,6);
System.out.println(mask);
}
/**
* 二分搜索法,返回座標,不存在返回-1
* @param sort
* @return
*/
private static int binarySearch(int[] sort,int data){
if(data<sort[0] || data>sort[sort.length-1]){
return -1;
}
int begin = 0;
int end = sort.length;
int mid = (begin+end)/2;
while(begin <= end){
mid = (begin+end)/2;
if(data > sort[mid]){
begin = mid + 1;
}else if(data < sort[mid]){
end = mid - 1;
}else{
return mid;
}
}
return -1;
}
}