算法分析與設計課程作業第十二週#1#2#3#4

算法分析與設計課程作業第十二週#1#2#3#4

這周從dynamic programming標籤的題目中挑了4道medium題目來做。

338.Counting Bits

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1’s in their binary representation and return them as an array.
Example:
For num = 5 you should return [0,1,1,2,1,2].
Follow up:
It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
Space complexity should be O(n).
Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.

思路

這道題要求了線性時間複雜度與線性空間複雜度。可用動態規劃的思想,對某個數二進制形式1的個數,可由前面已經計算了的某個數的1的個數計算得出(這個計算要求O(1)的時間複雜度)。這樣整體的時間複雜度爲O(n)。
狀態轉移式:bits[i]:數i二進制形式1的個數
bits[0]=0;
bits[1]=1;
bits[i]=bits[i/2] + i%2;

代碼

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> bits;
        bits.push_back(0);
        if(num == 0) return bits;
        bits.push_back(1);
        if(num == 1) return bits;
        for(int i = 2; i <= num; i++){
            bits.push_back(bits[i/2] + i%2);
        }
        return bits;
    }
};

647. Palindromic Substrings

Given a string, your task is to count how many palindromic substrings in this string.
The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.
Example 1:
Input: “abc”
Output: 3
Explanation: Three palindromic strings: “a”, “b”, “c”.

Example 2:
Input: “aaa”
Output: 6
Explanation: Six palindromic strings: “a”, “a”, “a”, “aa”, “aa”, “aaa”.

Note:
The input string length won’t exceed 1000.

思路

題目要求的是一個字符串中迴文子串的數目。我想到的是窮舉字符串中所有子串,每個判斷是否爲迴文子串。要想在O(1)時間內判斷出一個子串是否爲迴文子串(即判斷時間不由子串長度決定),就要用到線性規劃的思想,也要注意選擇子串進行判斷的順序(以下說明怎麼確定順序)。
首先給出狀態轉移式:bool dp[i][j]:從第i到第j個字符組成的子串是否爲迴文子串。初始爲false。
dp[i][j] = (s[i] == s[j]) && ((j - i <= 1)||dp[i+1][j-1]);
從dp[i][j]需由dp[i+1][j-1]算出,可知計算的外循環要麼就是i從大到小,要麼就是j從小到大,內循環的計算順序倒是不要緊。同時要注意i小於等於j。

外循環i從大到小代碼

class Solution {
public:
    int countSubstrings(string s) {
        int size = s.size();
        int num = 0;
        bool dp[size][size];
        for(int i = 0; i < size; i++){
            for(int j = 0; j < size; j++){
                dp[i][j] = false;
            }
        }
        for(int i = size-1; i >= 0; i--){
            for(int j = i; j < size; j++){
                dp[i][j] = (s[i] == s[j]) && ((j - i  <= 1)||dp[i+1][j-1]);
                if(dp[i][j]) num++;
            }
        }
        return num;
    }
};

外循環j從小到大代碼

class Solution {
public:
    int countSubstrings(string s) {
        int size = s.size();
        int num = 0;
        bool dp[size][size];
        for(int i = 0; i < size; i++){
            for(int j = 0; j < size; j++){
                dp[i][j] = false;
            }
        }
        for(int j = 0; j < size; j++){
            for(int i = 0; i <= j; i++){
                dp[i][j] = (s[i] == s[j]) && ((j - i  <= 1)||dp[i+1][j-1]);
                if(dp[i][j]) num++;
            }
        }
        return num;
    }
};

413. Arithmetic Slices

A sequence of number is called arithmetic if it consists of at least three elements and if the difference between any two consecutive elements is the same.
For example, these are arithmetic sequence:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
The following sequence is not arithmetic.
1, 1, 2, 5, 7

A zero-indexed array A consisting of N numbers is given. A slice of that array is any pair of integers (P, Q) such that 0 <= P < Q < N.
A slice (P, Q) of array A is called arithmetic if the sequence:
A[P], A[p + 1], …, A[Q - 1], A[Q] is arithmetic. In particular, this means that P + 1 < Q.
The function should return the number of arithmetic slices in the array A.

Example:
A = [1, 2, 3, 4]

return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself.

思路

這道題求的是一個數組中等差子數組的個數,咋眼一看,跟求迴文串那題一樣,可以寫出極爲類似的代碼解決問題。這樣的代碼時間複雜度與空間複雜度爲O(n^2),對大數組容易超時。
以下爲超時代碼。

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int size = A.size();
        if(size < 3) return 0;
        int num = 0;
        bool dp[size][size];
        for(int i = 0; i < size; i++){
            for(int j = 0; j < size; j++){
                dp[i][j] = false;
            }
        }
        for(int j = 2; j < size; j++){
            for(int i = 0; i <= j-1; i++){
                dp[i][j] = (A[i+1] - A[i] == A[j] - A[j-1]) && ((j-i <= 2)||dp[i+1][j-1]);
                if(dp[i][j] &&j-i >= 2) num++;
            }
        }
        return num;
    }
};

應有更快捷的方法,可以另闢蹊徑。
一個數列到某個數,該數是否爲某個等差子數列結尾(或者說爲多少個等差子數列的結尾),可以向前看兩個數,如果構成等差數列,那這個等差數列的差就確定了,從而可以與前一個數是否爲多少個等差子數列結尾構成關係(迴文串無法確立這一個關係,關鍵在於等差數列的等差性質)。
狀態轉移式:dp[i]:以i結尾有多少個等差子數列//事實上這個儲存的信息也比一個布爾值數組多
所求:所有dp[i]的和
dp[0]=0;
dp[1]=0;
if(A[i]-A[i-1] == A[i-1]-A[i-2]) dp[i] = dp[i-1]+1;
else dp[i] = 0;

代碼

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int size = A.size();
        if(size < 3) return 0;
        int num = 0;
        int dp[size];
        dp[0] = 0;
        dp[1] = 0;
        for(int i = 2; i < size; i++){
            if(A[i]-A[i-1] == A[i-1]-A[i-2]){
                dp[i] = dp[i-1]+1;
            }
            else
                dp[i] = 0;
            num += dp[i];
        }
        return num;
    }
};

646. Maximum Length of Pair Chain

You are given n pairs of numbers. In every pair, the first number is always smaller than the second number.
Now, we define a pair (c, d) can follow another pair (a, b) if and only if b < c. Chain of pairs can be formed in this fashion.
Given a set of pairs, find the length longest chain which can be formed. You needn’t use up all the given pairs. You can select pairs in any order.
Example 1:
Input: [[1,2], [2,3], [3,4]]
Output: 2
Explanation: The longest chain is [1,2] -> [3,4]

Note:
The number of given pairs will be in the range [1, 1000].

思路

這道題我沒有用動態規劃的思路,而是用了貪心算法。就是按pair第二個值大小先排好序,然後每次選滿足條件的pair第二個值最小的pair構成鏈條,以讓下次選擇的空間儘量大,從而可求出鏈條的最大長度。

代碼

class Solution {
public:
    int findLongestChain(vector<vector<int>>& pairs) {
        sort(pairs.begin(), pairs.end(), cmp);
        int size = pairs.size();
        int num = 1;
        int j = 0;
        for(int i = 1; i < size; i++){
            if(pairs[i][0] > pairs[j][1]){
                num++;
                j = i;
            }
        }
        return num;
    }
    static bool cmp(vector<int>& a, vector<int>&b) {
        return a[1] < b[1];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章