【LeetCode】算法與數據結構筆記(一) 數組和字符串


  本文主要爲LeetCode刷題學習筆記。

核心要點

集合

  集合裏的元素類型不一定相同

  集合裏的元素沒有順序

列表

  是一種數據項構成的有限序列,即按照一定的線性順序,排列而成的數據項的集合。

  列表最常見的表現形式有數組和鏈表,而棧和隊列則是兩種特殊類型的列表

數組

  數組與列表的區別在於索引。索引是數組中的一個重要概念,列表中沒有索引這個概念。在大多數編程語言中,索引是從0算起的。

  數組中元素在內存中也是連續存儲的。

  數組中有基本的四種操作:

  1. 讀取元素
nums[i] // 讀取第數組中的第i個元素。
  1. 查找元素
s1.find(s2,position) //在S1中查找子串S2, position示從從這個位置開始的字符串中找指定元素,默認爲0。
//返回值爲目標字符的位置,當沒有找到目標字符時返回npos。
  1. 插入元素
s1.insert(2,"123") // 下標爲2處插入“123”。
  1. 刪除元素
s1.erase(1,3) // 刪除從1開始,長度爲3的子串

  除此之外還有:

s1.append(s2,1,3) // 添加s2下標從1開始,長度爲3的字符串到s1。
s1.swap(s2) // 交換s1,s2.
s1.assign(4,"K") // s1賦值爲“KKKK"

編程實例

一維數組

合併區間

  給出一個區間的集合,請合併所有重疊的區間。

示例 1:

輸入: [[1,3],[2,6],[8,10],[15,18]]
輸出: [[1,6],[8,10],[15,18]]
解釋: 區間 [1,3][2,6] 重疊, 將它們合併爲 [1,6].

示例 2:

輸入: [[1,4],[4,5]]
輸出: [[1,5]]
解釋: 區間 [1,4][4,5] 可被視爲重疊區間。
  • 實現思想

  思想也就很簡單,首先按照二維數組裏面的一維數組的第一個元素排序,這個時候比較上一個一維數組的末尾元素(比如[1,3]中的3)與下一個一維數組的第一個元素(比如[2,6]中的2)大小,然後判斷是否要合併。

  • C++實現
class Solution {
public:
    static bool cmp(vector<int> num1, vector<int> num2){
            return num1[0]<num2[0];
        }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if(intervals.size()<2) return intervals;
        
        sort(intervals.begin(), intervals.end(),cmp);
        int n = intervals.size();
        vector<vector<int>> ans;
        ans.push_back(intervals[0]);
        for(int i=1; i<n; ++i){
            if(ans.back()[1] >= intervals[i][0]){
                ans.back()[1] = max(ans.back()[1], intervals[i][1]);
            } else {
                ans.push_back(intervals[i]);
            }
        }
        return ans;
    }
};

  這裏要注意:

    static bool cmp(vector<int> num1, vector<int> num2){
            return num1[0]<num2[0];

  之所以要加static的原因是:使用了函數指針,而函數指針所指函數須得是靜態纔行。如果不加的話,報錯如下:

fatal error: reference to non-static member function must be called

二維數組

旋轉圖像

  給定一個 n × n 的二維矩陣表示一個圖像。

  將圖像順時針旋轉 90 度。

  說明

  你必須在原地旋轉圖像,這意味着你需要直接修改輸入的二維矩陣。請不要使用另一個矩陣來旋轉圖像。

  示例 1:

給定 matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

原地旋轉輸入矩陣,使其變爲:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

示例 2:

給定 matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 

原地旋轉輸入矩陣,使其變爲:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]
  • 思路

  我們首先需要對其最外層循環,將每個數字旋轉90度,然後進入內層循環,所以我們要循環的外層數就是N/2(for(int r=0; r<n/2;++r));當確定了循環的層數之後,我們需要進入內層循環,內層循環的起始位置s=r,內層循環的終止位置從右邊往左邊看就是N-1-r

  接下來就是需要確定各個元素的位置了,剛開始起始位置的元素座標是(r,i)。因爲是按照順時針旋轉90度,所以逆時針旋轉的座標爲(end-(i-s), r)(end, end-(i-s)), (i, end)

  • C++實現
class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        for(int r=0; r<n/2;++r){
            int s = r;
            int end = n-1-r;
            for(int i=s; i<end; i++){
                int temp = matrix[r][i];
                matrix[r][i] = matrix[end-(i-s)][r];
                matrix[end-(i-s)][r] = matrix[end][end-(i-s)];
                matrix[end][end-(i-s)] = matrix[i][end];
                matrix[i][end] = temp;

            }
        }
    }
};

對角線遍歷

  給定一個含有 M x N 個元素的矩陣(M 行,N 列),請以對角線遍歷的順序返回這個矩陣中的所有元素,對角線遍歷如下圖所示。

  示例:

輸入:

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

輸出:  [1,2,4,7,5,3,6,8,9]

  解釋

  說明:

  給定矩陣中的元素總數不會超過 100000 。

  • 思路解析

  我們可以知道每一條斜線上的座標之和爲一個固定的值,從0m+n。如果我們以這個和作爲大循環遍歷的話(for(int s=0; s<=m+n;s++)),我們只需要去確定行或者列中的一個,我們就可以通過總和s減去行或者列得到另一個。以行爲例,如果我們知道行座標r的範圍,那麼s-r就是縱座標的值。

  那現在的問題就是如何確定行座標的值。

  當s小於行座標的總數時,行座標的最大值爲s,否者爲m = matrix.size()-1。程序裏面表示爲int max_r = min(s, m);,(對應第0列邊界)。

  當s很大時,大到被最後一列限制的時候,此時行座標的最小值爲s-n,否者爲0。程序裏面表示爲int min_r = max(0, s-n),(對應第最後一列邊界)。

  • C++實現
class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        vector<int> ans;
        if (matrix.empty()) return ans;
        
        int m = matrix.size()-1;
        int n = matrix[0].size()-1;

        for(int s=0; s<=m+n;s++){
            int min_r = max(0, s-n);
            int max_r = min(s, m);
            if(s%2==1){
                for(int r=min_r; r<=max_r; ++r){
                    ans.push_back(matrix[r][s-r]);
                }
            } else {
                for(int r=max_r; r>=min_r; --r){
                    ans.push_back(matrix[r][s-r]);
                }
            }
        }
        return ans;
    }
};

字符串簡介

最長公共前綴

  編寫一個函數來查找字符串數組中的最長公共前綴。

  如果不存在公共前綴,返回空字符串 “”。

  示例 1:

輸入: ["flower","flow","flight"]
輸出: "fl"

  示例 2:

輸入: ["dog","racecar","car"]
輸出: ""
解釋: 輸入不存在公共前綴。

  說明:

  所有輸入只包含小寫字母 a-z

  • 解題思路

  先從字符串數組中取出第一個字符strs[0],之後從前往後取出子字符,for(int i=0;i<=strs[0].length();++i)sub_tem = strs[0].substr(0, i);,拿到的子字符與剩餘字符一一對比,如果能找到且返回的座標是0,也就是從頭開始就匹配到了,那就說明這個字符滿足要求,否者循環就沒必要進行下去,已經不滿足要求了。

  如果到最後一個都能找到的話,就說明當前這個子字串是最長公共前綴。

  • C++實現
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        
        int n = strs.size();
        string ans = "";
        if(n==0) return ans;
        if(n==1) return strs[0];
        string sub_tem;
        
        for(int i=0;i<=strs[0].length();++i){
            sub_tem = strs[0].substr(0, i);
            for(int j=1;j< strs.size();++j){
                if(strs[j].find(sub_tem)!=0) break;
                if(j==strs.size()-1) ans.swap(sub_tem);
            }
            
        }
        return ans;
    }
};

翻轉字符串裏的單詞

  給定一個字符串,逐個翻轉字符串中的每個單詞。

  示例 1

輸入: "the sky is blue"
輸出: "blue is sky the"

  示例 2

輸入: "  hello world!  "
輸出: "world! hello"

  解釋: 輸入字符串可以在前面或者後面包含多餘的空格,但是反轉後的字符不能包括。

  示例 3

輸入: "a good   example"
輸出: "example good a"

  解釋: 如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。

  說明

  無空格字符構成一個單詞。

  輸入字符串可以在前面或者後面包含多餘的空格,但是反轉後的字符不能包括。

  如果兩個單詞間有多餘的空格,將反轉後單詞間的空格減少到只含一個。

  進階

  請選用CC 語言的用戶嘗試使用 O(1)O(1) 額外空間複雜度的原地解法。

雙指針

移除元素

  給你一個數組nums 和一個值 val,你需要 原地 移除所有數值等於val的元素,並返回移除後數組的新長度。

  不要使用額外的數組空間,你必須僅使用 O(1)O(1) 額外空間並 原地 修改輸入數組。

  元素的順序可以改變。你不需要考慮數組中超出新長度後面的元素。

  示例 1:

給定 nums = [3,2,2,3], val = 3,
函數應該返回新的長度 2, 並且 nums 中的前兩個元素均爲 2。
你不需要考慮數組中超出新長度後面的元素。

  示例 2:

給定 nums = [0,1,2,2,3,0,4,2], val = 2,
函數應該返回新的長度 5, 並且 nums 中的前五個元素爲 0, 1, 3, 0, 4。
注意這五個元素可爲任意順序。
你不需要考慮數組中超出新長度後面的元素。
  • 解題思路

  設定兩個快慢指針slowfastslow指針從0開始,fast指針隨着循環從0n(數組長度)。當遇到非val值時,fast元素賦值到slow,並且++slow,爲下一個賦值做準備。當循環結束,slow的值就是非val值的個數。

  • C++實現
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n = nums.size();
        int slow=0;
        for(int fast=0;fast<n;++fast){
            if(nums[fast]!=val){
                nums[slow]=nums[fast];
                ++slow;
            }
        }
        return slow;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章