1. 程式人生 > >演算法習題(2):Leetcode初級演算法(陣列)

演算法習題(2):Leetcode初級演算法(陣列)

Leetcode初級演算法(陣列)

從排序陣列中刪除重複項

給定一個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。
不要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用 O(1) 額外空間的條件下完成。

示例 1:

給定陣列 nums = [1,1,2],
函式應該返回新的長度 2, 並且原陣列 nums 的前兩個元素被修改為 1, 2。
你不需要考慮陣列中超出新長度後面的元素。

示例 2:

給定 nums = [0,0,1,1,1,2,2,3,3,4],

函式應該返回新的長度 5, 並且原陣列 nums 的前五個元素被修改為 0, 1, 2, 3, 4。

你不需要考慮陣列中超出新長度後面的元素。

這題很噁心,第一遍用c直接排序,刪除寫出來了,第二次的時候用c++寫,發現他沒有提供sort()和erase()(刪除任意位置)函式,不能直接寫0.0,所以具體思路和c差不多,而且他給出的test資料是已經排好序了的…..

    int removeDuplicates(vector<int>& nums) {
        if(nums.size()==0){
            return 0;
        }
        int sum = 1;
        for(int i=1;i<nums.size();i++){
            if
(nums[i]==nums[i-1]){ for(int j=i;j<nums.size();j++){ nums[j] = nums[j+1]; } nums.pop_back(); i--; } else{ sum++; } } return sum; }

買賣股票的最佳時機 II

買賣股票的最佳時機
輸入一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。

設計一個演算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
示例 1:

輸入: [7,1,5,3,6,4]
輸出: 7
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
隨後,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能獲得利潤 = 6-3 = 3 。

示例 2:

輸入: [1,2,3,4,5]
輸出: 4
解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 =5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接連購買股票,之後再將它們賣出。
因為這樣屬於同時參與了多筆交易,你必須在再次購買前出售掉之前的股票。

示例 3:

輸入: [7,6,4,3,1] 輸出: 0 解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。

貪心演算法,最貪心的方法就是隻要它後面的比他大,就將差值記錄下來

    int maxProfit(vector<int>& prices) {
        if(prices.size()==0||prices.size()==1)
            return 0;
        int count = 0;
        for(int i=0;i<prices.size()-1;i++){
            if(prices[i]<prices[i+1]){
                count+=(prices[i+1]-prices[i]);
            }
        }                                     //記錄差值
        return count;
    }

旋轉陣列

旋轉陣列
給定一個數組,將陣列中的元素向右移動 k 個位置,其中 k 是非負數。

示例 1:

輸入: [1,2,3,4,5,6,7] 和 k = 3
解釋: 向右旋轉 1 步:[7,1,2,3,4,5,6]
向右旋轉 2 步: [6,7,1,2,3,4,5]
向右旋轉 3 步: [5,6,7,1,2,3,4]

示例 2:

輸出: [3,99,-1,-100]
解釋: 向右旋轉 1 步: [99,-1,-100,3]
向右旋轉 2 步: [3,99,-1,-100]

說明:

  • 儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。 要求使用
  • 空間複雜度為 O(1) 的原地演算法。

    maye….試了好幾遍挨個旋轉,還是不行,不過應該可以多個旋轉,2個,3個,速度比較快,0.0我沒用空間複雜度為O(1)的原地演算法,就是gan♂

void rotate(int* nums, int numsSize, int k) {

        int len = numsSize;
        int res[len];
        int order = 0;
        for(int i = len - k%len;i < len;i++){
            res[order++] = nums[i];
        }
        for(int i = 0; i < len - k%len; i++){
            res[order++] = nums[i];
        }
        for(int i = 0;i < len; i++){
            nums[i] = res[i];
        }
}

存在重複

存在重複
給定一個整數陣列,判斷是否存在重複元素。

如果任何值在陣列中出現至少兩次,函式返回 true。如果陣列中每個元素都不相同,則返回 false。
示例 1:

輸入: [1,2,3,1]
輸出: true

示例 2:

輸入: [1,2,3,4]
輸出: false

示例 3:

輸入: [1,1,1,3,3,4,3,2,4,2]
輸出: true

直接排序然後判斷是否有重複。

    bool containsDuplicate(vector<int>& nums) {
        int n = nums.size();
        std::sort(nums.begin(),nums.end());  //排序
        for(int i=0;i<n-1;i++){
            if(nums[i]==nums[i+1]){
                return true;           //判斷
            }
        }
        return false;
    }

只出現一次的數字

只出現一次的數字
給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。

說明:

你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?

示例 1:

輸入: [2,2,1]
輸出: 1

示例 2:

輸入: [4,1,2,1,2]
輸出: 4

emmmmmmm先進行排序,然後判斷第一位和末位是否重複,再將每一個與其前後比較判斷(可以有更簡單的方法)

    int singleNumber(vector<int>& nums) {
        std::sort(nums.begin(),nums.end());     //排序
        if(nums[0]!=nums[1]){
            return nums[0];
        }
        if(nums[nums.size()-2]!=nums[nums.size()-1]){
            return nums[nums.size()-1];
        }                                    //判斷首尾
        for(int i=1;i<nums.size()-1;i++){
            if(nums[i]!=nums[i+1]&&nums[i]!=nums[i-1]){
                return nums[i];                 //比較前後
            }
        }
    }

兩個陣列的交集 II

兩個陣列的交集 II
給定兩個陣列,寫一個方法來計算它們的交集。

例如:
給定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].

注意:

  • 輸出結果中每個元素出現的次數,應與元素在兩個陣列中出現的次數一致。
  • 我們可以不考慮輸出結果的順序。

跟進:

  • 如果給定的陣列已經排好序呢?你將如何優化你的演算法?
  • 如果 nums1 的大小比 nums2 小很多,哪種方法更優?
  • 如果nums2的元素儲存在磁碟上,記憶體是有限的,你不能一次載入所有的元素到記憶體中,你該怎麼辦?

剛看到這道題的時候沒有什麼頭緒,最後想了一下,陣列先排序咋樣都不錯0.0,然後將陣列排序,然後從小到大如果nums1的值大,nums2的節點就往後,如果nums2的值大,nums1的節點就往後,如果相等則將數填入新的數組裡,最後返回動態陣列。

    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        std::sort(nums1.begin(),nums1.end());
        std::sort(nums2.begin(),nums2.end());       //排序
        vector<int> a;
        int i = 0;
        int j = 0;
        while(i<nums1.size()&&j<nums2.size()){
            if(nums1[i]>nums2[j]){
                j++;
            }              
            else if(nums1[i]<nums2[j]){
                i++;
            }                                  //判斷
            else{
                a.push_back(nums1[i]);
                i++;
                j++;                             //填入
            }
        }
        return a;                             //返回
    }

加一

加一
給定一個非負整數組成的非空陣列,在該數的基礎上加一,返回一個新的陣列。

最高位數字存放在陣列的首位, 陣列中每個元素只儲存一個數字。

你可以假設除了整數 0 之外,這個整數不會以零開頭。

示例 1:

輸入: [1,2,3]
輸出: [1,2,4]
解釋: 輸入陣列表示數字 123。

示例 2:

輸入: [4,3,2,1]
輸出: [4,3,2,2]
解釋: 輸入陣列表示數字 4321。

emmmmmmm先reverse給首位加1,然後判斷有沒有進位,最後一位要是進位了再補個1,最後再reverse回來

    vector<int> plusOne(vector<int>& digits) {
        reverse(digits.begin(), digits.end());       //反轉
        digits[0]++;                       //加1
        for(int i=0;i<digits.size()-1;i++){
            if(digits[i]==10){
                digits[i+1]++;
                digits[i]=0;                判斷進位
            }
        }
        if(digits[digits.size()-1]==10){
            digits[digits.size()-1]=0;         //判斷末位是否進位
            digits.push_back(1);
        }
        reverse(digits.begin(), digits.end());          //反轉
        return digits;                //返回
    } 

移動零

移動零
給定一個數組 nums,編寫一個函式將所有 0 移動到陣列的末尾,同時保持非零元素的相對順序。
示例:

輸入: [0,1,0,3,12]
輸出: [1,3,12,0,0]

說明:

  1. 必須在原陣列上操作,不能拷貝額外的陣列。
  2. 儘量減少操作次數。

遍歷,見到0將後面的全部進位,並記錄下0的個數,最後補0

    void moveZeroes(vector<int>& nums) {
        int sum = 0;
        for(int i=0;i<nums.size();i++){
            if(nums[i]==0){
                for(int j=i;j<nums.size()-1;j++){
                    nums[j] = nums[j+1];    
                }                                //找0進位
                sum++; 
                nums.pop_back();
                i--;
            }       
        }
        for(int i=0;i<sum;i++){
            nums.push_back(0);             //補0
        }
        printf("[");
        for(int i=0;i<nums.size()-1;i++){
            printf("%d,",nums[i]);
        } 
        printf("%d]",nums[nums.size()-1]);
    }

兩數之和

兩數之和
給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。

你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。

示例:

給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

暴力破解0.0遍歷maye 誰能告訴我個可以裝x的演算法0.0

    vector<int> twoSum(vector<int>& nums, int target) {
        int a,b;
        for(int i=0;i<nums.size();i++){
            for(int j=i+1;j<nums.size();j++){
                if(nums[i]+nums[j]==target){
                    a = i;
                    b = j;
                    break;
                }
            }
        }
        vector<int> c;
        c.push_back(a);
        c.push_back(b);
        return c;
    }

有效的數獨

判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。

  1. 數字 1-9 在每一行只能出現一次。
  2. 數字 1-9 在每一列只能出現一次。
    這裡寫圖片描述
    上圖是一個部分填充的有效的數獨。

示例 1:

輸入:
[
[“5”,”3”,”.”,”.”,”7”,”.”,”.”,”.”,”.”],
[“6”,”.”,”.”,”1”,”9”,”5”,”.”,”.”,”.”],
[“.”,”9”,”8”,”.”,”.”,”.”,”.”,”6”,”.”],
[“8”,”.”,”.”,”.”,”6”,”.”,”.”,”.”,”3”],
[“4”,”.”,”.”,”8”,”.”,”3”,”.”,”.”,”1”],
[“7”,”.”,”.”,”.”,”2”,”.”,”.”,”.”,”6”],
[“.”,”6”,”.”,”.”,”.”,”.”,”2”,”8”,”.”],
[“.”,”.”,”.”,”4”,”1”,”9”,”.”,”.”,”5”],
[“.”,”.”,”.”,”.”,”8”,”.”,”.”,”7”,”9”]
]
輸出: true

示例 2:

輸入:
[
[“8”,”3”,”.”,”.”,”7”,”.”,”.”,”.”,”.”],
[“6”,”.”,”.”,”1”,”9”,”5”,”.”,”.”,”.”],
[“.”,”9”,”8”,”.”,”.”,”.”,”.”,”6”,”.”],
[“8”,”.”,”.”,”.”,”6”,”.”,”.”,”.”,”3”],
[“4”,”.”,”.”,”8”,”.”,”3”,”.”,”.”,”1”],
[“7”,”.”,”.”,”.”,”2”,”.”,”.”,”.”,”6”],
[“.”,”6”,”.”,”.”,”.”,”.”,”2”,”8”,”.”],
[“.”,”.”,”.”,”4”,”1”,”9”,”.”,”.”,”5”],
[“.”,”.”,”.”,”.”,”8”,”.”,”.”,”7”,”9”]
]
輸出: false
解釋: 除了第一行的第一個數字從 5 改為 8 以外,空格內其他數字均與 示例1 相同。
但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。

數獨部分空格內已填入了數字,空白格用 ‘.’ 表示。

說明:

  • 一個有效的數獨(部分已被填充)不一定是可解的。
  • 只需要根據以上規則,驗證已經填入的數字是否有效即可。
  • 給定數獨序列只包含數字 1-9
  • 和字元 ‘.’ 。 給定數獨永遠是 9x9 形式的。

暫時不會0.0

旋轉影象

旋轉影象

給定一個 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]
]

我第一想法是在while迴圈中套for迴圈,和陣列順時針輸出差不多,但我寫的時候發現,這樣寫迴圈條件很難找,我也沒找到,你觀察這個陣列,先將陣列轉置,再將每一行reverse,就是旋轉好的陣列了,所以程式碼(但這樣寫和題目不符,明天我在來更新第二種寫法):
第一種寫法:

    void rotate(vector<vector<int>>& matrix) {
        vector<vector<int>> a(matrix.size());
        int k=0;
        for(int j=0;j<matrix[0].size();j++){
            for(int i=0;i<matrix.size();i++){
                a[k].push_back(matrix[i][j]);
            } 
            k++;
        }                                 //轉置
        for(int i=0;i<a.size();i++){
            reverse(a[i].begin(),a[i].end());
        }                                    //reverse
        matrix = a;                     //再放到matrix上
    }