1. 程式人生 > >求最長等差數列長度

求最長等差數列長度

Longest Consecutive Sequence

LeetCode上面這道題是求最長連續子序列。換種說法就是求公差為1的最長等差數列。

題目描述

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.

Your algorithm should run in O(n) complexity.

分析:

需要注意的是時間複雜度要求是O(n),所以排序後再處理那種方法是不可行的。我們可以就用陣列中的元素作為key建立hash表,然後直接迴圈遍歷找當前元素val的,val-1,val+1。

程式碼:

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int n=nums.size();
        if(n==0 || n==1){
            return
n; } int longest=1,val,cur; unordered_map<int,int> m; for(int i=0;i<n;i++){ m[nums[i]]=0;//沒有被訪問過的標記為0 } for(int i=0;i<n;i++){ if(m[nums[i]]){ continue; } cur=1; val=nums[i]-1
; while(m.find(val)!=m.end() && !m[val]){ m[val]=1; val--; cur++; } val=nums[i]+1; while(m.find(val)!=m.end() && !m[val]){ m[val]=1; val++; cur++; } longest=max(longest,cur); } return longest; } };

題目:

給一個無序陣列,求這個陣列中元素所能形成的最長等差數列的長度。

分析:

這裡的公差d就未知了。兩種dp方法。

第一種:
dp[i][d]表示陣列0~i範圍內,公差為d的等差數列長度。
dp[i][d]=dp[j][d]+1。
其實跟插入排序法有點像,範圍由小往大擴充套件,當範圍i定了之後,再倒著從j=i-1到j=0,我們對(i,j)形成的每個公差d=nums[i]-nums[j]所構成的dp[i][d]進行處理。

第二種:
dp[i][j]表示以nums[i]作為首項,nums[j]作為第二項的等差數列長度。
所以,我們需要從後往前進行處理。
由等差數列的性質我們可知,如果nums[i],nums[j],nums[k]構成等差數列,則滿足nums[i]+nums[k]=2nums[j]。
初始化工作對於dp[0..n-2][n-1]=2。
j從n-2開始,從後往前找滿足條件nums[i]+nums[k]=2nums[j]的元素,如果滿足則dp[i][j]=dp[j][k]+1。

程式碼:

第一種:

int LongestArithmeticSequence(vector<int> nums){
    int n = nums.size();
    sort(nums.begin(),nums.end());
    int len = nums[n - 1] - nums[0];
    vector<vector<int>> dp(n,vector<int>(len+1,1));//dp[i][d]表示0~i範圍內,公差為d的等差數列長度
    int d,longest=1;//公差
    for (int i = 1; i < n; i++){
        for (int j = i - 1; j >= 0; j--){
            d = nums[i] - nums[j];
            dp[i][d] = dp[j][d]+1;
            longest = max(longest,dp[i][d]);
        }
    }
    return longest;
}

第二種:

int LongestArithmeticSequence(vector<int> nums){
    int n = nums.size();
    sort(nums.begin(),nums.end());
    vector<vector<int>> dp(n, vector<int>(n));
    {
        for (int i = 0; i < n - 1; i++){
            dp[i][n - 1] = 2;
        }
    }
    int i, k,longest=1;
    for (int j = n - 2; j >= 0; j--){
        i = j - 1;
        k = j + 1;
        while (i >= 0 && k < n){
            if (nums[i] + nums[k] == 2 * nums[j]){
                dp[i][j] = dp[j][k] + 1;
                longest = max(longest,dp[i][j]);
                i--;
                k++;
            }
            else if (nums[i] + nums[k]>2 * nums[j]){
                i--;
            }
            else{
                k++;
            }
        }
    }
    return longest;
}