60第k個排列(康託);73矩陣置零;74搜索二維矩陣;33搜索旋轉排序數組;81搜索旋轉排序數組 II

給出集合 [1,2,3,…,n],其所有元素共有 n! 種排列。

按大小順序列出所有排列情況,並一一標記,當 n = 3 時, 所有排列如下:


    "123"
    "132"
    "213"
    "231"
    "312"
    "321"


給定 n 和 k,返回第 k 個排列。

說明:


    給定 n 的範圍是 [1, 9]。
    給定 k 的範圍是[1,  n!]。


示例 1:

輸入: n = 3, k = 3
輸出: "213"


示例 2:

輸入: n = 4, k = 9
輸出: "2314"

康託編碼

解題思路
    採用康託編碼的思路。其實就是康託展開的逆過程。康託展開用來求某個全排列數是第幾小的數,也就是當這些數按順序排時第幾個數。
    過程如下:比如求321 是 第幾小的,可以這樣來想:小於3的數有1和2 兩個,首位確定之後後面兩位有2!中情況,所以共有2*2!=4種。
    小於2的數只有一個1,所以有11!=1種情況,最後一位是1,沒有比一小的數,所以是00!=0
    綜上:小於321的數有4+1=5個,所以321是第六小的數。
    逆過程就是已知這個數是第k個數,求這個數是多少,當然是知道n的值的。
    第k個數就是有k-1個數比這個數小。
    所以就是 k-1=an*(n-1)!+an-1*(n-2)!+....+a1*0!;
    再舉一個例子:如何找出第16個(按字典序的){1,2,3,4,5}的全排列?
    首先用16-1得到15
    用15去除4! 得到0餘15
    用15去除3! 得到2餘3
    用3去除2! 得到1餘1
    用1去除1! 得到1餘0
    有0個數比它小的數是1,所以第一位是1
    有2個數比它小的數是3,但1已經在之前出現過了所以是4
    有1個數比它小的數是2,但1已經在之前出現過了所以是3
    有1個數比它小的數是2,但1,3,4都出現過了所以是5
    最後一個數只能是2
    所以排列爲1 4 3 5 2

 

class Solution {
public:
    string getPermutation(int n, int k) {
        string s="123456789",res="";
        if(k==1||n==1)return s.substr(0,n);
        vector<int>nn(n);//n!
        nn[0]=0;//0!
        nn[1]=1;//1!
        --k;
        for(int i=2;i<n;++i)
            nn[i]=i*nn[i-1];
        for(int i=n-1;i>0;--i){
            auto it=s.begin()+k/nn[i];//auto it=s.begin();advance(it,k/nn[i]);
            k=k%nn[i];
            res+=(*it);//res.push_back(*it);
            s.erase(it);//!!!
        }
        res+=s[0];
        return res;
    }
};

給定一個 m x n 的矩陣,如果一個元素爲 0,則將其所在行和列的所有元素都設爲 0。請使用原地算法。

示例 1:

輸入: 
[
  [1,1,1],
  [1,0,1],
  [1,1,1]
]
輸出: 
[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]


示例 2:

輸入: 
[
  [0,1,2,0],
  [3,4,5,2],
  [1,3,1,5]
]
輸出: 
[
  [0,0,0,0],
  [0,4,5,0],
  [0,3,1,0]
]

進階:


    一個直接的解決方案是使用  O(mn) 的額外空間,但這並不是一個好的解決方案。
    一個簡單的改進方案是使用 O(m + n) 的額外空間,但這仍然不是最好的解決方案。
    你能想出一個常數空間的解決方案嗎?

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        unordered_set<int>rowCol;//O(m+n)額外空間
        int m=matrix.size();
        if(m==0)return;
        int n=matrix[0].size();
        if(n==0)return;
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j)
                if(matrix[i][j]==0)
                    rowCol.insert(i),rowCol.insert(m+j);
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j)
                if(rowCol.count(i)||rowCol.count(m+j))
                    matrix[i][j]=0;
    }
};
//matrix[0<=i<m][0]==0表示第i+1行應該置0
//matrix[0][1<=j<n]==0表示第j+1列應該置0;matrix00IsCol==true表示第1列應該置0
class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m=matrix.size();
        if(m==0)return;
        int n=matrix[0].size();
        if(n==0)return;
        bool matrix00IsCol=false;//常數額外空間
        for(int i=0;i<m;++i){
            if(matrix[i][0]==0)matrix00IsCol=true;
            for(int j=1;j<n;++j)//j=0出錯:[[1,1,1],[0,1,2]]
                if(matrix[i][j]==0)
                    matrix[0][j]=0,matrix[i][0]=0;
        } 
        for(int i=1;i<m;++i)//處理第2列~第n列 第2行~第m行應該置0的情況
            for(int j=1;j<n;++j)  
                if(matrix[i][0]==0||matrix[0][j]==0)              
                    matrix[i][j]=0;
        if(matrix[0][0]==0)//處理第1行應該置0的情況
            for(int j=1;j<n;++j)
                matrix[0][j]=0;
        if(matrix00IsCol)//處理第1列應該置0的情況
            for(int i=0;i<m;++i)
                matrix[i][0]=0;
    }
};

編寫一個高效的算法來判斷 m x n 矩陣中,是否存在一個目標值。該矩陣具有如下特性:


    每行中的整數從左到右按升序排列。
    每行的第一個整數大於前一行的最後一個整數。


示例 1:

輸入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
輸出: true


示例 2:

輸入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
輸出: false

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m=matrix.size();
        if(m==0)return false;
        int n=matrix[0].size();
        if(n==0)return false;
        int le=0,ri=m*n-1;
        while(le<=ri){
            int mid=le+((ri-le)>>1);
            int i=mid/n,j=mid%n;
            if(target==matrix[i][j])return true;
            else if(target<matrix[i][j])ri=mid-1;
            else le=mid+1;
        }
        return false;
    }
}

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。

( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。

搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。

你可以假設數組中不存在重複的元素。

你的算法時間複雜度必須是 O(log n) 級別。

示例 1:

輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4


示例 2:

輸入: nums = [4,5,6,7,0,1,2], target = 3
輸出: -1

class Solution {
public:
    int search(vector<int>& nums, int target) {
         int le=0,ri=nums.size()-1;
        while(le<=ri){
            int mid=le+((ri-le)>>1);
            if(nums[mid]==target)return mid;
            if(nums[mid]>=nums[le])//[le~mid]有序
                if(nums[le]<=target&&target<nums[mid])ri=mid-1;//判斷是否屬於有序部分,即大於等最小值&&小於等於最大值
                else le=mid+1;
            else//[mid~ri]有序
                if(nums[mid]<target&&target<=nums[ri])le=mid+1;//判斷是否屬於有序部分,即大於等最小值&&小於等於最大值
                else ri=mid-1;
        }
        return -1;
    }

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。

( 例如,數組 [0,0,1,2,2,5,6] 可能變爲 [2,5,6,0,0,1,2] )。

編寫一個函數來判斷給定的目標值是否存在於數組中。若存在返回 true,否則返回 false。

示例 1:

輸入: nums = [2,5,6,0,0,1,2], target = 0
輸出: true


示例 2:

輸入: nums = [2,5,6,0,0,1,2], target = 3
輸出: false

進階:


    這是 搜索旋轉排序數組 的延伸題目,本題中的 nums  可能包含重複元素。
    這會影響到程序的時間複雜度嗎?會有怎樣的影響,爲什麼?

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        int le=0,ri=nums.size()-1;
        while(le<=ri){
            int mid=le+((ri-le)>>1);
            if(nums[mid]==target)return true;

            //nums[mid]==nums[le]的情況判斷不出是[le-mid]還是[mid-ri]有序,所以要特殊處理,即+1直到不相等的情況出現爲止
            while(le<=ri&&nums[mid]==nums[le])++le;
            if(le>mid)continue;

            if(nums[mid]>nums[le])//[le-mid]有序
                if(nums[le]<=target&&target<nums[mid])ri=mid-1;
                else le=mid+1;
            else//[mid-ri]有序
                if(nums[mid]<target&&target<=nums[ri])le=mid+1;
                else ri=mid-1;
        }
        return false;
    }
};

 

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