1. 程式人生 > >【一、Leetcode陣列專題(1)easy】

【一、Leetcode陣列專題(1)easy】

【陣列專題】

難度:easy

【第一題】 Two Sum(NO.1)

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:
Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

.

知識點: vector unordered_map

暴力解法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int i,j;
        vector<int> re(2);
        for(i=0; i<nums.size(); i++)
            for
(j=i+1; j<nums.size(); j++){ if(nums[i]+nums[j]==target){ re[0]=i; re[1]=j; return re; } } } };

時間複雜度O(N^2) Runningtime: 112ms

網上的優化是hash table解法 時間複雜度O(n)

學習了一下hash table ,解法如下

class
Solution { public: vector<int> twoSum(vector<int>& nums, int target) { int i; vector<int> re; unordered_map<int,int> mapping; int gap=0; for(i=0; i<nums.size(); i++) mapping[nums[i]]=i; for(i=0; i<nums.size(); i++){ gap = target - nums[i];//注意這裡,可以省去比較; if( mapping.find(gap) != mapping.end() && mapping[gap]!=i){ // 多了一個判定條件,即找到的值不能為nums[i]本身 即3+3=6的情況 re.push_back(i); re.push_back(mapping[gap]); return re; } } } };

時間複雜度 O(n) Runningtime: 9ms
效率大大提高了

iterator find(const key_type&k);
const_iterator find(const key_type&k)const;

mapping.find(gap) 返回為迭代器
獲取迭代器到元素
搜尋容器中的一個元素,其中k為關鍵字,如果發現,返回一個迭代器到它,否則它返回一個迭代器到unordered_map :: end(元素超過容器的結尾)。
一個學習雜湊表的網址,看完後發現自己以前其實學習過雜湊表的,真是忘的一乾二淨了。。
http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html
mapping.find(gap) != mapping.end()說明存在gap值,如果==mapping.end()說明不存在

.

gap = target - nums[i];//注意這裡,可以省去比較;減少一定複雜度
與gap+nums[i]=target的不同,仔細體會

.

雜湊表 使用條件:key是不可以重複的,但是value可以重複

大神級解法,看看得了,與9ms思想相差不大,少一個for迴圈;不看此解法也行。
Running time 3ms

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        unordered_map<int,int> hm;
        for(int i = 0; i != nums.size();i++){
            int temp = target - nums[i];
            if(hm.find(temp) != hm.end())
            {
                res.push_back(hm[temp]);
                res.push_back(i);
                  return res;
            }
             hm[nums[i]] = i;
        }
    }
};

第二題 Remove Duplicates from Sorted Array(NO.26)

題目描述

Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

For example,
Given input array nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn’t matter what you leave beyond the new length.

vector慎用erase 和查詢 程式碼很方便 但開銷太大
比如下面這個,時間開銷為O(n^3),無法提交。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int len=nums.size();
        for(int i=0; i<nums.size(); i++){
            for(int j=i+1; j<nums.size(); j++){
                if(nums[i]==nums[j]){
                    nums.erase(nums.begin()+j);
                    j--;//刪除後所有陣列會往前移動 所j要減一個
                    len--;
                }
            }
        }
        return len; 
    }
};

卡點:erase刪除開銷太大,不能使用,那用什麼來替代重複值的位置內容?
問題:審題不清楚,題目說了已經排好序的。這樣難度降低了一層其實。

改進:i,j兩個“指標”往前走的思想;覆蓋前面陣列內容

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.size()==0) return 0;

        int i=0;
        for(int j=1; j<nums.size(); j++){
            if(nums[i]!=nums[j]){
                i++;
                nums[i]=nums[j];
            }
        }
        return i+1;

    }
};

時間複雜度O(n) Runningtime 26ms

第三題 Remove Element (NO.27)

題目描述

Given an array and a value, remove all instances of that value in place and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

The order of elements can be changed. It doesn’t matter what you leave beyond the new length.

Example:
Given input array nums = [3,2,2,3], val = 3

Your function should return length = 2, with the first two elements of nums being 2.

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {

        int i=0;
        for(i=0; i<nums.size(); i++){
            if(nums[i]==val){
                nums.erase(nums.begin()+i);
                i--;
            }
        }

        return nums.size();
    }
};

時間複雜度:近似是O(n),因為erase不一定是O(n)

runningtime:3ms

第二種解法,效率差不多,主要了解下remove用法(remove配合erase使用),記不住也沒事;估計用不到;

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        auto it = remove(nums.begin(), nums.end(), val);
        nums.erase(it, nums.end());
        return nums.size();
    }
};

時間複雜度 O(2n)=O(n)
Runningtime 6ms

romve沒有真的刪除值,只是把統一val放到了begin和end中的最後幾個位置,返回的是第一個val的開始位置
所以erase直接刪除從 it到end,就是真正刪除了所有val,詳細查閱下自己的c++筆記。

第四題 Search Insert Position (NO.35)

題目描述

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Here are few examples.

[1,3,5,6], 5 → 2

[1,3,5,6], 2 → 1

[1,3,5,6], 7 → 4

[1,3,5,6], 0 → 0

非常明顯的二分搜尋方法;

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int low=0;
        int high=nums.size()-1;
        int mid;

        while(low<=high){
            mid=(low+high)/2;
            if (nums[mid]==target) return mid;
            else if (nums[mid]>target) high=mid-1;
            else low=low+1;
        }
        return low;

    }
};

時間複雜度O(n) Runningtime:9ms

第五題 Maximum Subarray(No.53)

問題描述

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],

the contiguous subarray [4,-1,2,1] has the largest sum = 6.

卡點:除了暴力列出所有組合,求出最大的一個和,想不到別的方法。。。無從下手
方案:好好學習學習。。。第一次接觸;
兩個值,一個值(sum)累加,並在加到小於0時清0;
另一個值(flag)記錄並**更新**sum累加過程中的最大值。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int flag=nums[0];
        int i=0,sum=0;
        for(i=0; i<nums.size(); i++){
            sum+=nums[i];
            flag=max(flag,sum);
            sum=max(sum,0);
        }
        return flag;
    }
};

時間複雜度O(n) Runningtime:13ms

這其實就是一種分治解法(動態規劃),好好學習;

第六題 Plus One(No.66)

題目描述
Given a non-negative integer represented as a non-empty array of digits, plus one to the integer.

You may assume the integer do not contain any leading zero, except the number 0 itself.

The digits are stored such that the most significant digit is at the head of the list.

卡點:沒思路。以前沒有接觸過。
思路:應該嘗試以下解決方法,找到規律。
首先需要個迴圈遍歷陣列,
其次,整體上分為兩種
1、若最後一位不是9(<9),則最後一位直接+1 return;

2、若最後一位是9(其他 else),則考慮進位。

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        for(int i=digits.size()-1 ; i>=0; i--){
            if(digits[i]<9){
                digits[i]++;
                return digits;
            }    
            else{
                digits[i]=0;    
            }
        }
        digits[0]=1;
        digits.push_back(0);
        return digits;

    }
};

時間複雜度 O(n) RunningTime 3ms

第七題 Merge Sorted Array(No.88)

題目描述
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.

總結:坑爹的描述,題目意思是陣列為空,但m,n不一定為空!
所以長度要用m,n,不要用size。
錯誤解法

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i=m-1;
        int j=n-1;

        if(m==0){
            nums1.assign(nums2.begin(),nums2.end());
            return;
        }

        while(i>=0&&j>=0){
            if(nums1[i]<=nums2[j]){
                nums1.insert(nums1.begin()+i+1,nums2[j]);
                j--;
            }
            else
                i--;
        }

        while(j>=0){
            nums1.insert(nums1.begin(),nums2[j]);
            j--;
        }
        return;

    }
};

錯誤原因,0的影響,m,n的影響,不能直接用size要用m,n,陣列為空,但m,n不一定為空!比較蛋疼。

正確解法:
要從m+n-1 的位置開始,從後往前放置數字。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i=m-1;
        int j=n-1;
        int k = m+n-1;
        while(i >=0 && j>=0)
        {
            if(nums1[i] > nums2[j])
                nums1[k--] = nums1[i--];
            else
                nums1[k--] = nums2[j--];
        }
        while(j>=0)
            nums1[k--] = nums2[j--];
    }

};
時間複雜度O(n),Runningtime 3ms

第八題 Pascal’s Triangle(No.118)

題目描述
Given numRows, generate the first numRows of Pascal’s triangle.

For example, given numRows = 5,
Return

[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]

想法:每個元素等於上一行相鄰兩個元素的和
(每一層的第i個位置,等於上一層第i-1與第i個位置之和。)
實施
1、前兩行特殊處理;
2、第三行開始施行 [i-1]、[i]相加;

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> result;
        if( numRows==0) return result;

        result.push_back(vector<int>(1,1));

        for(int i=2; i<=numRows; i++){
            vector<int> current(i,1);  //  i個1
            vector<int> &prev=result[i-2];  //上一行,因為陣列從零開始,
            //陣列第0行  對應三角形第一行 i=1;
            //陣列第1行  對應三角形第二行 i=2;
            //陣列第2行  對應三角形第三行 i=3 上   上一行為陣列第一行  prev[(i=3)3-2=1];

            for(int j=1; j<i-1; j++){
                current[j]=prev[j]+prev[j-1];
            }

            result.push_back(current);
        }
        return result;

    }
};

時間複雜度 O(n^2) Runningtime 3ms

第九題 Pascal’s Triangle II(No.119)

題目描述
Given an index k, return the kth row of the Pascal’s triangle.

For example, given k = 3,
Return [1,3,3,1].

Note:
Could you optimize your algorithm to use only O(k) extra space?

可能會考,因為有一個考點就是能否省去額外空間,在面試中出現的可能性大一些,不過總體比較簡單,電面中比較合適。

這道題跟Pascal’s Triangle很類似,只是這裡只需要求出某一行的結果。Pascal’s Triangle中因為是求出全部結果,所以我們需要上一行的資料就很自然的可以去取。而這裡我們只需要一行資料,就得考慮一下是不是能只用一行的空間來儲存結果而不需要額外的來儲存上一行呢?這裡確實是可以實現的。

對於每一行我們知道如果從前往後掃,第i個元素的值等於上一行的res[i]+res[i+1],可以看到資料是往前看的,如果我們只用一行空間,那麼需要的資料就會被覆蓋掉。所以這裡採取的方法是從後往前掃,這樣每次需要的資料就是res[i]+res[i-1],我們需要的資料不會被覆蓋,因為需要的res[i]只在當前步用,下一步就不需要了。這個技巧在動態規劃省空間時也經常使用,主要就是看我們需要的資料是原來的資料還是新的資料來決定我們遍歷的方向。時間複雜度還是O(n^2),而空間這裡是O(k)來儲存結果,仍然不需要額外空間。

class Solution {
public:
    vector<int> getRow(int rowIndex) {
        vector<int> A(rowIndex+1,0);    // 題目中的k是從0開始的  所以要+1; 初始全部賦值為0,因為下面有0+1=1的更新  //  rowIndex=4   [1,3,3,1,0] i=3

        A[0]=1;
        for(int i=1;i<rowIndex+1;i++){  // i是個數,所以從1開始
            for(int j=i; j>=1; j--){   //大於等於1 ,因為第一個就是1.不用更新
                A[j]=A[j]+A[j-1];
            }
        }
        return A;


    }
};

陣列首先申請全部空間row+1;
每次實際利用空間 i;
每次增大一個空間到 i+1;
所以,從後向前,先確認 最後一個位置(i+1)值,再依次向前確認,
這題想法很好,回頭再看看。
時間複雜度O(n^2) 空間複雜度O(k),Runningtime 0ms

第十題 Best Time to Buy and Sell Stock(NO.121)

題目描述
Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Example 1:
Input: [7, 1, 5, 3, 6, 4]
Output: 5
max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)

Example 2:
Input: [7, 6, 4, 3, 1]
Output: 0
In this case, no transaction is done, i.e. max profit = 0.

重點複習,這種標記min和max的貪心演算法,本題我的首要想法還是暴力法。。。弄個兩層迴圈。。。感覺自己還是太菜,沒有想法。
貪心法,分別找到價格最低和最高的一天,低進高出,注意最低的一天要在最高的一天之前。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()<2) return 0;

        int max=0;
        int min=prices[0];//先假設第一個最小

        for(int i=0; i<prices.size(); i++)
        {
            if(prices[i]<min)    
                min=prices[i];
            if(prices[i]-min>max)
                max=prices[i]-min;
        }
        return max;


    }
};

時間複雜度O(n) 空間複雜度O(1)(只有兩個變數的空間)
Runningtime 6ms;

第十一題 Best Time to Buy and Sell Stock II(No.122)

題目描述
Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

完全沒有想法,感覺無從下手。
總不能把所有的組合情況都列出來吧?

5min後有點想法,只要後一個比前一個大,就賣出,如果下一個比當前賣出的大,則再買入當前,然後繼續賣出後一個,如此反覆。因為只要後面繼續比前面的大,那麼收益就是正的會累加,賣了再買就行。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()<2) return 0;

        int sum=0;
        int flag=0;

        for(int i=1;i<prices.size();i++)
        {
            if((flag=prices[i]-prices[i-1]) > 0)   
                sum=sum+flag;
        }
        return sum;   
    }
};

時間複雜度 O(n)
Runningtime:6ms

此想法是正確的。。。。好激動。。。。。第一次自己想出來和標答一樣。。。。。幹TMD。。。
感覺自己智商還是線上的。
總結:貪心法,低進高出,把所有正的價格差價相加起來。

我發現困得時候不要看機器學習視訊,必睡著,做做演算法反而提神。
注:以後所有for和if的括號都要換行!!!這樣以博主智商看著清晰,方便理解。。。。從此加入換行黨。。

第十二題 Two Sum II - Input array is sorted(No.167)

題目描述
Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution and you may not use the same element twice.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
本身這題不用刷了。。好奇點開發現簡單順手就寫了。。
此題和第一題出差不多,改了一個判定條件,其他沒變。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
         int i;
        vector<int> re;
        unordered_map<int,int> mapping;
        int gap=0;

        for(i=0; i<nums.size(); i++)
            mapping[nums[i]]=i;

        for(i=0; i<nums.size(); i++){
            gap = target - nums[i];//注意這裡,可以省去比較;
            if( mapping.find(gap) != mapping.end() && mapping[gap]>i){ // 多了一個判定條件,即找到的值不能為nums[i]本身  即3+3=6的情況
                re.push_back(i+1);
                re.push_back(mapping[gap]+1);
                return re;
            }
        }
    }
};

時間複雜度O(n)
Runningtime 9ms

陣列的Easy專題到此結束了啦!

跟博主一起進入下一個任務吧!(陣列 medium專題)