【面試題】和爲S的兩個數、和爲S的連續正數序列

題1:輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。 

解法1:雙層循環,從前向後掃描,簡單好想,時間複雜度爲O(n^2)

//時間複雜度爲O(n^2)
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        vector<int> vec;
        if( array.empty() || array.size() <2)
         	return vec;
        int length = array.size();
        for(int i = 0 ;i<length;++i)
        {
            for(int j = i+1;j<length;++j)
            {
                if(array[i]+array[j] == sum)
                {
                    vec.push_back(array[i]);
                    vec.push_back(array[j]);
                    return vec;
                }
            }
            
        }
       return vec; 
    }


解法2:時間複雜度爲O(n)的算法

思路:在數組中選擇兩個數,如果兩個數之和等於S,就是要找的。如果小於S,希望兩數之和再大一點,由於數組是遞增排序的,可以選擇兩個數中較小的數後面的數,因爲後面的數更大一些。如果大於S,我們想要數字之和小一點,可以選擇較大數之前的數,因爲前面的數小一點。根據此思路,可以定義兩個指針,一個指向最前,向後找;另一個指向最後,向前找。

 vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        vector<int> vec;
        if( array.empty() || array.size() <2)
         	return vec;
        vector<int>::iterator begin = array.begin();
        vector<int>::iterator end = array.end();
        --end;
        while(begin < end)
        {
            if(*begin + *end == sum)
            {
                vec.push_back(*begin);
                vec.push_back(*end);
                break;
            }
            else if(*begin + *end > sum)
                --end;
            else
                ++begin;
        } 
       return vec; 
    }

由於數組是排序的,所以較小數字一定位於較大數字之前,這就是while循環繼續的條件。函數代碼中只有一個while循環,從兩端向中間進行掃描,所以時間複雜度爲O(n)。

要求兩數乘積最小,兩種解法第一次找的的兩個數字必然是乘積最小的,可以進行簡單驗證。

題2:輸入一個正數S,打印所有和爲S的連續正數序列,至少含有兩個數,例如,輸入15,由於1+2+3+4+5 = 4+5+6 = 7+8 =15,所以打印三個序列,1~5,4~6,7~8.

思路:根據上面題目的想法,可以定義兩個變量small,big,small初始化爲1,big初始化爲2.small增加到(1+S)/2,結束。

假設我們以求和爲9爲例,初始化兩個變量後,此時介於small和big之間的序列爲{1,2},和爲3。小於9,則接下來增加big的值big=3,序列爲{1,2,3},和爲6,仍小於9,則繼續增加big的值big=4,此時序列爲{1,2,3,4},和爲10,此時大於9,我們就要刪掉一些數字,於是我們增加small的值small=2,序列變爲{2,3,4},和爲9,此時我們找到了第一組序列。

接下來我們再增加big的值big=5,序列變爲{2,3,4,5},和爲14,大於9,則增加small的值small=3,序列變爲{3,4,5},和爲12,大於9,則增加small的值small=4,序列變爲{4,5},和爲9,這是第二組序列。

接下來我們增加big的值big=6,序列變爲{4,5,6},和爲15,大於9,則增加small的值small=5,此時small=5 >= (1+S)/2=5,結束。

  vector<int> InsertData(int start,int end)
    {
        vector<int> vec;
        for(int i = start;i<=end;++i)
        {
            vec.push_back(i);
        }
        return vec;
    }
    vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int>> res;
        if(sum <3)
            return res;
       
        vector<int> vec;
        int middle = (sum+1)/2;
        int small = 1;
        int big =2;
        int cursum = small + big;
        while(small < middle)
        {
            if(cursum == sum)
            {
                vec = InsertData(small,big);
                res.push_back(vec);
            }
            while(cursum > sum && small < middle)
            {
                cursum -= small;
                ++small;
                if(cursum == sum)
                {
                    vec = InsertData(small,big);
                	res.push_back(vec);
                }
            }
            ++big;
            cursum += big;
        }
        return res;
    }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章