基礎面試題 — 數據結構與算法

數據結構

數據結構是對實際問題中的數據元素及相互間的聯繫的抽象。通常用線性表來表示經常使用數據結構,線性表分爲順序存儲的順序表和連式存儲的鏈表。前端

經常使用數據結構

在學習算法以前,必需要了解一些經常使用數據結構的概念。git

  • 棧:一種特殊串聯形式的抽象數據類型,可由鏈表或數組實現,經過鏈表或數組的棧頂(Top)指針對數據進行壓棧(Push)和出棧(Pop)操做,其特色是LIFO。github

  • 隊列:先進先出(FIFO)的線性表,通常用鏈表和數組來實現,只容許在後端(back or rear)插入,在前端(front)刪除。面試

  • 數組:由相同元素的集合所組成的數據結構,存儲在一塊連續的內存單元,根據元素的索引能夠計算出該元素對應的存儲地址。算法

  • 鏈表:由一連串節點組成,每一個節點包含任意的實例數據和一個或兩個用來指向下一個/上一個節點位置的連接。編程

  • 樹:實現抽象數據類型的數據結構,如:二叉樹、霍夫曼樹。後端

  • 圖:表示物件與物件之間的關係,圖論的基本研究對象。數組

  • 堆:是計算機科學中一種特別的樹狀數據結構,也是一種特殊的二叉樹。bash

  • 散列表:根據鍵(key)直接訪問內存存儲位置的一種數據結構,經過計算一個關於鍵值的函數,將所需查詢的數據映射到表中的一個位置來訪問記錄,映射函數叫作散列函數,存放記錄的數組叫散列表(散列函數和哈希衝突是實現散列表最重要的兩個環節)。網絡

算法

所謂算法,就是解決問題方案的準確而完整的描述。

運算操做

爲了完成各類運算,計算機提供了一套最基本的功能操做:

  1. 算術運算:加、減、乘、除;
  2. 邏輯運算:與、或、非;
  3. 比較運算:大於,小於,等於,不等於;
  4. 數據轉送:輸入、輸出,賦值。

算法分析的重要指標

  1. 時間複雜度:指算法運行所須要的時間,即算法的時間代價。
  2. 空間複雜度:對一個算法在運行過程當中所須要的輔助存儲空間大小的度量。

算法面試題

介紹完理論,能夠開始實踐了,如下算法題目有不少能夠在劍指Offer一書中找到,此文以及所涉及的題目僅供參考,不一樣的題目有不一樣的解答方式,切勿死記,必定要基於空間複雜度和時間複雜度再選擇對應的算法。此文部分題目提供了部分參考代碼,完整參考代碼請點擊此處查看。

  • 算術運算題

    1. 質數
      • 大於1的天然數中,只能被1和自身整除的天然數(不要考慮1),質數判斷的參考實現以下:
    bool isPrime(unsigned n) {
        for (int i = 2; i < n; i++) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }
    複製代碼
    1. 醜數
      • 只能被二、3和5整除的正整數數,1是第一個醜數,醜數判斷的參考實現以下:
      bool isUgly(int n) {
          if (n >= 1) {
              while (n % 2 == 0) {
                  n = n / 2;
              }
              while (n % 3 == 0) {
                  n = n / 3;
              }
              while (n % 5 == 0) {
                  n = n / 5;
              }
              if (n == 1) {
                  return true;
              }
          }
          return false;
      }
      複製代碼
    2. 斐波那契數列
      • 從0和1開始,以後的數就是前兩個數的和,參考實現以下:
      long long fibonacciSequence(unsigned n) {
      
          int result[] = {0, 1};
          if (n < 2) {
              return result[n];
          }
          long long firstValue = 0;
          long long secondValue = 1;
          long long sum = 0;
          for (int i = 2; i < n; i++) { // n之內的天然數
              sum += firstValue + secondValue;
              firstValue = secondValue;
              secondValue = sum;
          }
          return sum;
      }
      複製代碼
  • 排序

    1. 冒泡排序(平均複雜度 O(n^2) 且穩定)
      • 每趟肯定一個最小值,把最小值往上冒,參考實現以下:
      void bubbleSort(int *a, int len) {
          if (a == nullptr || len < 1) {
              return;
          }
          for (int i = 0; i < len-1; i++) {
              for (int j = 0; j < len-1-i; j++) {
                  if (a[j] > a[j+1]) {
                      swap(a[j], a[j+1]);
                  }
              }
          }
      }
      複製代碼
    2. 選擇排序(平均複雜度 O(n^2) 且穩定)
      • 選擇一個數字,而後與其他數字逐個比較,小於該數字則交換,參考實現以下:
      void selectSort(int *a, int len) {
          if (a == nullptr || len < 1) {
              return;
          }
          for (int i = 0; i < len - 1; i++) {
              for (int j = i+1; j < len; j++) {
                  if (a[i] > a[j]) {
                      swap(a[i], a[j]);
                  }
              }
          }
      }
      複製代碼
    3. 插入排序(平均複雜度 O(n^2) 且穩定)
      • 從頭開始,選擇一個數與前面排好序的數比較,把該數插入到合適的位置,參考實現以下:
      void insertSort(int *a, int len) {
          if (a == nullptr || len < 1) {
              return;
          }
          for (int i = 0; i < len; i++) {
              for (int j = i+1; j > 0; j--) {
                  if (a[j] < a[j-1]) {
                      swap(a[j], a[j-1]);
                  }
              }
          }
      }
      複製代碼
    4. 快速排序(平均複雜度 O(nlogn) 不穩定)
      • 核心實現是,選擇一個數做爲基準值,大於該值的放在右邊,小於該值的放在左邊,最後把該值放在左右分割的位置,遞歸參考實現以下:
      void IVSort::quickSort(int *a, int len) { // step 1
          if (a == nullptr || len < 1) {
              return;
          }
          quickSortImp(a, 0, len-1);
      }
      
      void quickSortImp(int *a, int start, int end) { // step 2
          if (start >= end) {
              return;
          }
          int index = quickSortImpCore(a, start, end);
          if (index > start) {
              end = index-1;
              quickSortImp(a, start, end);
          }
          if (index < end) {
              start = index+1;
              quickSortImp(a, start, end);
          }
      }
      // 快速排序核心實現
      int quickSortImpCore(int *a, int start, int end) { step 3
          int index = start + 1;
          // 默認選第一個做爲基本值
          for (int i = index; i <= end; i++) {
              if (a[start] > a[i]) {
                  if (index != i) {
                      swap(a[index], a[i]);
                  }
                  ++index;
              }
          }
          --index;
          swap(a[start], a[index]);
          return index;
      }
      複製代碼
  • 查找

    1. 二分法(折半查找,平均複雜度O(logn))
      • 經過左右索引,不斷縮小查找區域,適用於已排序數列,參考實現以下:
      bool binarySearch(int *a, int len, int target) {
          if (a != nullptr && len > 0) {
              int start = 0;
              int end = len - 1;
              while (start < end) {
                  int mid = (start + end)/2;
                  if (a[mid] > target) {
                      end = mid-1;
                  }else if (a[mid] < target) {
                      start = mid + 1;
                  }else {
                      return true;
                  }
              }
          }
          return false;
      }
      複製代碼

鑑於代碼量大會致使篇幅過長,不方便閱讀,如下題目不在貼出參考代碼,有須要可點擊此處查看。

  • 字符串

    1. 字符串翻轉
    2. 字符串轉數字
    3. 字符串替換
  • 數組

    1. 找出重複的數
    2. 二維數組的查找
    3. 旋轉數組中最小的數
    4. 數組中出現超過一半的數字
    5. 數組中第K大的數
    6. 有序數組中某個數出現的次數
    7. 調整奇數位位於偶數位前面
  • 鏈表

    1. 刪除指定節點
    2. 刪除重複節點
    3. 倒數第K個節點
    4. 中間節點
    5. 入口節點
    6. 翻轉鏈表
    7. 合併兩個鏈表
    8. 兩個鏈表的首個公共節點
    1. 前序遍歷(遞歸和非遞歸)
    2. 中序遍歷(遞歸和非遞歸)
    3. 後序遍歷(遞歸和非遞歸)
    4. 根據前序和中序構建二叉樹
    5. 根據中序和後序構建二叉樹
    6. 中序遍歷的下一個節點
    7. 翻轉二叉樹
    8. 樹的深度
    9. 根據中序遍歷判斷是不是二叉搜索樹(BST:Binary Search Tree)
    10. 從上到下打印二叉樹

總結

對於從事編程工做的朋友來講,數據結構與算法是編程的基礎(這裏是網絡篇iOS篇),也是不少大廠面試的必考題,熟悉算法不只僅是爲了應付面試,算法題巧妙的解決思路有助於幫助咱們提升代碼的執行效率和豐富解決問題的思路,實乃防治老年癡呆必備之良藥,望按需取之,另:各位如有更好的解決思路,歡迎一塊兒學習交流。


PS:此文給出的參考代碼,不必定是最佳的答案,且以上代碼都是基於Xcode環境編寫,並提供了一些簡單的Test Case,沒有徹底覆蓋,你們能夠自行編寫case測試,若發現有任何Bug,可經過新浪「Joelixy_」和GitHub及時與我聯繫,我會在第一時間修正,謝謝!

相關文章
相關標籤/搜索