717. 1比特與2比特字符;89. 格雷編碼-鏡像反射法-2進制碼轉格雷碼;92反轉鏈表 II

有兩種特殊字符。第一種字符可以用一比特0來表示。第二種字符可以用兩比特(10 或 11)來表示。

現給一個由若干比特組成的字符串。問最後一個字符是否必定爲一個一比特字符。給定的字符串總是由0結束。

示例 1:

輸入: 
bits = [1, 0, 0]
輸出: True
解釋: 
唯一的編碼方式是一個兩比特字符和一個一比特字符。所以最後一個字符是一比特字符。


示例 2:

輸入: 
bits = [1, 1, 1, 0]
輸出: False
解釋: 
唯一的編碼方式是兩比特字符和兩比特字符。所以最後一個字符不是一比特字符。


注意:


    1 <= len(bits) <= 1000.
    bits[i] 總是0 或 1.

class Solution {//方法一:線性掃描
public:
    bool isOneBitCharacter(vector<int>& bits) {
        int bSize=bits.size();
        if(bSize==1||bits[bSize-2]==0)return true;
        int i=0;
        while(i<=bSize-2)
            if(bits[i]==0)++i;//0則+1
            else i+=2;//1則+2
        return i==bSize-1;
    }
};

方法二:貪心
三種字符分別爲 0,10 和 11,那麼 bits\mathrm{bits}bits 數組中出現的所有 0 都表示一個字符的結束位置(無論其爲一比特還是兩比特)。因此最後一位是否爲一比特字符,只和他左側出現的連續的 1 的個數(即它與倒數第二個 0 出現的位置之間的 1 的個數,如果 bits\mathrm{bits}bits 數組中只有 1 個 0,那麼就是整個數組的長度減一)有關。如果 1 的個數爲偶數個,那麼最後一位是一比特字符,如果 1 的個數爲奇數個,那麼最後一位不是一比特字符。

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        int bSize=bits.size();
        if(bSize==1||bits[bSize-2]==0)return true;
        int cnt=0;
        for(int i=bSize-2;i>=0;--i){
            if(bits[i]==0)break;
            ++cnt;
        }
        return (cnt&1)==0;
    }
};

格雷編碼是一個二進制數字系統,在該系統中,兩個連續的數值僅有一個位數的差異。

給定一個代表編碼總位數的非負整數 n,打印其格雷編碼序列。即使有多個不同答案,你也只需要返回其中一種。

格雷編碼序列必須以 0 開頭。

 

示例 1:

輸入: 2
輸出: [0,1,3,2]
解釋:
00 - 0
01 - 1
11 - 3
10 - 2

對於給定的 n,其格雷編碼序列並不唯一。
例如,[0,2,3,1] 也是一個有效的格雷編碼序列。

00 - 0
10 - 2
11 - 3
01 - 1

示例 2:

輸入: 0
輸出: [0]
解釋: 我們定義格雷編碼序列必須以 0 開頭。
     給定編碼總位數爲 n 的格雷編碼序列,其長度爲 2n。當 n = 0 時,長度爲 20 = 1。
     因此,當 n = 0 時,其格雷編碼序列爲 [0]。

class Solution {
    unordered_set<int>visited;
    vector<int>res;
public:
    vector<int> grayCode(int n) {
        if(n==0)return {0};
        visited.insert(0);
        res.push_back(0);
        backTrack(0,n);
        return res;
    }
    void backTrack(int val,int n){
        for(int i=0;i<n;++i){
            int temp=val^(1<<i);
            if(visited.count(temp)==0){
                visited.insert(temp);
                res.push_back(temp);
                backTrack(temp,n);
                return;
            }
        }
    }
};

Gray Code (鏡像反射法

思路:

設 nnn 階格雷碼集合爲 G(n)G(n)G(n),則 G(n+1)G(n+1)G(n+1) 階格雷碼爲:

給 G(n)G(n)G(n) 階格雷碼每個元素二進制形式前面添加 000,得到 G′(n)G'(n)G′(n);
設 G(n)G(n)G(n) 集合倒序(鏡像)爲 R(n)R(n)R(n),給 R(n)R(n)R(n) 每個元素二進制形式前面添加 111,得到 R′(n)R'(n)R′(n);
G(n+1)=G′(n)∪R′(n)G(n+1) = G'(n) ∪ R'(n)G(n+1)=G′(n)∪R′(n) 拼接兩個集合即可得到下一階格雷碼。


根據以上規律,可從 000 階格雷碼推導致任何階格雷碼。
代碼解析:

由於最高位前默認爲 000,因此 G′(n)=G(n)G'(n) = G(n)G′(n)=G(n),只需在 res(即 G(n)G(n)G(n) )後添加 R′(n)R'(n)R′(n) 即可;
計算 R′(n)R'(n)R′(n):執行 head = 1 << i 計算出對應位數,以給 R(n)R(n)R(n) 前添加 111 得到對應 R′(n)R'(n)R′(n);
倒序遍歷 res(即 G(n)G(n)G(n) ):依次求得 R′(n)R'(n)R′(n) 各元素添加至 res 尾端,遍歷完成後 res(即 G(n+1)G(n+1)G(n+1))。

class Solution {
public:
    vector<int> grayCode(int n) {
        if(n==0)return {0};
        vector<int>res(1,0);
        for(int i=0;i<n;++i)
            for(int j=res.size()-1;j>=0;--j)
                res.push_back(res[j]|(1<<i));//
        return res;
    }
};

class Solution {
public:
    vector<int> grayCode(int n) {
        if(n==0)return {0};
        vector<int>res(1,0);
        for(int i=0,temp=1;i<n;++i,temp<<=1)
            for(int j=res.size()-1;j>=0;--j)
                res.push_back(res[j]|temp);
        return res;
    }
};

 2進制碼轉格雷碼

解題思路
二進制碼轉換成二進制格雷碼,其法則是保留二進制碼的最高位作爲格雷碼的最高位,而次高位格雷碼爲二進制碼的高位與次高位相異或,而格雷碼其餘各位與次高位的求法相類似。

class Solution {
public:
    vector<int> grayCode(int n) {
        if(n==0)return {0};
        vector<int>res;
        for(int i=0,end=1<<n;i<end;++i)
            res.push_back(i^(i>>1));//
        return res;
    }
};

反轉從位置 m 到 n 的鏈表。請使用一趟掃描完成反轉。

說明:
1 ≤ m ≤ n ≤ 鏈表長度。

示例:

輸入: 1->2->3->4->5->NULL, m = 2, n = 4
輸出: 1->4->3->2->5->NULL

//爲了便於理解,所以指針定義有所冗餘,可以進一步優化
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode *LN=new ListNode(0);
        LN->next=head;
        ListNode *pre=LN,*cur=head,*next=nullptr;//遍歷鏈表必備三指針
        //鏈表分爲三塊:第一塊,中間塊,第二塊
        //初始:LN->firstEnd->midEnd(m反轉開始)->midStart(m反轉結束)->secondStart->
        //結果:LN->firstEnd->midStart(m反轉結束)->midEnd(m反轉開始)->secondStart->
        ListNode *firstEnd=nullptr,*midStart=nullptr,*midEnd=nullptr,*secondStart=nullptr;
        for(int i=1;cur;++i){
            next=cur->next;//1
            if(m<=i&&i<=n){                
                cur->next=pre;//2反轉
                if(i==m){
                    firstEnd=pre;
                    midEnd=cur;
                }
                if(i==n){
                    secondStart=next;
                    midStart=cur;
                    break;
                }               
            }
            pre=cur;//3
            cur=next;//4
        }
        //初始->結果
        firstEnd->next=midStart;
        midEnd->next=secondStart;
        return LN->next;
    }
};

 

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